Replace Houdini's magical piloting locker with buckle (#1336)

This commit is contained in:
DrSmugleaf
2020-07-26 12:12:53 +02:00
committed by GitHub
parent 4e1597eeb3
commit 96ec60adab
9 changed files with 308 additions and 53 deletions

View File

@@ -273,6 +273,8 @@ namespace Content.Server.GameObjects.Components.Buckle
ReAttach(strap); ReAttach(strap);
BuckleStatus(); BuckleStatus();
SendMessage(new BuckleMessage(Owner, to));
return true; return true;
} }
@@ -317,19 +319,13 @@ namespace Content.Server.GameObjects.Components.Buckle
} }
} }
if (BuckledTo.Owner.TryGetComponent(out StrapComponent strap))
{
strap.Remove(this);
_entitySystem.GetEntitySystem<AudioSystem>()
.PlayFromEntity(strap.UnbuckleSound, Owner);
}
if (Owner.Transform.Parent == BuckledTo.Owner.Transform) if (Owner.Transform.Parent == BuckledTo.Owner.Transform)
{ {
ContainerHelpers.AttachParentToContainerOrGrid(Owner.Transform); ContainerHelpers.AttachParentToContainerOrGrid(Owner.Transform);
Owner.Transform.WorldRotation = BuckledTo.Owner.Transform.WorldRotation; Owner.Transform.WorldRotation = BuckledTo.Owner.Transform.WorldRotation;
} }
var oldBuckledTo = BuckledTo;
BuckledTo = null; BuckledTo = null;
if (Owner.TryGetComponent(out AppearanceComponent appearance)) if (Owner.TryGetComponent(out AppearanceComponent appearance))
@@ -353,6 +349,15 @@ namespace Content.Server.GameObjects.Components.Buckle
BuckleStatus(); BuckleStatus();
if (oldBuckledTo.Owner.TryGetComponent(out StrapComponent strap))
{
strap.Remove(this);
_entitySystem.GetEntitySystem<AudioSystem>()
.PlayFromEntity(strap.UnbuckleSound, Owner);
}
SendMessage(new UnbuckleMessage(Owner, oldBuckledTo.Owner));
return true; return true;
} }

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Observer; #nullable enable
using Content.Server.GameObjects.Components.Observer;
using Content.Server.GameObjects.EntitySystems.Click; using Content.Server.GameObjects.EntitySystems.Click;
using Content.Server.Interfaces.GameTicking; using Content.Server.Interfaces.GameTicking;
using Content.Server.Mobs; using Content.Server.Mobs;
@@ -21,7 +22,7 @@ namespace Content.Server.GameObjects.Components.Mobs
[RegisterComponent] [RegisterComponent]
public class MindComponent : Component, IExamine public class MindComponent : Component, IExamine
{ {
private bool _showExamineInfo = false; private bool _showExamineInfo;
/// <inheritdoc /> /// <inheritdoc />
public override string Name => "Mind"; public override string Name => "Mind";
@@ -30,7 +31,7 @@ namespace Content.Server.GameObjects.Components.Mobs
/// The mind controlling this mob. Can be null. /// The mind controlling this mob. Can be null.
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public Mind Mind { get; private set; } public Mind? Mind { get; private set; }
/// <summary> /// <summary>
/// True if we have a mind, false otherwise. /// True if we have a mind, false otherwise.
@@ -74,7 +75,7 @@ namespace Content.Server.GameObjects.Components.Mobs
if (HasMind) if (HasMind)
{ {
var visiting = Mind.VisitingEntity; var visiting = Mind?.VisitingEntity;
if (visiting != null) if (visiting != null)
{ {
if (visiting.TryGetComponent(out GhostComponent ghost)) if (visiting.TryGetComponent(out GhostComponent ghost))
@@ -82,7 +83,7 @@ namespace Content.Server.GameObjects.Components.Mobs
ghost.CanReturnToBody = false; ghost.CanReturnToBody = false;
} }
Mind.TransferTo(visiting); Mind!.TransferTo(visiting);
} }
else else
{ {
@@ -98,11 +99,14 @@ namespace Content.Server.GameObjects.Components.Mobs
} }
var ghost = Owner.EntityManager.SpawnEntity("MobObserver", spawnPosition); var ghost = Owner.EntityManager.SpawnEntity("MobObserver", spawnPosition);
ghost.Name = Mind.CharacterName;
var ghostComponent = ghost.GetComponent<GhostComponent>(); var ghostComponent = ghost.GetComponent<GhostComponent>();
ghostComponent.CanReturnToBody = false; ghostComponent.CanReturnToBody = false;
Mind.TransferTo(ghost);
if (Mind != null)
{
ghost.Name = Mind.CharacterName;
Mind.TransferTo(ghost);
}
}); });
} }
} }
@@ -117,20 +121,24 @@ namespace Content.Server.GameObjects.Components.Mobs
public void Examine(FormattedMessage message, bool inDetailsRange) public void Examine(FormattedMessage message, bool inDetailsRange)
{ {
if (!ShowExamineInfo || !inDetailsRange) if (!ShowExamineInfo || !inDetailsRange)
{
return; return;
}
var dead = false; var dead =
Owner.TryGetComponent<SpeciesComponent>(out var species) &&
species.CurrentDamageState is DeadState;
if(Owner.TryGetComponent<SpeciesComponent>(out var species)) if (!HasMind)
if (species.CurrentDamageState is DeadState) {
dead = true;
if(!HasMind)
message.AddMarkup(!dead message.AddMarkup(!dead
? $"[color=red]" + Loc.GetString("{0:They} are totally catatonic. The stresses of life in deep-space must have been too much for {0:them}. Any recovery is unlikely.", Owner) + "[/color]" ? $"[color=red]" + Loc.GetString("{0:They} are totally catatonic. The stresses of life in deep-space must have been too much for {0:them}. Any recovery is unlikely.", Owner) + "[/color]"
: $"[color=purple]" + Loc.GetString("{0:Their} soul has departed.", Owner) + "[/color]"); : $"[color=purple]" + Loc.GetString("{0:Their} soul has departed.", Owner) + "[/color]");
else if (Mind.Session == null) }
else if (Mind?.Session == null)
{
message.AddMarkup("[color=yellow]" + Loc.GetString("{0:They} have a blank, absent-minded stare and appears completely unresponsive to anything. {0:They} may snap out of it soon.", Owner) + "[/color]"); message.AddMarkup("[color=yellow]" + Loc.GetString("{0:They} have a blank, absent-minded stare and appears completely unresponsive to anything. {0:They} may snap out of it soon.", Owner) + "[/color]");
}
} }
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.Components.Buckle; using Content.Server.GameObjects.Components.Buckle;
using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Mobs;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Network;
@@ -95,6 +96,14 @@ namespace Content.Server.GameObjects.Components.Mobs
buckle.TryUnbuckle(player); buckle.TryUnbuckle(player);
break; break;
case StatusEffect.Piloting:
if (!player.TryGetComponent(out ShuttleControllerComponent controller))
{
break;
}
controller.RemoveController();
break;
} }
break; break;

View File

@@ -1,17 +1,19 @@
using Content.Server.GameObjects.Components.Mobs; #nullable enable
using Content.Server.GameObjects.Components.Buckle;
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Strap;
using Content.Shared.Physics; using Content.Shared.Physics;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC; 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.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Movement namespace Content.Server.GameObjects.Components.Movement
@@ -21,8 +23,8 @@ namespace Content.Server.GameObjects.Components.Movement
internal class ShuttleControllerComponent : Component, IMoverComponent internal class ShuttleControllerComponent : Component, IMoverComponent
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IEntityManager _entityManager; [Dependency] private readonly IEntityManager _entityManager = default!;
#pragma warning restore 649 #pragma warning restore 649
private bool _movingUp; private bool _movingUp;
@@ -30,11 +32,22 @@ namespace Content.Server.GameObjects.Components.Movement
private bool _movingLeft; private bool _movingLeft;
private bool _movingRight; private bool _movingRight;
/// <summary>
/// The icon to be displayed when piloting from this chair.
/// </summary>
private string _pilotingIcon = default!;
/// <summary>
/// The entity that's currently controlling this component.
/// Changed from <see cref="SetController"/> and <see cref="RemoveController"/>
/// </summary>
private IEntity? _controller;
public override string Name => "ShuttleController"; public override string Name => "ShuttleController";
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public float CurrentWalkSpeed { get; set; } = 8; public float CurrentWalkSpeed { get; } = 8;
public float CurrentSprintSpeed { get; set; } public float CurrentSprintSpeed => 0;
/// <inheritdoc /> /// <inheritdoc />
[ViewVariables] [ViewVariables]
@@ -44,7 +57,8 @@ namespace Content.Server.GameObjects.Components.Movement
[ViewVariables] [ViewVariables]
public float GrabRange => 0.0f; public float GrabRange => 0.0f;
public bool Sprinting { get; set; } public bool Sprinting => false;
public (Vector2 walking, Vector2 sprinting) VelocityDir { get; } = (Vector2.Zero, Vector2.Zero); public (Vector2 walking, Vector2 sprinting) VelocityDir { get; } = (Vector2.Zero, Vector2.Zero);
public GridCoordinates LastPosition { get; set; } public GridCoordinates LastPosition { get; set; }
public float StepSoundDistance { get; set; } public float StepSoundDistance { get; set; }
@@ -53,7 +67,8 @@ namespace Content.Server.GameObjects.Components.Movement
{ {
var gridId = Owner.Transform.GridID; var gridId = Owner.Transform.GridID;
if (_mapManager.TryGetGrid(gridId, out var grid) && _entityManager.TryGetEntity(grid.GridEntityId, out var gridEntity)) if (_mapManager.TryGetGrid(gridId, out var grid) &&
_entityManager.TryGetEntity(grid.GridEntityId, out var gridEntity))
{ {
//TODO: Switch to shuttle component //TODO: Switch to shuttle component
if (!gridEntity.TryGetComponent(out IPhysicsComponent physComp)) if (!gridEntity.TryGetComponent(out IPhysicsComponent physComp))
@@ -115,37 +130,116 @@ namespace Content.Server.GameObjects.Components.Movement
// can't normalize zero length vector // can't normalize zero length vector
if (result.LengthSquared > 1.0e-6) if (result.LengthSquared > 1.0e-6)
{
result = result.Normalized; result = result.Normalized;
}
return result; return result;
} }
/// <summary>
/// Changes the entity currently controlling this shuttle controller
/// </summary>
/// <param name="entity">The entity to set</param>
private void SetController(IEntity entity)
{
if (_controller != null ||
!entity.TryGetComponent(out MindComponent mind) ||
mind.Mind == null ||
!Owner.TryGetComponent(out ServerStatusEffectsComponent status))
{
return;
}
mind.Mind.Visit(Owner);
_controller = entity;
status.ChangeStatusEffectIcon(StatusEffect.Piloting, _pilotingIcon);
}
/// <summary>
/// Removes the current controller
/// </summary>
/// <param name="entity">The entity to remove, or null to force the removal of any current controller</param>
public void RemoveController(IEntity? entity = null)
{
if (_controller == null)
{
return;
}
// If we are not forcing a controller removal and the entity is not the current controller
if (entity != null && entity != _controller)
{
return;
}
UpdateRemovedEntity(entity ?? _controller);
_controller = null;
}
/// <summary>
/// Updates the state of an entity that is no longer controlling this shuttle controller.
/// Called from <see cref="RemoveController"/>
/// </summary>
/// <param name="entity">The entity to update</param>
private void UpdateRemovedEntity(IEntity entity)
{
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
{
status.RemoveStatusEffect(StatusEffect.Piloting);
}
if (entity.TryGetComponent(out MindComponent mind))
{
mind.Mind?.UnVisit();
}
if (entity.TryGetComponent(out BuckleComponent buckle))
{
buckle.TryUnbuckle(entity, true);
}
}
private void BuckleChanged(IEntity entity, in bool buckled)
{
Logger.DebugS("shuttle", $"Pilot={entity.Name}, buckled={buckled}");
if (buckled)
{
SetController(entity);
}
else
{
RemoveController(entity);
}
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _pilotingIcon, "pilotingIcon", "/Textures/Interface/StatusEffects/Buckle/buckled.png");
}
public override void Initialize()
{
base.Initialize();
Owner.EnsureComponent<ServerStatusEffectsComponent>();
}
/// <inheritdoc /> /// <inheritdoc />
public override void HandleMessage(ComponentMessage message, IComponent component) public override void HandleMessage(ComponentMessage message, IComponent? component)
{ {
base.HandleMessage(message, component); base.HandleMessage(message, component);
switch (message) switch (message)
{ {
case ContainerContentsModifiedMessage contents: case StrapChangeMessage strap:
if(contents.Entity.TryGetComponent(out MindComponent mindComp)) BuckleChanged(strap.Entity, strap.Buckled);
ContentsChanged(contents.Entity, mindComp, contents.Removed);
break; break;
} }
} }
private void ContentsChanged(IEntity entity, MindComponent mindComp, in bool removed)
{
Logger.DebugS("shuttle", $"Pilot={entity.Name}, removed={removed}");
if (!removed)
{
mindComp.Mind?.Visit(Owner);
}
else
{
mindComp.Mind?.UnVisit();
}
}
} }
} }

View File

@@ -81,6 +81,7 @@ namespace Content.Server.GameObjects.Components.Strap
} }
/// <summary> /// <summary>
/// DO NOT CALL THIS DIRECTLY.
/// Adds a buckled entity. Called from <see cref="BuckleComponent.TryBuckle"/> /// Adds a buckled entity. Called from <see cref="BuckleComponent.TryBuckle"/>
/// </summary> /// </summary>
/// <param name="buckle">The component to add</param> /// <param name="buckle">The component to add</param>
@@ -107,6 +108,8 @@ namespace Content.Server.GameObjects.Components.Strap
appearance.SetData(StrapVisuals.RotationAngle, _rotation); appearance.SetData(StrapVisuals.RotationAngle, _rotation);
} }
SendMessage(new StrapMessage(buckle.Owner, Owner));
return true; return true;
} }
@@ -120,6 +123,7 @@ namespace Content.Server.GameObjects.Components.Strap
if (_buckledEntities.Remove(buckle.Owner)) if (_buckledEntities.Remove(buckle.Owner))
{ {
_occupiedSize -= buckle.Size; _occupiedSize -= buckle.Size;
SendMessage(new UnStrapMessage(buckle.Owner, Owner));
} }
} }
@@ -157,6 +161,11 @@ namespace Content.Server.GameObjects.Components.Strap
_occupiedSize = 0; _occupiedSize = 0;
} }
public override ComponentState GetComponentState()
{
return new StrapComponentState(Position);
}
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out BuckleComponent buckle)) if (!eventArgs.User.TryGetComponent(out BuckleComponent buckle))

View File

@@ -1,6 +1,7 @@
using System; using System;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.Buckle namespace Content.Shared.GameObjects.Components.Buckle
@@ -50,4 +51,62 @@ namespace Content.Shared.GameObjects.Components.Buckle
{ {
Buckled Buckled
} }
[Serializable, NetSerializable]
public abstract class BuckleChangeMessage : ComponentMessage
{
/// <summary>
/// Constructs a new instance of <see cref="BuckleChangeMessage"/>
/// </summary>
/// <param name="entity">The entity that had its buckling status changed</param>
/// <param name="strap">The strap that the entity was buckled to or unbuckled from</param>
/// <param name="buckled">True if the entity was buckled, false otherwise</param>
protected BuckleChangeMessage(IEntity entity, IEntity strap, bool buckled)
{
Entity = entity;
Strap = strap;
Buckled = buckled;
}
/// <summary>
/// The entity that had its buckling status changed
/// </summary>
public IEntity Entity { get; }
/// <summary>
/// The strap that the entity was buckled to or unbuckled from
/// </summary>
public IEntity Strap { get; }
/// <summary>
/// True if the entity was buckled, false otherwise.
/// </summary>
public bool Buckled { get; }
}
[Serializable, NetSerializable]
public class BuckleMessage : BuckleChangeMessage
{
/// <summary>
/// Constructs a new instance of <see cref="BuckleMessage"/>
/// </summary>
/// <param name="entity">The entity that had its buckling status changed</param>
/// <param name="strap">The strap that the entity was buckled to or unbuckled from</param>
public BuckleMessage(IEntity entity, IEntity strap) : base(entity, strap, true)
{
}
}
[Serializable, NetSerializable]
public class UnbuckleMessage : BuckleChangeMessage
{
/// <summary>
/// Constructs a new instance of <see cref="UnbuckleMessage"/>
/// </summary>
/// <param name="entity">The entity that had its buckling status changed</param>
/// <param name="strap">The strap that the entity was buckled to or unbuckled from</param>
public UnbuckleMessage(IEntity entity, IEntity strap) : base(entity, strap, false)
{
}
}
} }

View File

@@ -58,5 +58,6 @@ namespace Content.Shared.GameObjects.Components.Mobs
Thirst, Thirst,
Stun, Stun,
Buckled, Buckled,
Piloting
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.Strap namespace Content.Shared.GameObjects.Components.Strap
@@ -29,9 +30,81 @@ namespace Content.Shared.GameObjects.Components.Strap
public sealed override uint? NetID => ContentNetIDs.STRAP; public sealed override uint? NetID => ContentNetIDs.STRAP;
} }
[Serializable, NetSerializable]
public sealed class StrapComponentState : ComponentState
{
public StrapComponentState(StrapPosition position) : base(ContentNetIDs.BUCKLE)
{
Position = position;
}
/// <summary>
/// The change in position that this strap makes to the strapped mob
/// </summary>
public StrapPosition Position { get; }
}
[Serializable, NetSerializable] [Serializable, NetSerializable]
public enum StrapVisuals public enum StrapVisuals
{ {
RotationAngle RotationAngle
} }
[Serializable, NetSerializable]
public abstract class StrapChangeMessage : ComponentMessage
{
/// <summary>
/// Constructs a new instance of <see cref="StrapChangeMessage"/>
/// </summary>
/// <param name="entity">The entity that had its buckling status changed</param>
/// <param name="strap">The strap that the entity was buckled to or unbuckled from</param>
/// <param name="buckled">True if the entity was buckled, false otherwise</param>
protected StrapChangeMessage(IEntity entity, IEntity strap, bool buckled)
{
Entity = entity;
Strap = strap;
Buckled = buckled;
}
/// <summary>
/// The entity that had its buckling status changed
/// </summary>
public IEntity Entity { get; }
/// <summary>
/// The strap that the entity was buckled to or unbuckled from
/// </summary>
public IEntity Strap { get; }
/// <summary>
/// True if the entity was buckled, false otherwise.
/// </summary>
public bool Buckled { get; }
}
[Serializable, NetSerializable]
public class StrapMessage : StrapChangeMessage
{
/// <summary>
/// Constructs a new instance of <see cref="StrapMessage"/>
/// </summary>
/// <param name="entity">The entity that had its buckling status changed</param>
/// <param name="strap">The strap that the entity was buckled to or unbuckled from</param>
public StrapMessage(IEntity entity, IEntity strap) : base(entity, strap, true)
{
}
}
[Serializable, NetSerializable]
public class UnStrapMessage : StrapChangeMessage
{
/// <summary>
/// Constructs a new instance of <see cref="UnStrapMessage"/>
/// </summary>
/// <param name="entity">The entity that had its buckling status changed</param>
/// <param name="strap">The strap that the entity was buckled to or unbuckled from</param>
public UnStrapMessage(IEntity entity, IEntity strap) : base(entity, strap, false)
{
}
}
} }

View File

@@ -13,9 +13,6 @@
- type: Collidable - type: Collidable
- type: Clickable - type: Clickable
- type: InteractionOutline - type: InteractionOutline
- type: EntityStorage
showContents: true
noDoor: true
- type: Damageable - type: Damageable
- type: Destructible - type: Destructible
thresholdvalue: 100 thresholdvalue: 100