Implement magboots. (#2988)

Got an alert and action and everything.
This commit is contained in:
Pieter-Jan Briers
2021-01-11 19:24:09 +01:00
committed by GitHub
parent 32c14b0e51
commit 052ea49884
15 changed files with 380 additions and 23 deletions

View File

@@ -4,15 +4,13 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Content.Client.GameObjects.Components.Clothing; using Content.Client.GameObjects.Components.Clothing;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Content.Shared.GameObjects.Verbs; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.Preferences.Appearance; using Content.Shared.Preferences.Appearance;
using Robust.Client.Console;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components; using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
using static Content.Shared.GameObjects.Components.Inventory.SharedInventoryComponent.ClientInventoryMessage; using static Content.Shared.GameObjects.Components.Inventory.SharedInventoryComponent.ClientInventoryMessage;
@@ -81,6 +79,46 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
return item != null && _slots.Values.Any(e => e == item); return item != null && _slots.Values.Any(e => e == item);
} }
public override float WalkSpeedModifier
{
get
{
var mod = 1f;
foreach (var slot in _slots.Values)
{
if (slot != null)
{
foreach (var modifier in slot.GetAllComponents<IMoveSpeedModifier>())
{
mod *= modifier.WalkSpeedModifier;
}
}
}
return mod;
}
}
public override float SprintSpeedModifier
{
get
{
var mod = 1f;
foreach (var slot in _slots.Values)
{
if (slot != null)
{
foreach (var modifier in slot.GetAllComponents<IMoveSpeedModifier>())
{
mod *= modifier.SprintSpeedModifier;
}
}
}
return mod;
}
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{ {
base.HandleComponentState(curState, nextState); base.HandleComponentState(curState, nextState);
@@ -120,6 +158,11 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
_slots.Remove(slot); _slots.Remove(slot);
} }
} }
if (Owner.TryGetComponent(out MovementSpeedModifierComponent? mod))
{
mod.RefreshMovementSpeedModifiers();
}
} }
private void _setSlot(Slots slot, IEntity entity) private void _setSlot(Slots slot, IEntity entity)

View File

@@ -0,0 +1,22 @@
using Content.Shared.GameObjects.Components;
using Robust.Shared.GameObjects;
#nullable enable
namespace Content.Client.GameObjects.Components
{
[RegisterComponent]
public sealed class MagbootsComponent : SharedMagbootsComponent
{
public override bool On { get; set; }
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (curState is not MagbootsComponentState compState)
return;
On = compState.On;
OnChanged();
}
}
}

View File

@@ -7,6 +7,7 @@ using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.EntitySystems.Click; using Content.Server.GameObjects.EntitySystems.Click;
using Content.Server.Interfaces.GameObjects; using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
using Content.Shared.GameObjects.EntitySystems.EffectBlocker; using Content.Shared.GameObjects.EntitySystems.EffectBlocker;
@@ -105,6 +106,46 @@ namespace Content.Server.GameObjects.Components.GUI
} }
} }
public override float WalkSpeedModifier
{
get
{
var mod = 1f;
foreach (var slot in _slotContainers.Values)
{
if (slot.ContainedEntity != null)
{
foreach (var modifier in slot.ContainedEntity.GetAllComponents<IMoveSpeedModifier>())
{
mod *= modifier.WalkSpeedModifier;
}
}
}
return mod;
}
}
public override float SprintSpeedModifier
{
get
{
var mod = 1f;
foreach (var slot in _slotContainers.Values)
{
if (slot.ContainedEntity != null)
{
foreach (var modifier in slot.ContainedEntity.GetAllComponents<IMoveSpeedModifier>())
{
mod *= modifier.SprintSpeedModifier;
}
}
}
return mod;
}
}
bool IEffectBlocker.CanSlip() bool IEffectBlocker.CanSlip()
{ {
if (Owner.TryGetComponent(out InventoryComponent inventoryComponent) && if (Owner.TryGetComponent(out InventoryComponent inventoryComponent) &&
@@ -165,7 +206,7 @@ namespace Content.Server.GameObjects.Components.GUI
return GetSlotItem<ItemComponent>(slot); return GetSlotItem<ItemComponent>(slot);
} }
public IEnumerable<T> LookupItems<T>() where T: Component public IEnumerable<T> LookupItems<T>() where T : Component
{ {
return _slotContainers.Values.SelectMany(x => x.ContainedEntities.Select(e => e.GetComponentOrNull<T>())) return _slotContainers.Values.SelectMany(x => x.ContainedEntities.Select(e => e.GetComponentOrNull<T>()))
.Where(x => x != null); .Where(x => x != null);
@@ -185,6 +226,7 @@ namespace Content.Server.GameObjects.Components.GUI
containedEntity = null; containedEntity = null;
Dirty(); Dirty();
} }
return containedEntity?.GetComponent<T>(); return containedEntity?.GetComponent<T>();
} }
@@ -230,12 +272,16 @@ namespace Content.Server.GameObjects.Components.GUI
Dirty(); Dirty();
UpdateMovementSpeed();
return true; return true;
} }
public bool Equip(Slots slot, ItemComponent item, bool mobCheck = true) => Equip(slot, item, mobCheck, out var _); public bool Equip(Slots slot, ItemComponent item, bool mobCheck = true) =>
Equip(slot, item, mobCheck, out var _);
public bool Equip(Slots slot, IEntity entity, bool mobCheck = true) => Equip(slot, entity.GetComponent<ItemComponent>(), mobCheck); public bool Equip(Slots slot, IEntity entity, bool mobCheck = true) =>
Equip(slot, entity.GetComponent<ItemComponent>(), mobCheck);
/// <summary> /// <summary>
/// Checks whether an item can be put in the specified slot. /// Checks whether an item can be put in the specified slot.
@@ -314,9 +360,19 @@ namespace Content.Server.GameObjects.Components.GUI
Dirty(); Dirty();
UpdateMovementSpeed();
return true; return true;
} }
private void UpdateMovementSpeed()
{
if (Owner.TryGetComponent(out MovementSpeedModifierComponent mod))
{
mod.RefreshMovementSpeedModifiers();
}
}
public void ForceUnequip(Slots slot) public void ForceUnequip(Slots slot)
{ {
var inventorySlot = _slotContainers[slot]; var inventorySlot = _slotContainers[slot];
@@ -452,7 +508,7 @@ namespace Content.Server.GameObjects.Components.GUI
var activeHand = hands.GetActiveHand; var activeHand = hands.GetActiveHand;
if (activeHand != null && activeHand.Owner.TryGetComponent(out ItemComponent clothing)) if (activeHand != null && activeHand.Owner.TryGetComponent(out ItemComponent clothing))
{ {
hands.Drop(hands.ActiveHand, doDropInteraction:false); hands.Drop(hands.ActiveHand, doDropInteraction: false);
if (!Equip(msg.Inventoryslot, clothing, true, out var reason)) if (!Equip(msg.Inventoryslot, clothing, true, out var reason))
{ {
hands.PutInHand(clothing); hands.PutInHand(clothing);
@@ -461,6 +517,7 @@ namespace Content.Server.GameObjects.Components.GUI
Owner.PopupMessageCursor(reason); Owner.PopupMessageCursor(reason);
} }
} }
break; break;
} }
case ClientInventoryUpdate.Use: case ClientInventoryUpdate.Use:
@@ -491,7 +548,9 @@ namespace Content.Server.GameObjects.Components.GUI
if (activeHand != null && GetSlotItem(msg.Inventoryslot) == null) if (activeHand != null && GetSlotItem(msg.Inventoryslot) == null)
{ {
var canEquip = CanEquip(msg.Inventoryslot, activeHand, true, out var reason); var canEquip = CanEquip(msg.Inventoryslot, activeHand, true, out var reason);
_hoverEntity = new KeyValuePair<Slots, (EntityUid entity, bool fits)>(msg.Inventoryslot, (activeHand.Owner.Uid, canEquip)); _hoverEntity =
new KeyValuePair<Slots, (EntityUid entity, bool fits)>(msg.Inventoryslot,
(activeHand.Owner.Uid, canEquip));
Dirty(); Dirty();
} }
@@ -519,7 +578,8 @@ namespace Content.Server.GameObjects.Components.GUI
} }
/// <inheritdoc /> /// <inheritdoc />
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null) public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel,
ICommonSession session = null)
{ {
base.HandleNetworkMessage(message, netChannel, session); base.HandleNetworkMessage(message, netChannel, session);

View File

@@ -0,0 +1,157 @@
#nullable enable
using Content.Server.GameObjects.Components.Atmos;
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.Actions;
using Content.Shared.Alert;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
using Content.Shared.GameObjects.Verbs;
using Content.Shared.Interfaces.GameObjects.Components;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.ComponentDependencies;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Localization;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
namespace Content.Server.GameObjects.Components
{
[RegisterComponent]
[ComponentReference(typeof(IActivate))]
public sealed class MagbootsComponent : SharedMagbootsComponent, IUnequipped, IEquipped, IUse, IActivate
{
[ComponentDependency] private ItemComponent? _item = null;
[ComponentDependency] private ItemActionsComponent? _itemActions = null;
[ComponentDependency] private SpriteComponent? _sprite = null;
private bool _on;
[ViewVariables]
public override bool On
{
get => _on;
set
{
_on = value;
UpdateContainer();
_itemActions?.Toggle(ItemActionType.ToggleMagboots, On);
if (_item != null)
_item.EquippedPrefix = On ? "on" : null;
_sprite?.LayerSetState(0, On ? "icon-on" : "icon");
OnChanged();
Dirty();
}
}
public void Toggle(IEntity user)
{
On = !On;
}
void IUnequipped.Unequipped(UnequippedEventArgs eventArgs)
{
if (On && eventArgs.Slot == Slots.SHOES)
{
if (eventArgs.User.TryGetComponent(out MovedByPressureComponent? movedByPressure))
{
movedByPressure.Enabled = true;
}
if (eventArgs.User.TryGetComponent(out ServerAlertsComponent? alerts))
{
alerts.ClearAlert(AlertType.Magboots);
}
}
}
void IEquipped.Equipped(EquippedEventArgs eventArgs)
{
UpdateContainer();
}
private void UpdateContainer()
{
if (!Owner.TryGetContainer(out var container))
return;
if (container.Owner.TryGetComponent(out InventoryComponent? inventoryComponent)
&& inventoryComponent.GetSlotItem(Slots.SHOES)?.Owner == Owner)
{
if (container.Owner.TryGetComponent(out MovedByPressureComponent? movedByPressure))
{
movedByPressure.Enabled = false;
}
if (container.Owner.TryGetComponent(out ServerAlertsComponent? alerts))
{
if (On)
{
alerts.ShowAlert(AlertType.Magboots);
}
else
{
alerts.ClearAlert(AlertType.Magboots);
}
}
}
}
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
{
Toggle(eventArgs.User);
return true;
}
void IActivate.Activate(ActivateEventArgs eventArgs)
{
Toggle(eventArgs.User);
}
public override ComponentState GetComponentState()
{
return new MagbootsComponentState(On);
}
[UsedImplicitly]
public sealed class ToggleMagbootsVerb : Verb<MagbootsComponent>
{
protected override void GetData(IEntity user, MagbootsComponent component, VerbData data)
{
if (!ActionBlockerSystem.CanInteract(user))
{
data.Visibility = VerbVisibility.Invisible;
return;
}
data.Text = Loc.GetString("Toggle Magboots");
}
protected override void Activate(IEntity user, MagbootsComponent component)
{
component.Toggle(user);
}
}
}
[UsedImplicitly]
public sealed class ToggleMagbootsAction : IToggleItemAction
{
public void ExposeData(ObjectSerializer serializer) { }
public bool DoToggleAction(ToggleItemActionEventArgs args)
{
if (!args.Item.TryGetComponent<MagbootsComponent>(out var magboots))
return false;
magboots.Toggle(args.Performer);
return true;
}
}
}

View File

@@ -24,6 +24,7 @@
Error, Error,
ToggleInternals, ToggleInternals,
ToggleLight, ToggleLight,
ToggleMagboots,
DebugInstant, DebugInstant,
DebugToggle, DebugToggle,
DebugTargetPoint, DebugTargetPoint,

View File

@@ -45,6 +45,7 @@
Parched, Parched,
Pulled, Pulled,
Pulling, Pulling,
Magboots,
Debug1, Debug1,
Debug2, Debug2,
Debug3, Debug3,

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Reflection; using Robust.Shared.Interfaces.Reflection;
@@ -11,7 +12,7 @@ using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefine
namespace Content.Shared.GameObjects.Components.Inventory namespace Content.Shared.GameObjects.Components.Inventory
{ {
public abstract class SharedInventoryComponent : Component public abstract class SharedInventoryComponent : Component, IMoveSpeedModifier
{ {
// ReSharper disable UnassignedReadonlyField // ReSharper disable UnassignedReadonlyField
[Dependency] protected readonly IReflectionManager ReflectionManager; [Dependency] protected readonly IReflectionManager ReflectionManager;
@@ -100,5 +101,8 @@ namespace Content.Shared.GameObjects.Components.Inventory
Slot = slot; Slot = slot;
} }
} }
public abstract float WalkSpeedModifier { get; }
public abstract float SprintSpeedModifier { get; }
} }
} }

View File

@@ -1,4 +1,6 @@
using Robust.Shared.GameObjects; using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -54,6 +56,15 @@ namespace Content.Shared.GameObjects.Components.Movement
_movespeedModifiersNeedRefresh = true; _movespeedModifiersNeedRefresh = true;
} }
public static void RefreshItemModifiers(IEntity item)
{
if (item.TryGetContainer(out var container) &&
container.Owner.TryGetComponent(out MovementSpeedModifierComponent mod))
{
mod.RefreshMovementSpeedModifiers();
}
}
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);

View File

@@ -0,0 +1,35 @@
using System;
using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components
{
public abstract class SharedMagbootsComponent : Component, IMoveSpeedModifier
{
public sealed override string Name => "Magboots";
public sealed override uint? NetID => ContentNetIDs.MAGBOOTS;
public abstract bool On { get; set; }
protected void OnChanged()
{
MovementSpeedModifierComponent.RefreshItemModifiers(Owner);
}
public float WalkSpeedModifier => On ? 0.85f : 1;
public float SprintSpeedModifier => On ? 0.65f : 1;
[Serializable, NetSerializable]
public sealed class MagbootsComponentState : ComponentState
{
public bool On { get; }
public MagbootsComponentState(bool @on) : base(ContentNetIDs.MAGBOOTS)
{
On = on;
}
}
}
}

View File

@@ -88,6 +88,7 @@
public const uint REAGENT_GRINDER = 1082; public const uint REAGENT_GRINDER = 1082;
public const uint ACTIONS = 1083; public const uint ACTIONS = 1083;
public const uint DAMAGEABLE = 1084; public const uint DAMAGEABLE = 1084;
public const uint MAGBOOTS = 1085;
// Net IDs for integration tests. // Net IDs for integration tests.
public const uint PREDICTION_TEST = 10001; public const uint PREDICTION_TEST = 10001;

View File

@@ -0,0 +1,13 @@
- type: itemAction
actionType: ToggleMagboots
icon: Clothing/Shoes/Boots/magboots.rsi/icon.png
iconOn: Clothing/Shoes/Boots/magboots.rsi/icon-on.png
name: "Toggle Magboots"
description: "Turn your magboots on."
filters:
- tools
keywords:
- atmos
- air
behaviorType: Toggle
behavior: !type:ToggleMagbootsAction { }

View File

@@ -15,6 +15,7 @@
- category: Temperature - category: Temperature
- category: Hunger - category: Hunger
- category: Thirst - category: Thirst
- alertType: Magboots
- type: alert - type: alert
alertType: LowOxygen alertType: LowOxygen

View File

@@ -0,0 +1,5 @@
- type: alert
alertType: Magboots
icon: { sprite: "/Textures/Clothing/Shoes/Boots/magboots.rsi", state: "icon-on" }
name: "Magboots"
description: You are immume to airflow, but slightly slower.

View File

@@ -1,15 +1,3 @@
- type: entity
parent: ClothingShoesBase
id: ClothingShoesBootsMag
name: magboots
description: Magnetic boots, often used during extravehicular activity to ensure the user remains safely attached to the vehicle.
components:
- type: Sprite
sprite: Clothing/Shoes/Boots/magboots.rsi
state: icon
- type: Clothing
sprite: Clothing/Shoes/Boots/magboots.rsi
- type: entity - type: entity
parent: ClothingShoesBase parent: ClothingShoesBase
id: ClothingShoesBootsWork id: ClothingShoesBootsWork

View File

@@ -0,0 +1,15 @@
- type: entity
parent: ClothingShoesBase
id: ClothingShoesBootsMag
name: magboots
description: Magnetic boots, often used during extravehicular activity to ensure the user remains safely attached to the vehicle.
components:
- type: Sprite
sprite: Clothing/Shoes/Boots/magboots.rsi
state: icon
- type: Clothing
sprite: Clothing/Shoes/Boots/magboots.rsi
- type: Magboots
- type: ItemActions
actions:
- actionType: ToggleMagboots