Merge branch 'master' into DecimalReagents
This commit is contained in:
@@ -288,7 +288,7 @@ namespace Content.Client.Chat
|
|||||||
WriteChatMessage(storedMessage);
|
WriteChatMessage(storedMessage);
|
||||||
|
|
||||||
// Local messages that have an entity attached get a speech bubble.
|
// Local messages that have an entity attached get a speech bubble.
|
||||||
if (msg.Channel == ChatChannel.Local && msg.SenderEntity != default)
|
if ((msg.Channel == ChatChannel.Local || msg.Channel == ChatChannel.Dead) && msg.SenderEntity != default)
|
||||||
{
|
{
|
||||||
AddSpeechBubble(msg);
|
AddSpeechBubble(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using Content.Client.UserInterface;
|
||||||
|
using Content.Shared.GameObjects.Components.Observer;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Client.GameObjects.Components.Observer
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class GhostComponent : SharedGhostComponent
|
||||||
|
{
|
||||||
|
private GhostGui _gui;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
public bool CanReturnToBody { get; private set; } = true;
|
||||||
|
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly IGameHud _gameHud;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager;
|
||||||
|
[Dependency] private IComponentManager _componentManager;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
base.OnRemove();
|
||||||
|
|
||||||
|
_gui?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void SetGhostVisibility(bool visibility)
|
||||||
|
{
|
||||||
|
// So, for now this is a client-side hack... Please, PLEASE someone make this work server-side.
|
||||||
|
foreach (var ghost in _componentManager.GetAllComponents(typeof(GhostComponent)))
|
||||||
|
{
|
||||||
|
if (ghost.Owner.TryGetComponent(out SpriteComponent component))
|
||||||
|
component.Visible = visibility;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
if (Owner.TryGetComponent(out SpriteComponent component))
|
||||||
|
component.Visible = _playerManager.LocalPlayer.ControlledEntity?.HasComponent<GhostComponent>() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
|
||||||
|
IComponent component = null)
|
||||||
|
{
|
||||||
|
base.HandleMessage(message, netChannel, component);
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case PlayerAttachedMsg _:
|
||||||
|
if (_gui == null)
|
||||||
|
{
|
||||||
|
_gui = new GhostGui(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_gui.Orphan();
|
||||||
|
}
|
||||||
|
|
||||||
|
_gameHud.HandsContainer.AddChild(_gui);
|
||||||
|
SetGhostVisibility(true);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PlayerDetachedMsg _:
|
||||||
|
_gui.Parent?.RemoveChild(_gui);
|
||||||
|
SetGhostVisibility(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendReturnToBodyMessage() => SendNetworkMessage(new ReturnToBodyComponentMessage());
|
||||||
|
|
||||||
|
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||||
|
{
|
||||||
|
base.HandleComponentState(curState, nextState);
|
||||||
|
|
||||||
|
if (!(curState is GhostComponentState state)) return;
|
||||||
|
|
||||||
|
CanReturnToBody = state.CanReturnToBody;
|
||||||
|
|
||||||
|
if (Owner == _playerManager.LocalPlayer.ControlledEntity)
|
||||||
|
{
|
||||||
|
_gui?.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Content.Client/UserInterface/GhostGui.cs
Normal file
34
Content.Client/UserInterface/GhostGui.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Data;
|
||||||
|
using Content.Client.GameObjects.Components.Observer;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Client.UserInterface
|
||||||
|
{
|
||||||
|
public class GhostGui : Control
|
||||||
|
{
|
||||||
|
public Button ReturnToBody = new Button(){Text = "Return to body"};
|
||||||
|
private GhostComponent _owner;
|
||||||
|
|
||||||
|
public GhostGui(GhostComponent owner)
|
||||||
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
_owner = owner;
|
||||||
|
|
||||||
|
MouseFilter = MouseFilterMode.Ignore;
|
||||||
|
|
||||||
|
ReturnToBody.OnPressed += (args) => { owner.SendReturnToBodyMessage(); };
|
||||||
|
|
||||||
|
AddChild(ReturnToBody);
|
||||||
|
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
ReturnToBody.Disabled = !_owner.CanReturnToBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using Content.Server.GameTicking;
|
|||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
using Content.Shared;
|
using Content.Shared;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.IntegrationTests
|
namespace Content.IntegrationTests
|
||||||
@@ -54,6 +55,10 @@ namespace Content.IntegrationTests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GridCoordinates GetLateJoinSpawnPoint() => GridCoordinates.InvalidGrid;
|
||||||
|
public GridCoordinates GetJobSpawnPoint(string jobId) => GridCoordinates.InvalidGrid;
|
||||||
|
public GridCoordinates GetObserverSpawnPoint() => GridCoordinates.InvalidGrid;
|
||||||
|
|
||||||
public T AddGameRule<T>() where T : GameRule, new()
|
public T AddGameRule<T>() where T : GameRule, new()
|
||||||
{
|
{
|
||||||
return new T();
|
return new T();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Players;
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
|
using Content.Server.Players;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
@@ -30,10 +31,14 @@ namespace Content.Server.Administration
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var canReturn = mind.CurrentEntity != null && !mind.CurrentEntity.HasComponent<GhostComponent>();
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||||
var ghost = entityManager.SpawnEntity("AdminObserver", player.AttachedEntity.Transform.GridPosition);
|
var ghost = entityManager.SpawnEntity("AdminObserver", player.AttachedEntity.Transform.GridPosition);
|
||||||
|
if(canReturn)
|
||||||
mind.Visit(ghost);
|
mind.Visit(ghost);
|
||||||
|
else
|
||||||
|
mind.TransferTo(ghost);
|
||||||
|
ghost.GetComponent<GhostComponent>().CanReturnToBody = canReturn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Content.Server.Interfaces.Chat;
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
|
using Content.Server.Interfaces.Chat;
|
||||||
|
using Content.Server.Observer;
|
||||||
using Robust.Server.Interfaces.Console;
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
@@ -24,7 +26,10 @@ namespace Content.Server.Chat
|
|||||||
|
|
||||||
var message = string.Join(" ", args);
|
var message = string.Join(" ", args);
|
||||||
|
|
||||||
chat.EntitySay(player.AttachedEntity, message);
|
if (player.AttachedEntity.HasComponent<GhostComponent>())
|
||||||
|
chat.SendDeadChat(player, message);
|
||||||
|
else
|
||||||
|
chat.EntitySay(player.AttachedEntity, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
using Content.Server.Interfaces.Chat;
|
using Content.Server.Interfaces.Chat;
|
||||||
|
using Content.Server.Observer;
|
||||||
|
using Content.Server.Players;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Interfaces.Network;
|
using Robust.Shared.Interfaces.Network;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
|
||||||
namespace Content.Server.Chat
|
namespace Content.Server.Chat
|
||||||
{
|
{
|
||||||
@@ -20,6 +25,7 @@ namespace Content.Server.Chat
|
|||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[Dependency] private readonly IServerNetManager _netManager;
|
[Dependency] private readonly IServerNetManager _netManager;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager;
|
[Dependency] private readonly IPlayerManager _playerManager;
|
||||||
|
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||||
[Dependency] private readonly IMoMMILink _mommiLink;
|
[Dependency] private readonly IMoMMILink _mommiLink;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
@@ -93,6 +99,18 @@ namespace Content.Server.Chat
|
|||||||
_mommiLink.SendOOCMessage(player.SessionId.ToString(), message);
|
_mommiLink.SendOOCMessage(player.SessionId.ToString(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SendDeadChat(IPlayerSession player, string message)
|
||||||
|
{
|
||||||
|
var clients = _playerManager.GetPlayersBy(x => x.AttachedEntity != null && x.AttachedEntity.HasComponent<GhostComponent>()).Select(p => p.ConnectedClient);;
|
||||||
|
|
||||||
|
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
||||||
|
msg.Channel = ChatChannel.Dead;
|
||||||
|
msg.Message = message;
|
||||||
|
msg.MessageWrap = $"{_localizationManager.GetString("DEAD")}: {player.AttachedEntity.Name}: {{0}}";
|
||||||
|
msg.SenderEntity = player.AttachedEntityUid.GetValueOrDefault();
|
||||||
|
_netManager.ServerSendToMany(msg, clients.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
public void SendHookOOC(string sender, string message)
|
public void SendHookOOC(string sender, string message)
|
||||||
{
|
{
|
||||||
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
||||||
|
|||||||
@@ -75,7 +75,13 @@ namespace Content.Server.GameObjects
|
|||||||
{
|
{
|
||||||
if (damageType == DamageType.Total)
|
if (damageType == DamageType.Total)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Cannot take damage for DamageType.Total");
|
foreach (DamageType e in Enum.GetValues(typeof(DamageType)))
|
||||||
|
{
|
||||||
|
if (e == damageType) continue;
|
||||||
|
TakeDamage(e, amount, source, sourceMob);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
InitializeDamageType(damageType);
|
InitializeDamageType(damageType);
|
||||||
|
|
||||||
|
|||||||
@@ -38,5 +38,6 @@ namespace Content.Server.GameObjects.Components.Markers
|
|||||||
Unset = 0,
|
Unset = 0,
|
||||||
LateJoin,
|
LateJoin,
|
||||||
Job,
|
Job,
|
||||||
|
Observer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.GameObjects.Components.Observer;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using Timer = Robust.Shared.Timers.Timer;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Observer
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class GhostComponent : SharedGhostComponent, IActionBlocker
|
||||||
|
{
|
||||||
|
private bool _canReturnToBody = true;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool CanReturnToBody
|
||||||
|
{
|
||||||
|
get => _canReturnToBody;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_canReturnToBody = value;
|
||||||
|
Dirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ComponentState GetComponentState() => new GhostComponentState(CanReturnToBody);
|
||||||
|
|
||||||
|
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
|
||||||
|
IComponent component = null)
|
||||||
|
{
|
||||||
|
base.HandleMessage(message, netChannel, component);
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case ReturnToBodyComponentMessage reenter:
|
||||||
|
if (!Owner.TryGetComponent(out IActorComponent actor) || !CanReturnToBody) break;
|
||||||
|
if (netChannel == null || netChannel == actor.playerSession.ConnectedClient)
|
||||||
|
{
|
||||||
|
actor.playerSession.ContentData().Mind.UnVisit();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PlayerAttachedMsg _:
|
||||||
|
Dirty();
|
||||||
|
break;
|
||||||
|
case PlayerDetachedMsg _:
|
||||||
|
Timer.Spawn(100, Owner.Delete);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanInteract() => false;
|
||||||
|
public bool CanUse() => false;
|
||||||
|
public bool CanThrow() => false;
|
||||||
|
public bool CanDrop() => false;
|
||||||
|
public bool CanPickup() => false;
|
||||||
|
public bool CanEmote() => false;
|
||||||
|
public bool CanAttack() => false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,23 +5,23 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
public interface IActionBlocker
|
public interface IActionBlocker
|
||||||
{
|
{
|
||||||
bool CanMove();
|
bool CanMove() => true;
|
||||||
|
|
||||||
bool CanInteract();
|
bool CanInteract() => true;
|
||||||
|
|
||||||
bool CanUse();
|
bool CanUse() => true;
|
||||||
|
|
||||||
bool CanThrow();
|
bool CanThrow() => true;
|
||||||
|
|
||||||
bool CanSpeak();
|
bool CanSpeak() => true;
|
||||||
|
|
||||||
bool CanDrop();
|
bool CanDrop() => true;
|
||||||
|
|
||||||
bool CanPickup();
|
bool CanPickup() => true;
|
||||||
|
|
||||||
bool CanEmote();
|
bool CanEmote() => true;
|
||||||
|
|
||||||
bool CanAttack();
|
bool CanAttack() => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ActionBlockerSystem : EntitySystem
|
public class ActionBlockerSystem : EntitySystem
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ using Content.Server.GameObjects.Components.Mobs;
|
|||||||
using Content.Server.GameObjects.Components.Movement;
|
using Content.Server.GameObjects.Components.Movement;
|
||||||
using Content.Server.GameObjects.Components.Sound;
|
using Content.Server.GameObjects.Components.Sound;
|
||||||
using Content.Server.Interfaces.GameObjects.Components.Movement;
|
using Content.Server.Interfaces.GameObjects.Components.Movement;
|
||||||
|
using Content.Server.Observer;
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.GameObjects.Components.Inventory;
|
using Content.Shared.GameObjects.Components.Inventory;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.GameObjects.EntitySystems;
|
using Robust.Server.GameObjects.EntitySystems;
|
||||||
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Server.Interfaces.Timing;
|
using Robust.Server.Interfaces.Timing;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
@@ -25,6 +27,7 @@ using Robust.Shared.IoC;
|
|||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
@@ -138,6 +141,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
if (physics.LinearVelocity != Vector2.Zero)
|
if (physics.LinearVelocity != Vector2.Zero)
|
||||||
physics.LinearVelocity = Vector2.Zero;
|
physics.LinearVelocity = Vector2.Zero;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -185,6 +189,11 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
if (!TryGetAttachedComponent(session as IPlayerSession, out IMoverComponent moverComp))
|
if (!TryGetAttachedComponent(session as IPlayerSession, out IMoverComponent moverComp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var owner = (session as IPlayerSession)?.AttachedEntity;
|
||||||
|
|
||||||
|
if (owner != null && owner.TryGetComponent(out SpeciesComponent species) && species.CurrentDamageState is DeadState)
|
||||||
|
new Ghost().Execute(null, (IPlayerSession)session, null);
|
||||||
|
|
||||||
moverComp.SetVelocityDirection(dir, state);
|
moverComp.SetVelocityDirection(dir, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
private IEntity _spawnPlayerMob(Job job, bool lateJoin = true)
|
private IEntity _spawnPlayerMob(Job job, bool lateJoin = true)
|
||||||
{
|
{
|
||||||
GridCoordinates coordinates = lateJoin ? _getLateJoinSpawnPoint() : _getJobSpawnPoint(job.Prototype.ID);
|
GridCoordinates coordinates = lateJoin ? GetLateJoinSpawnPoint() : GetJobSpawnPoint(job.Prototype.ID);
|
||||||
var entity = _entityManager.SpawnEntity(PlayerPrototypeName, coordinates);
|
var entity = _entityManager.SpawnEntity(PlayerPrototypeName, coordinates);
|
||||||
if (entity.TryGetComponent(out InventoryComponent inventory))
|
if (entity.TryGetComponent(out InventoryComponent inventory))
|
||||||
{
|
{
|
||||||
@@ -299,11 +299,11 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
private IEntity _spawnObserverMob()
|
private IEntity _spawnObserverMob()
|
||||||
{
|
{
|
||||||
GridCoordinates coordinates = _getLateJoinSpawnPoint();
|
var coordinates = GetObserverSpawnPoint();
|
||||||
return _entityManager.SpawnEntity(ObserverPrototypeName, coordinates);
|
return _entityManager.SpawnEntity(ObserverPrototypeName, coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GridCoordinates _getLateJoinSpawnPoint()
|
public GridCoordinates GetLateJoinSpawnPoint()
|
||||||
{
|
{
|
||||||
var location = _spawnPoint;
|
var location = _spawnPoint;
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ namespace Content.Server.GameTicking
|
|||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GridCoordinates _getJobSpawnPoint(string jobId)
|
public GridCoordinates GetJobSpawnPoint(string jobId)
|
||||||
{
|
{
|
||||||
var location = _spawnPoint;
|
var location = _spawnPoint;
|
||||||
|
|
||||||
@@ -336,6 +336,23 @@ namespace Content.Server.GameTicking
|
|||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GridCoordinates GetObserverSpawnPoint()
|
||||||
|
{
|
||||||
|
var location = _spawnPoint;
|
||||||
|
|
||||||
|
var possiblePoints = new List<GridCoordinates>();
|
||||||
|
foreach (var entity in _entityManager.GetEntities(new TypeEntityQuery(typeof(SpawnPointComponent))))
|
||||||
|
{
|
||||||
|
var point = entity.GetComponent<SpawnPointComponent>();
|
||||||
|
if (point.SpawnType == SpawnPointType.Observer)
|
||||||
|
possiblePoints.Add(entity.Transform.GridPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (possiblePoints.Count != 0) location = _robustRandom.Pick(possiblePoints);
|
||||||
|
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cleanup that has to run to clear up anything from the previous round.
|
/// Cleanup that has to run to clear up anything from the previous round.
|
||||||
/// Stuff like wiping the previous map clean.
|
/// Stuff like wiping the previous map clean.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace Content.Server.Interfaces.Chat
|
|||||||
void EntityMe(IEntity source, string action);
|
void EntityMe(IEntity source, string action);
|
||||||
|
|
||||||
void SendOOC(IPlayerSession player, string message);
|
void SendOOC(IPlayerSession player, string message);
|
||||||
|
void SendDeadChat(IPlayerSession player, string message);
|
||||||
|
|
||||||
void SendHookOOC(string sender, string message);
|
void SendHookOOC(string sender, string message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Server.Interfaces.GameTicking
|
namespace Content.Server.Interfaces.GameTicking
|
||||||
@@ -27,6 +28,10 @@ namespace Content.Server.Interfaces.GameTicking
|
|||||||
void MakeJoinGame(IPlayerSession player);
|
void MakeJoinGame(IPlayerSession player);
|
||||||
void ToggleReady(IPlayerSession player, bool ready);
|
void ToggleReady(IPlayerSession player, bool ready);
|
||||||
|
|
||||||
|
GridCoordinates GetLateJoinSpawnPoint();
|
||||||
|
GridCoordinates GetJobSpawnPoint(string jobId);
|
||||||
|
GridCoordinates GetObserverSpawnPoint();
|
||||||
|
|
||||||
// GameRule system.
|
// GameRule system.
|
||||||
T AddGameRule<T>() where T : GameRule, new();
|
T AddGameRule<T>() where T : GameRule, new();
|
||||||
void RemoveGameRule(GameRule rule);
|
void RemoveGameRule(GameRule rule);
|
||||||
|
|||||||
74
Content.Server/Observer/Ghost.cs
Normal file
74
Content.Server/Observer/Ghost.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using Content.Server.GameObjects;
|
||||||
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Server.Interfaces.GameTicking;
|
||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.GameObjects;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.Server.Observer
|
||||||
|
{
|
||||||
|
public class Ghost : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "ghost";
|
||||||
|
public string Description => "Give up on life and become a ghost.";
|
||||||
|
public string Help => "ghost";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
shell.SendText((IPlayerSession) null, "Nah");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mind = player.ContentData().Mind;
|
||||||
|
var canReturn = player.AttachedEntity != null;
|
||||||
|
var name = player.AttachedEntity?.Name ?? player.Name;
|
||||||
|
|
||||||
|
if (player.AttachedEntity != null && player.AttachedEntity.HasComponent<GhostComponent>())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mind.VisitingEntity != null)
|
||||||
|
{
|
||||||
|
mind.UnVisit();
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = player.AttachedEntity?.Transform.GridPosition ?? IoCManager.Resolve<IGameTicker>().GetObserverSpawnPoint();
|
||||||
|
|
||||||
|
if (canReturn && player.AttachedEntity.TryGetComponent(out SpeciesComponent species))
|
||||||
|
{
|
||||||
|
switch (species.CurrentDamageState)
|
||||||
|
{
|
||||||
|
case DeadState _:
|
||||||
|
canReturn = true;
|
||||||
|
break;
|
||||||
|
case CriticalState _:
|
||||||
|
canReturn = true;
|
||||||
|
if (!player.AttachedEntity.TryGetComponent(out DamageableComponent damageable)) break;
|
||||||
|
damageable.TakeDamage(DamageType.Total, 100); // TODO: Use airloss/oxyloss instead
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
canReturn = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
var ghost = entityManager.SpawnEntity("MobObserver", position);
|
||||||
|
ghost.Name = name;
|
||||||
|
var ghostComponent = ghost.GetComponent<GhostComponent>();
|
||||||
|
ghostComponent.CanReturnToBody = canReturn;
|
||||||
|
|
||||||
|
if(canReturn)
|
||||||
|
mind.Visit(ghost);
|
||||||
|
else
|
||||||
|
mind.TransferTo(ghost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ namespace Content.Shared.Chat
|
|||||||
/// Represents chat channels that the player can filter chat tabs by.
|
/// Represents chat channels that the player can filter chat tabs by.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum ChatChannel : byte
|
public enum ChatChannel : short
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|
||||||
@@ -46,9 +46,14 @@ namespace Content.Shared.Chat
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Emotes = 64,
|
Emotes = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deadchat
|
||||||
|
/// </summary>
|
||||||
|
Dead = 128,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unspecified.
|
/// Unspecified.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Unspecified = 128,
|
Unspecified = 256,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace Content.Shared.Chat
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sending entity.
|
/// The sending entity.
|
||||||
/// Only applies to <see cref="ChatChannel.Local"/> and <see cref="ChatChannel.Emotes"/>.
|
/// Only applies to <see cref="ChatChannel.Local"/>, <see cref="ChatChannel.Dead"/> and <see cref="ChatChannel.Emotes"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EntityUid SenderEntity { get; set; }
|
public EntityUid SenderEntity { get; set; }
|
||||||
|
|
||||||
@@ -48,6 +48,7 @@ namespace Content.Shared.Chat
|
|||||||
switch (Channel)
|
switch (Channel)
|
||||||
{
|
{
|
||||||
case ChatChannel.Local:
|
case ChatChannel.Local:
|
||||||
|
case ChatChannel.Dead:
|
||||||
case ChatChannel.Emotes:
|
case ChatChannel.Emotes:
|
||||||
SenderEntity = buffer.ReadEntityUid();
|
SenderEntity = buffer.ReadEntityUid();
|
||||||
break;
|
break;
|
||||||
@@ -63,6 +64,7 @@ namespace Content.Shared.Chat
|
|||||||
switch (Channel)
|
switch (Channel)
|
||||||
{
|
{
|
||||||
case ChatChannel.Local:
|
case ChatChannel.Local:
|
||||||
|
case ChatChannel.Dead:
|
||||||
case ChatChannel.Emotes:
|
case ChatChannel.Emotes:
|
||||||
buffer.Write(SenderEntity);
|
buffer.Write(SenderEntity);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.GameObjects.Components.Observer
|
||||||
|
{
|
||||||
|
public class SharedGhostComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Ghost";
|
||||||
|
public override uint? NetID => ContentNetIDs.GHOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class GhostComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public bool CanReturnToBody { get; }
|
||||||
|
|
||||||
|
public GhostComponentState(bool canReturnToBody) : base(ContentNetIDs.GHOST)
|
||||||
|
{
|
||||||
|
CanReturnToBody = canReturnToBody;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReturnToBodyComponentMessage : ComponentMessage
|
||||||
|
{
|
||||||
|
public ReturnToBodyComponentMessage() => Directed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,5 +41,6 @@
|
|||||||
public const uint HANDHELD_LIGHT = 1036;
|
public const uint HANDHELD_LIGHT = 1036;
|
||||||
public const uint PAPER = 1037;
|
public const uint PAPER = 1037;
|
||||||
public const uint REAGENT_INJECTOR = 1038;
|
public const uint REAGENT_INJECTOR = 1038;
|
||||||
|
public const uint GHOST = 1039;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
- ooc
|
- ooc
|
||||||
- observe
|
- observe
|
||||||
- toggleready
|
- toggleready
|
||||||
|
- ghost
|
||||||
|
|
||||||
- Index: 50
|
- Index: 50
|
||||||
Name: Moderator
|
Name: Moderator
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
- showtime
|
- showtime
|
||||||
- observe
|
- observe
|
||||||
- toggleready
|
- toggleready
|
||||||
|
- ghost
|
||||||
- kick
|
- kick
|
||||||
- listplayers
|
- listplayers
|
||||||
- loc
|
- loc
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
- aghost
|
- aghost
|
||||||
- observe
|
- observe
|
||||||
- toggleready
|
- toggleready
|
||||||
|
- ghost
|
||||||
- spawn
|
- spawn
|
||||||
- delete
|
- delete
|
||||||
- tp
|
- tp
|
||||||
@@ -84,6 +87,7 @@
|
|||||||
- aghost
|
- aghost
|
||||||
- observe
|
- observe
|
||||||
- toggleready
|
- toggleready
|
||||||
|
- ghost
|
||||||
- spawn
|
- spawn
|
||||||
- delete
|
- delete
|
||||||
- tp
|
- tp
|
||||||
|
|||||||
@@ -15,3 +15,8 @@
|
|||||||
- type: Examiner
|
- type: Examiner
|
||||||
DoRangeCheck: false
|
DoRangeCheck: false
|
||||||
- type: IgnorePause
|
- type: IgnorePause
|
||||||
|
- type: Ghost
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
drawdepth: Mobs
|
||||||
|
texture: Mob/observer.png
|
||||||
|
|||||||
Submodule RobustToolbox updated: ec52102d02...1cdb279319
Reference in New Issue
Block a user