Merge branch 'master' into DecimalReagents

This commit is contained in:
PrPleGoo
2020-04-09 17:24:22 +02:00
23 changed files with 415 additions and 24 deletions

View File

@@ -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);
} }

View File

@@ -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();
}
}
}
}

View 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;
}
}
}

View File

@@ -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();

View File

@@ -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;
} }
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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>();

View File

@@ -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);

View File

@@ -38,5 +38,6 @@ namespace Content.Server.GameObjects.Components.Markers
Unset = 0, Unset = 0,
LateJoin, LateJoin,
Job, Job,
Observer,
} }
} }

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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);
} }

View File

@@ -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.

View File

@@ -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);
} }

View File

@@ -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);

View 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);
}
}
}

View File

@@ -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,
} }
} }

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
} }
} }

View File

@@ -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

View File

@@ -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