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);
BuckleStatus();
SendMessage(new BuckleMessage(Owner, to));
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)
{
ContainerHelpers.AttachParentToContainerOrGrid(Owner.Transform);
Owner.Transform.WorldRotation = BuckledTo.Owner.Transform.WorldRotation;
}
var oldBuckledTo = BuckledTo;
BuckledTo = null;
if (Owner.TryGetComponent(out AppearanceComponent appearance))
@@ -353,6 +349,15 @@ namespace Content.Server.GameObjects.Components.Buckle
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;
}

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.Interfaces.GameTicking;
using Content.Server.Mobs;
@@ -21,7 +22,7 @@ namespace Content.Server.GameObjects.Components.Mobs
[RegisterComponent]
public class MindComponent : Component, IExamine
{
private bool _showExamineInfo = false;
private bool _showExamineInfo;
/// <inheritdoc />
public override string Name => "Mind";
@@ -30,7 +31,7 @@ namespace Content.Server.GameObjects.Components.Mobs
/// The mind controlling this mob. Can be null.
/// </summary>
[ViewVariables]
public Mind Mind { get; private set; }
public Mind? Mind { get; private set; }
/// <summary>
/// True if we have a mind, false otherwise.
@@ -74,7 +75,7 @@ namespace Content.Server.GameObjects.Components.Mobs
if (HasMind)
{
var visiting = Mind.VisitingEntity;
var visiting = Mind?.VisitingEntity;
if (visiting != null)
{
if (visiting.TryGetComponent(out GhostComponent ghost))
@@ -82,7 +83,7 @@ namespace Content.Server.GameObjects.Components.Mobs
ghost.CanReturnToBody = false;
}
Mind.TransferTo(visiting);
Mind!.TransferTo(visiting);
}
else
{
@@ -98,11 +99,14 @@ namespace Content.Server.GameObjects.Components.Mobs
}
var ghost = Owner.EntityManager.SpawnEntity("MobObserver", spawnPosition);
ghost.Name = Mind.CharacterName;
var ghostComponent = ghost.GetComponent<GhostComponent>();
ghostComponent.CanReturnToBody = false;
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)
{
if (!ShowExamineInfo || !inDetailsRange)
{
return;
}
var dead = false;
var dead =
Owner.TryGetComponent<SpeciesComponent>(out var species) &&
species.CurrentDamageState is DeadState;
if(Owner.TryGetComponent<SpeciesComponent>(out var species))
if (species.CurrentDamageState is DeadState)
dead = true;
if(!HasMind)
if (!HasMind)
{
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=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]");
}
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Buckle;
using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.Network;
@@ -95,6 +96,14 @@ namespace Content.Server.GameObjects.Components.Mobs
buckle.TryUnbuckle(player);
break;
case StatusEffect.Piloting:
if (!player.TryGetComponent(out ShuttleControllerComponent controller))
{
break;
}
controller.RemoveController();
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.Strap;
using Content.Shared.Physics;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Movement
@@ -21,8 +23,8 @@ namespace Content.Server.GameObjects.Components.Movement
internal class ShuttleControllerComponent : Component, IMoverComponent
{
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager;
[Dependency] private readonly IEntityManager _entityManager;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
#pragma warning restore 649
private bool _movingUp;
@@ -30,11 +32,22 @@ namespace Content.Server.GameObjects.Components.Movement
private bool _movingLeft;
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";
[ViewVariables(VVAccess.ReadWrite)]
public float CurrentWalkSpeed { get; set; } = 8;
public float CurrentSprintSpeed { get; set; }
public float CurrentWalkSpeed { get; } = 8;
public float CurrentSprintSpeed => 0;
/// <inheritdoc />
[ViewVariables]
@@ -44,7 +57,8 @@ namespace Content.Server.GameObjects.Components.Movement
[ViewVariables]
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 GridCoordinates LastPosition { get; set; }
public float StepSoundDistance { get; set; }
@@ -53,7 +67,8 @@ namespace Content.Server.GameObjects.Components.Movement
{
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
if (!gridEntity.TryGetComponent(out IPhysicsComponent physComp))
@@ -115,37 +130,116 @@ namespace Content.Server.GameObjects.Components.Movement
// can't normalize zero length vector
if (result.LengthSquared > 1.0e-6)
{
result = result.Normalized;
}
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 />
public override void HandleMessage(ComponentMessage message, IComponent component)
public override void HandleMessage(ComponentMessage message, IComponent? component)
{
base.HandleMessage(message, component);
switch (message)
{
case ContainerContentsModifiedMessage contents:
if(contents.Entity.TryGetComponent(out MindComponent mindComp))
ContentsChanged(contents.Entity, mindComp, contents.Removed);
case StrapChangeMessage strap:
BuckleChanged(strap.Entity, strap.Buckled);
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>
/// DO NOT CALL THIS DIRECTLY.
/// Adds a buckled entity. Called from <see cref="BuckleComponent.TryBuckle"/>
/// </summary>
/// <param name="buckle">The component to add</param>
@@ -107,6 +108,8 @@ namespace Content.Server.GameObjects.Components.Strap
appearance.SetData(StrapVisuals.RotationAngle, _rotation);
}
SendMessage(new StrapMessage(buckle.Owner, Owner));
return true;
}
@@ -120,6 +123,7 @@ namespace Content.Server.GameObjects.Components.Strap
if (_buckledEntities.Remove(buckle.Owner))
{
_occupiedSize -= buckle.Size;
SendMessage(new UnStrapMessage(buckle.Owner, Owner));
}
}
@@ -157,6 +161,11 @@ namespace Content.Server.GameObjects.Components.Strap
_occupiedSize = 0;
}
public override ComponentState GetComponentState()
{
return new StrapComponentState(Position);
}
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
{
if (!eventArgs.User.TryGetComponent(out BuckleComponent buckle))

View File

@@ -1,6 +1,7 @@
using System;
using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.Buckle
@@ -50,4 +51,62 @@ namespace Content.Shared.GameObjects.Components.Buckle
{
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,
Stun,
Buckled,
Piloting
}
}

View File

@@ -1,5 +1,6 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.Strap
@@ -29,9 +30,81 @@ namespace Content.Shared.GameObjects.Components.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]
public enum StrapVisuals
{
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: Clickable
- type: InteractionOutline
- type: EntityStorage
showContents: true
noDoor: true
- type: Damageable
- type: Destructible
thresholdvalue: 100