Merge branch 'master' into 2020-04-28-tool-component

# Conflicts:
#	Content.Server/GameObjects/Components/AnchorableComponent.cs
#	Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs
#	Content.Server/GameObjects/Components/Doors/AirlockComponent.cs
#	Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs
#	Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs
#	Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs
#	Content.Server/GameObjects/Components/WiresComponent.cs
This commit is contained in:
zumorica
2020-05-23 18:00:28 +02:00
47 changed files with 312 additions and 232 deletions

View File

@@ -12,7 +12,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components
{ {
[RegisterComponent] [RegisterComponent]
public class AnchorableComponent : Component, IAttackBy public class AnchorableComponent : Component, IInteractUsing
{ {
public override string Name => "Anchorable"; public override string Name => "Anchorable";
@@ -22,7 +22,7 @@ namespace Content.Server.GameObjects.Components
Owner.EnsureComponent<PhysicsComponent>(); Owner.EnsureComponent<PhysicsComponent>();
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!Owner.TryGetComponent(out PhysicsComponent physics) if (!Owner.TryGetComponent(out PhysicsComponent physics)
|| !eventArgs.AttackWith.TryGetComponent(out ToolComponent tool)) || !eventArgs.AttackWith.TryGetComponent(out ToolComponent tool))

View File

@@ -20,7 +20,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// containers, and can directly inject into a mobs bloodstream. /// containers, and can directly inject into a mobs bloodstream.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class InjectorComponent : SharedInjectorComponent, IAfterAttack, IUse public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly IServerNotifyManager _notifyManager;
@@ -109,17 +109,17 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// Called when clicking on entities while holding in active hand /// Called when clicking on entities while holding in active hand
/// </summary> /// </summary>
/// <param name="eventArgs"></param> /// <param name="eventArgs"></param>
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
//Make sure we have the attacking entity //Make sure we have the attacking entity
if (eventArgs.Attacked == null || !_internalContents.Injector) if (eventArgs.Target == null || !_internalContents.Injector)
{ {
return; return;
} }
var targetEntity = eventArgs.Attacked; var targetEntity = eventArgs.Target;
//Handle injecting/drawing for solutions //Handle injecting/drawing for solutions
if (targetEntity.TryGetComponent<SolutionComponent>(out var targetSolution) && targetSolution.Injectable) if (targetEntity.TryGetComponent<SolutionComponent>(out var targetSolution) && targetSolution.Injectable)
{ {

View File

@@ -23,7 +23,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// (DrinkComponent adds a SolutionComponent if one isn't present). /// (DrinkComponent adds a SolutionComponent if one isn't present).
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
class PourableComponent : Component, IAttackBy class PourableComponent : Component, IInteractUsing
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly IServerNotifyManager _notifyManager;
@@ -58,7 +58,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary> /// </summary>
/// <param name="eventArgs">Attack event args</param> /// <param name="eventArgs">Attack event args</param>
/// <returns></returns> /// <returns></returns>
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
//Get target and check if it can be poured into //Get target and check if it can be poured into
if (!Owner.TryGetComponent<SolutionComponent>(out var targetSolution)) if (!Owner.TryGetComponent<SolutionComponent>(out var targetSolution))
@@ -67,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
return false; return false;
//Get attack entity and check if it can pour out. //Get attack entity and check if it can pour out.
var attackEntity = eventArgs.AttackWith; var attackEntity = eventArgs.Using;
if (!attackEntity.TryGetComponent<SolutionComponent>(out var attackSolution) || !attackSolution.CanPourOut) if (!attackEntity.TryGetComponent<SolutionComponent>(out var attackSolution) || !attackSolution.CanPourOut)
return false; return false;
if (!attackEntity.TryGetComponent<PourableComponent>(out var attackPourable)) if (!attackEntity.TryGetComponent<PourableComponent>(out var attackPourable))

View File

@@ -30,8 +30,8 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
[ComponentReference(typeof(IAttackBy))] [ComponentReference(typeof(IInteractUsing))]
public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IAttackBy, ISolutionChange public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IInteractUsing, ISolutionChange
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly IServerNotifyManager _notifyManager;
@@ -278,7 +278,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary> /// </summary>
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param> /// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
/// <returns></returns> /// <returns></returns>
bool IAttackBy.AttackBy(AttackByEventArgs args) bool IInteractUsing.InteractUsing(InteractUsingEventArgs args)
{ {
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent hands))
{ {

View File

@@ -27,7 +27,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components.Construction namespace Content.Server.GameObjects.Components.Construction
{ {
[RegisterComponent] [RegisterComponent]
public class ConstructionComponent : Component, IAttackBy public class ConstructionComponent : Component, IInteractUsing
{ {
public override string Name => "Construction"; public override string Name => "Construction";
@@ -53,7 +53,7 @@ namespace Content.Server.GameObjects.Components.Construction
Transform = Owner.GetComponent<ITransformComponent>(); Transform = Owner.GetComponent<ITransformComponent>();
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
// default interaction check for AttackBy allows inside blockers, so we will check if its blocked if // default interaction check for AttackBy allows inside blockers, so we will check if its blocked if
// we're not allowed to build on impassable stuff // we're not allowed to build on impassable stuff
@@ -65,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Construction
var stage = Prototype.Stages[Stage]; var stage = Prototype.Stages[Stage];
if (TryProcessStep(stage.Forward, eventArgs.AttackWith, eventArgs.User)) if (TryProcessStep(stage.Forward, eventArgs.Using, eventArgs.User))
{ {
Stage++; Stage++;
if (Stage == Prototype.Stages.Count - 1) if (Stage == Prototype.Stages.Count - 1)
@@ -85,7 +85,7 @@ namespace Content.Server.GameObjects.Components.Construction
} }
} }
else if (TryProcessStep(stage.Backward, eventArgs.AttackWith, eventArgs.User)) else if (TryProcessStep(stage.Backward, eventArgs.Using, eventArgs.User))
{ {
Stage--; Stage--;
if (Stage == 0) if (Stage == 0)

View File

@@ -21,7 +21,7 @@ namespace Content.Server.GameObjects.Components.Doors
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
[ComponentReference(typeof(ServerDoorComponent))] [ComponentReference(typeof(ServerDoorComponent))]
public class AirlockComponent : ServerDoorComponent, IWires, IAttackBy public class AirlockComponent : ServerDoorComponent, IWires, IInteractUsing
{ {
public override string Name => "Airlock"; public override string Name => "Airlock";
@@ -200,7 +200,7 @@ namespace Content.Server.GameObjects.Components.Doors
return _powerDevice.Powered; return _powerDevice.Powered;
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.TryGetComponent<ToolComponent>(out var tool)) if (!eventArgs.AttackWith.TryGetComponent<ToolComponent>(out var tool))
return false; return false;

View File

@@ -16,7 +16,7 @@ namespace Content.Server.GameObjects.Components.Fluids
/// Can a mop click on this entity and dump its fluids /// Can a mop click on this entity and dump its fluids
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class BucketComponent : Component, IAttackBy public class BucketComponent : Component, IInteractUsing
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ILocalizationManager _localizationManager; [Dependency] private readonly ILocalizationManager _localizationManager;
@@ -71,9 +71,9 @@ namespace Content.Server.GameObjects.Components.Fluids
return true; return true;
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.TryGetComponent(out MopComponent mopComponent)) if (!eventArgs.Using.TryGetComponent(out MopComponent mopComponent))
{ {
return false; return false;
} }

View File

@@ -16,7 +16,7 @@ namespace Content.Server.GameObjects.Components.Fluids
/// For cleaning up puddles /// For cleaning up puddles
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class MopComponent : Component, IAfterAttack public class MopComponent : Component, IAfterInteract
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ILocalizationManager _localizationManager; [Dependency] private readonly ILocalizationManager _localizationManager;
@@ -58,12 +58,12 @@ namespace Content.Server.GameObjects.Components.Fluids
} }
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
Solution solution; Solution solution;
if (eventArgs.Attacked == null) if (eventArgs.Target == null)
{ {
if (CurrentVolume <= 0) if (CurrentVolume <= 0)
{ {
@@ -77,7 +77,7 @@ namespace Content.Server.GameObjects.Components.Fluids
return; return;
} }
if (!eventArgs.Attacked.TryGetComponent(out PuddleComponent puddleComponent)) if (!eventArgs.Target.TryGetComponent(out PuddleComponent puddleComponent))
{ {
return; return;
} }

View File

@@ -2,6 +2,7 @@ using Robust.Server.GameObjects.Components.Container;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Network;
using Robust.Shared.Localization;
using Robust.Shared.Timers; using Robust.Shared.Timers;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
@@ -23,15 +24,17 @@ namespace Content.Server.GameObjects
_inventory = Owner.GetComponent<InventoryComponent>(); _inventory = Owner.GetComponent<InventoryComponent>();
} }
bool IInventoryController.CanEquip(Slots slot, IEntity entity, bool flagsCheck) bool IInventoryController.CanEquip(Slots slot, IEntity entity, bool flagsCheck, out string reason)
{ {
var slotMask = SlotMasks[slot]; var slotMask = SlotMasks[slot];
reason = null;
if ((slotMask & (SlotFlags.POCKET | SlotFlags.IDCARD)) != SlotFlags.NONE) if ((slotMask & (SlotFlags.POCKET | SlotFlags.IDCARD)) != SlotFlags.NONE)
{ {
// Can't wear stuff in ID card or pockets unless you have a uniform. // Can't wear stuff in ID card or pockets unless you have a uniform.
if (_inventory.GetSlotItem(Slots.INNERCLOTHING) == null) if (_inventory.GetSlotItem(Slots.INNERCLOTHING) == null)
{ {
reason = Loc.GetString("You need a uniform to store something in your pockets!");
return false; return false;
} }
@@ -44,6 +47,10 @@ namespace Content.Server.GameObjects
{ {
return true; return true;
} }
else if (!flagsCheck)
{
reason = Loc.GetString("This is too large!");
}
} }
} }

View File

@@ -14,7 +14,14 @@ namespace Content.Server.GameObjects
/// <param name="slot">The slot to be equipped into.</param> /// <param name="slot">The slot to be equipped into.</param>
/// <param name="entity">The entity to equip.</param> /// <param name="entity">The entity to equip.</param>
/// <param name="flagsCheck">Whether the entity passes default slot masks & flags checks.</param> /// <param name="flagsCheck">Whether the entity passes default slot masks & flags checks.</param>
/// <param name="reason">The translated reason why the item cannot be equiped, if this function returns false. Can be null.</param>
/// <returns>True if the entity can be equipped, false otherwise</returns> /// <returns>True if the entity can be equipped, false otherwise</returns>
bool CanEquip(Slots slot, IEntity entity, bool flagsCheck) => flagsCheck; bool CanEquip(Slots slot, IEntity entity, bool flagsCheck, out string reason)
{
reason = null;
return flagsCheck;
}
bool CanEquip(Slots slot, IEntity entity, bool flagsCheck) => CanEquip(slot, entity, flagsCheck, out var _);
} }
} }

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks.Dataflow; using System.Threading.Tasks.Dataflow;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces;
using Content.Shared.GameObjects; using Content.Shared.GameObjects;
using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.Container;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
@@ -11,6 +12,7 @@ using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects.Components;
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.Map; using Robust.Shared.Map;
using Robust.Shared.Players; using Robust.Shared.Players;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -24,6 +26,7 @@ namespace Content.Server.GameObjects
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IEntitySystemManager _entitySystemManager; [Dependency] private readonly IEntitySystemManager _entitySystemManager;
[Dependency] private readonly IServerNotifyManager _serverNotifyManager;
#pragma warning restore 649 #pragma warning restore 649
[ViewVariables] [ViewVariables]
@@ -91,8 +94,9 @@ namespace Content.Server.GameObjects
/// </remarks> /// </remarks>
/// <param name="slot">The slot to put the item in.</param> /// <param name="slot">The slot to put the item in.</param>
/// <param name="item">The item to insert into the slot.</param> /// <param name="item">The item to insert into the slot.</param>
/// <param name="reason">The translated reason why the item cannot be equiped, if this function returns false. Can be null.</param>
/// <returns>True if the item was successfully inserted, false otherwise.</returns> /// <returns>True if the item was successfully inserted, false otherwise.</returns>
public bool Equip(Slots slot, ItemComponent item) public bool Equip(Slots slot, ItemComponent item, out string reason)
{ {
if (item == null) if (item == null)
{ {
@@ -100,7 +104,7 @@ namespace Content.Server.GameObjects
"Clothing must be passed here. To remove some clothing from a slot, use Unequip()"); "Clothing must be passed here. To remove some clothing from a slot, use Unequip()");
} }
if (!CanEquip(slot, item)) if (!CanEquip(slot, item, out reason))
{ {
return false; return false;
} }
@@ -117,18 +121,21 @@ namespace Content.Server.GameObjects
return true; return true;
} }
public bool Equip(Slots slot, IEntity entity) => Equip(slot, entity.GetComponent<ItemComponent>()); public bool Equip(Slots slot, ItemComponent item) => Equip(slot, item, out var _);
public bool Equip(Slots slot, IEntity entity) => Equip(slot, entity.GetComponent<ItemComponent>());
/// <summary> /// <summary>
/// Checks whether an item can be put in the specified slot. /// Checks whether an item can be put in the specified slot.
/// </summary> /// </summary>
/// <param name="slot">The slot to check for.</param> /// <param name="slot">The slot to check for.</param>
/// <param name="item">The item to check for.</param> /// <param name="item">The item to check for.</param>
/// <param name="reason">The translated reason why the item cannot be equiped, if this function returns false. Can be null.</param>
/// <returns>True if the item can be inserted into the specified slot.</returns> /// <returns>True if the item can be inserted into the specified slot.</returns>
public bool CanEquip(Slots slot, ItemComponent item) public bool CanEquip(Slots slot, ItemComponent item, out string reason)
{ {
var pass = false; var pass = false;
reason = null;
if (!ActionBlockerSystem.CanEquip(Owner)) if (!ActionBlockerSystem.CanEquip(Owner))
return false; return false;
@@ -139,16 +146,23 @@ namespace Content.Server.GameObjects
{ {
pass = true; pass = true;
} }
else
{
reason = Loc.GetString("This doesn't fit.");
}
} }
if (Owner.TryGetComponent(out IInventoryController controller)) if (Owner.TryGetComponent(out IInventoryController controller))
{ {
pass = controller.CanEquip(slot, item.Owner, pass); pass = controller.CanEquip(slot, item.Owner, pass, out var controllerReason);
reason = controllerReason ?? reason;
} }
return pass && SlotContainers[slot].CanInsert(item.Owner); return pass && SlotContainers[slot].CanInsert(item.Owner);
} }
public bool CanEquip(Slots slot, ItemComponent item) => CanEquip(slot, item, out var _);
public bool CanEquip(Slots slot, IEntity entity) => CanEquip(slot, entity.GetComponent<ItemComponent>()); public bool CanEquip(Slots slot, IEntity entity) => CanEquip(slot, entity.GetComponent<ItemComponent>());
/// <summary> /// <summary>
@@ -282,9 +296,12 @@ namespace Content.Server.GameObjects
if (activeHand != null && activeHand.Owner.TryGetComponent(out ItemComponent clothing)) if (activeHand != null && activeHand.Owner.TryGetComponent(out ItemComponent clothing))
{ {
hands.Drop(hands.ActiveIndex); hands.Drop(hands.ActiveIndex);
if (!Equip(msg.Inventoryslot, clothing)) if (!Equip(msg.Inventoryslot, clothing, out var reason))
{ {
hands.PutInHand(clothing); hands.PutInHand(clothing);
if (reason != null)
_serverNotifyManager.PopupMessage(Owner, Owner, reason);
} }
} }
break; break;

View File

@@ -23,7 +23,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components.Gravity namespace Content.Server.GameObjects.Components.Gravity
{ {
[RegisterComponent] [RegisterComponent]
public class GravityGeneratorComponent: SharedGravityGeneratorComponent, IAttackBy, IBreakAct, IAttackHand public class GravityGeneratorComponent: SharedGravityGeneratorComponent, IInteractUsing, IBreakAct, IInteractHand
{ {
private BoundUserInterface _userInterface; private BoundUserInterface _userInterface;
@@ -90,7 +90,7 @@ namespace Content.Server.GameObjects.Components.Gravity
serializer.DataField(ref _intact, "intact", true); serializer.DataField(ref _intact, "intact", true);
} }
bool IAttackHand.AttackHand(AttackHandEventArgs eventArgs) bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent<IActorComponent>(out var actor)) if (!eventArgs.User.TryGetComponent<IActorComponent>(out var actor))
return false; return false;
@@ -102,9 +102,9 @@ namespace Content.Server.GameObjects.Components.Gravity
return true; return true;
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.TryGetComponent(out WelderComponent tool)) if (!eventArgs.Using.TryGetComponent(out WelderComponent tool))
return false; return false;
if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Welding, 5f)) if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Welding, 5f))

View File

@@ -8,7 +8,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Weapon.Melee namespace Content.Server.GameObjects.Components.Weapon.Melee
{ {
[RegisterComponent] [RegisterComponent]
public class HealingComponent : Component, IAfterAttack, IUse public class HealingComponent : Component, IAfterInteract, IUse
{ {
public override string Name => "Healing"; public override string Name => "Healing";
@@ -23,16 +23,16 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
serializer.DataField(ref Damage, "damage", DamageType.Brute); serializer.DataField(ref Damage, "damage", DamageType.Brute);
} }
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
if (eventArgs.Attacked == null) if (eventArgs.Target == null)
{ {
return; return;
} }
if (!eventArgs.Attacked.TryGetComponent(out DamageableComponent damagecomponent)) return; if (!eventArgs.Target.TryGetComponent(out DamageableComponent damagecomponent)) return;
if (Owner.TryGetComponent(out StackComponent stackComponent)) if (Owner.TryGetComponent(out StackComponent stackComponent))
{ {
if (!stackComponent.Use(1)) if (!stackComponent.Use(1))

View File

@@ -22,7 +22,7 @@ namespace Content.Server.GameObjects.Components.Interactable
/// Component that represents a handheld lightsource which can be toggled on and off. /// Component that represents a handheld lightsource which can be toggled on and off.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IAttackBy, IMapInit internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IInteractUsing, IMapInit
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ISharedNotifyManager _notifyManager; [Dependency] private readonly ISharedNotifyManager _notifyManager;
@@ -53,15 +53,15 @@ namespace Content.Server.GameObjects.Components.Interactable
[ViewVariables] [ViewVariables]
public bool Activated { get; private set; } public bool Activated { get; private set; }
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.HasComponent<PowerCellComponent>()) return false; if (!eventArgs.Using.HasComponent<PowerCellComponent>()) return false;
if (Cell != null) return false; if (Cell != null) return false;
var handsComponent = eventArgs.User.GetComponent<IHandsComponent>(); var handsComponent = eventArgs.User.GetComponent<IHandsComponent>();
if (!handsComponent.Drop(eventArgs.AttackWith, _cellContainer)) if (!handsComponent.Drop(eventArgs.Using, _cellContainer))
{ {
return false; return false;
} }

View File

@@ -4,11 +4,14 @@ using Robust.Shared.Utility;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces;
using Content.Shared.GameObjects; using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items; using Content.Shared.GameObjects.Components.Items;
using Robust.Shared.IoC;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.GameObjects namespace Content.Server.GameObjects
{ {
@@ -17,6 +20,10 @@ namespace Content.Server.GameObjects
[ComponentReference(typeof(StoreableComponent))] [ComponentReference(typeof(StoreableComponent))]
public class ClothingComponent : ItemComponent, IUse public class ClothingComponent : ItemComponent, IUse
{ {
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _serverNotifyManager;
#pragma warning restore 649
public override string Name => "Clothing"; public override string Name => "Clothing";
public override uint? NetID => ContentNetIDs.CLOTHING; public override uint? NetID => ContentNetIDs.CLOTHING;
@@ -82,16 +89,38 @@ namespace Content.Server.GameObjects
hands.Drop(Owner); hands.Drop(Owner);
inv.Unequip(slot); inv.Unequip(slot);
hands.PutInHand(item); hands.PutInHand(item);
if (!TryEquip(inv, slot, eventArgs.User))
{
hands.Drop(item.Owner);
inv.Equip(slot, item);
hands.PutInHand(Owner.GetComponent<ItemComponent>());
}
} }
else else
{ {
hands.Drop(Owner); hands.Drop(Owner);
if (!TryEquip(inv, slot, eventArgs.User))
hands.PutInHand(Owner.GetComponent<ItemComponent>());
} }
return inv.Equip(slot, this); return true;
} }
return false; return false;
} }
private bool TryEquip(InventoryComponent inv, Slots slot, IEntity user)
{
if (!inv.Equip(slot, this, out var reason))
{
if (reason != null)
_serverNotifyManager.PopupMessage(Owner, user, reason);
return false;
}
return true;
}
} }
} }

View File

@@ -15,7 +15,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components.Items namespace Content.Server.GameObjects.Components.Items
{ {
[RegisterComponent] [RegisterComponent]
public class FloorTileItemComponent : Component, IAfterAttack public class FloorTileItemComponent : Component, IAfterInteract
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager;
@@ -39,11 +39,11 @@ namespace Content.Server.GameObjects.Components.Items
base.Initialize(); base.Initialize();
Stack = Owner.GetComponent<StackComponent>(); Stack = Owner.GetComponent<StackComponent>();
} }
public void AfterAttack(AfterAttackEventArgs eventArgs) public void AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
var attacked = eventArgs.Attacked; var attacked = eventArgs.Target;
var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GridID); var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GridID);
var tile = mapGrid.GetTileRef(eventArgs.ClickLocation); var tile = mapGrid.GetTileRef(eventArgs.ClickLocation);
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId]; var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];

View File

@@ -31,7 +31,7 @@ namespace Content.Server.GameObjects
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(StoreableComponent))] [ComponentReference(typeof(StoreableComponent))]
public class ItemComponent : StoreableComponent, IAttackHand, IExAct, IEquipped, IUnequipped public class ItemComponent : StoreableComponent, IInteractHand, IExAct, IEquipped, IUnequipped
{ {
public override string Name => "Item"; public override string Name => "Item";
public override uint? NetID => ContentNetIDs.ITEM; public override uint? NetID => ContentNetIDs.ITEM;
@@ -102,7 +102,7 @@ namespace Content.Server.GameObjects
return InteractionChecks.InRangeUnobstructed(user, itemPos, ignoredEnt: Owner, insideBlockerValid:true); return InteractionChecks.InRangeUnobstructed(user, itemPos, ignoredEnt: Owner, insideBlockerValid:true);
} }
public bool AttackHand(AttackHandEventArgs eventArgs) public bool InteractHand(InteractHandEventArgs eventArgs)
{ {
if (!CanPickup(eventArgs.User)) return false; if (!CanPickup(eventArgs.User)) return false;

View File

@@ -32,7 +32,7 @@ namespace Content.Server.GameObjects
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
[ComponentReference(typeof(IStorageComponent))] [ComponentReference(typeof(IStorageComponent))]
public class ServerStorageComponent : SharedStorageComponent, IAttackBy, IUse, IActivate, IStorageComponent, IDestroyAct public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IMapManager _mapManager;
@@ -141,9 +141,9 @@ namespace Content.Server.GameObjects
/// <param name="user"></param> /// <param name="user"></param>
/// <param name="attackwith"></param> /// <param name="attackwith"></param>
/// <returns></returns> /// <returns></returns>
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
Logger.DebugS("Storage", "Storage (UID {0}) attacked by user (UID {1}) with entity (UID {2}).", Owner.Uid, eventArgs.User.Uid, eventArgs.AttackWith.Uid); Logger.DebugS("Storage", "Storage (UID {0}) attacked by user (UID {1}) with entity (UID {2}).", Owner.Uid, eventArgs.User.Uid, eventArgs.Using.Uid);
if(Owner.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurfaceComponent)) if(Owner.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurfaceComponent))
{ {

View File

@@ -28,7 +28,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class KitchenMicrowaveComponent : SharedMicrowaveComponent, IActivate, IAttackBy, ISolutionChange public class KitchenMicrowaveComponent : SharedMicrowaveComponent, IActivate, IInteractUsing, ISolutionChange
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IEntitySystemManager _entitySystemManager; [Dependency] private readonly IEntitySystemManager _entitySystemManager;
@@ -184,7 +184,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
var itemEntity = eventArgs.User.GetComponent<HandsComponent>().GetActiveHand.Owner; var itemEntity = eventArgs.User.GetComponent<HandsComponent>().GetActiveHand.Owner;

View File

@@ -13,7 +13,7 @@ using Robust.Shared.Random;
namespace Content.Server.GameObjects.Components.Mining namespace Content.Server.GameObjects.Components.Mining
{ {
[RegisterComponent] [RegisterComponent]
public class AsteroidRockComponent : Component, IAttackBy public class AsteroidRockComponent : Component, IInteractUsing
{ {
public override string Name => "AsteroidRock"; public override string Name => "AsteroidRock";
private static readonly string[] SpriteStates = {"0", "1", "2", "3", "4"}; private static readonly string[] SpriteStates = {"0", "1", "2", "3", "4"};
@@ -29,9 +29,9 @@ namespace Content.Server.GameObjects.Components.Mining
spriteComponent.LayerSetState(0, _random.Pick(SpriteStates)); spriteComponent.LayerSetState(0, _random.Pick(SpriteStates));
} }
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
var item = eventArgs.AttackWith; var item = eventArgs.Using;
if (!item.TryGetComponent(out MeleeWeaponComponent meleeWeaponComponent)) return false; if (!item.TryGetComponent(out MeleeWeaponComponent meleeWeaponComponent)) return false;
Owner.GetComponent<DamageableComponent>().TakeDamage(DamageType.Brute, meleeWeaponComponent.Damage, item, eventArgs.User); Owner.GetComponent<DamageableComponent>().TakeDamage(DamageType.Brute, meleeWeaponComponent.Damage, item, eventArgs.User);

View File

@@ -22,7 +22,7 @@ using Timer = Robust.Shared.Timers.Timer;
namespace Content.Server.GameObjects.Components.Mobs namespace Content.Server.GameObjects.Components.Mobs
{ {
[RegisterComponent] [RegisterComponent]
public class StunnableComponent : Component, IActionBlocker, IAttackHand, IMoveSpeedModifier public class StunnableComponent : Component, IActionBlocker, IInteractHand, IMoveSpeedModifier
{ {
public override string Name => "Stunnable"; public override string Name => "Stunnable";
@@ -161,7 +161,7 @@ namespace Content.Server.GameObjects.Components.Mobs
_stunnedTimer = 0f; _stunnedTimer = 0f;
} }
public bool AttackHand(AttackHandEventArgs eventArgs) public bool InteractHand(InteractHandEventArgs eventArgs)
{ {
if (!_canHelp || !KnockedDown) if (!_canHelp || !KnockedDown)
return false; return false;

View File

@@ -23,7 +23,7 @@ namespace Content.Server.GameObjects.Components.Movement
{ {
[RegisterComponent] [RegisterComponent]
public class ServerTeleporterComponent : Component, IAfterAttack public class ServerTeleporterComponent : Component, IAfterInteract
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IMapManager _mapManager;
@@ -84,7 +84,7 @@ namespace Content.Server.GameObjects.Components.Movement
_state = newState; _state = newState;
} }
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (_teleporterType == TeleporterType.Directed) if (_teleporterType == TeleporterType.Directed)
{ {

View File

@@ -23,7 +23,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components.Nutrition namespace Content.Server.GameObjects.Components.Nutrition
{ {
[RegisterComponent] [RegisterComponent]
public class DrinkComponent : Component, IAfterAttack, IUse public class DrinkComponent : Component, IAfterInteract, IUse
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ILocalizationManager _localizationManager; [Dependency] private readonly ILocalizationManager _localizationManager;
@@ -100,11 +100,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
return true; return true;
} }
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
UseDrink(eventArgs.Attacked); UseDrink(eventArgs.Target);
} }
private void UseDrink(IEntity targetEntity) private void UseDrink(IEntity targetEntity)

View File

@@ -17,7 +17,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Nutrition namespace Content.Server.GameObjects.Components.Nutrition
{ {
[RegisterComponent] [RegisterComponent]
public class FoodComponent : Component, IAfterAttack, IUse public class FoodComponent : Component, IAfterInteract, IUse
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ILocalizationManager _localizationManager; [Dependency] private readonly ILocalizationManager _localizationManager;
@@ -110,11 +110,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
return true; return true;
} }
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
UseFood(eventArgs.Attacked); UseFood(eventArgs.Target);
} }
void UseFood(IEntity user) void UseFood(IEntity user)

View File

@@ -10,7 +10,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components.Interactable namespace Content.Server.GameObjects.Components.Interactable
{ {
[RegisterComponent] [RegisterComponent]
public class PaperComponent : SharedPaperComponent, IExamine, IAttackBy, IUse public class PaperComponent : SharedPaperComponent, IExamine, IInteractUsing, IUse
{ {
private BoundUserInterface _userInterface; private BoundUserInterface _userInterface;
@@ -63,9 +63,9 @@ namespace Content.Server.GameObjects.Components.Interactable
UpdateUserInterface(); UpdateUserInterface();
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.HasComponent<WriteComponent>()) if (!eventArgs.Using.HasComponent<WriteComponent>())
return false; return false;
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
return false; return false;

View File

@@ -6,7 +6,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components
{ {
[RegisterComponent] [RegisterComponent]
public class PlaceableSurfaceComponent : Component, IAttackBy public class PlaceableSurfaceComponent : Component, IInteractUsing
{ {
public override string Name => "PlaceableSurface"; public override string Name => "PlaceableSurface";
@@ -19,7 +19,7 @@ namespace Content.Server.GameObjects.Components
serializer.DataField(ref _isPlaceable, "IsPlaceable", true); serializer.DataField(ref _isPlaceable, "IsPlaceable", true);
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!IsPlaceable) if (!IsPlaceable)
return false; return false;
@@ -28,8 +28,8 @@ namespace Content.Server.GameObjects.Components
{ {
return false; return false;
} }
handComponent.Drop(eventArgs.AttackWith); handComponent.Drop(eventArgs.Using);
eventArgs.AttackWith.Transform.WorldPosition = eventArgs.ClickLocation.Position; eventArgs.Using.Transform.WorldPosition = eventArgs.ClickLocation.Position;
return true; return true;
} }
} }

View File

@@ -18,8 +18,8 @@ namespace Content.Server.GameObjects.Components.Power.Chargers
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
[ComponentReference(typeof(IAttackBy))] [ComponentReference(typeof(IInteractUsing))]
public sealed class PowerCellChargerComponent : BaseCharger, IActivate, IAttackBy public sealed class PowerCellChargerComponent : BaseCharger, IActivate, IInteractUsing
{ {
public override string Name => "PowerCellCharger"; public override string Name => "PowerCellCharger";
public override double CellChargePercent => _container.ContainedEntity != null ? public override double CellChargePercent => _container.ContainedEntity != null ?
@@ -37,9 +37,9 @@ namespace Content.Server.GameObjects.Components.Power.Chargers
_powerDevice.OnPowerStateChanged += PowerUpdate; _powerDevice.OnPowerStateChanged += PowerUpdate;
} }
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
var result = TryInsertItem(eventArgs.AttackWith); var result = TryInsertItem(eventArgs.Using);
if (result) if (result)
{ {
return true; return true;

View File

@@ -21,17 +21,17 @@ namespace Content.Server.GameObjects.Components.Power.Chargers
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
[ComponentReference(typeof(IAttackBy))] [ComponentReference(typeof(IInteractUsing))]
public sealed class WeaponCapacitorChargerComponent : BaseCharger, IActivate, IAttackBy public sealed class WeaponCapacitorChargerComponent : BaseCharger, IActivate, IInteractUsing
{ {
public override string Name => "WeaponCapacitorCharger"; public override string Name => "WeaponCapacitorCharger";
public override double CellChargePercent => _container.ContainedEntity != null ? public override double CellChargePercent => _container.ContainedEntity != null ?
_container.ContainedEntity.GetComponent<HitscanWeaponCapacitorComponent>().Charge / _container.ContainedEntity.GetComponent<HitscanWeaponCapacitorComponent>().Charge /
_container.ContainedEntity.GetComponent<HitscanWeaponCapacitorComponent>().Capacity * 100 : 0.0f; _container.ContainedEntity.GetComponent<HitscanWeaponCapacitorComponent>().Capacity * 100 : 0.0f;
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
var result = TryInsertItem(eventArgs.AttackWith); var result = TryInsertItem(eventArgs.Using);
if (!result) if (!result)
{ {
var localizationManager = IoCManager.Resolve<ILocalizationManager>(); var localizationManager = IoCManager.Resolve<ILocalizationManager>();

View File

@@ -10,20 +10,20 @@ using Robust.Shared.Interfaces.GameObjects.Components;
namespace Content.Server.GameObjects.Components.Power namespace Content.Server.GameObjects.Components.Power
{ {
[RegisterComponent] [RegisterComponent]
public class PowerDebugTool : SharedPowerDebugTool, IAfterAttack public class PowerDebugTool : SharedPowerDebugTool, IAfterInteract
{ {
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (eventArgs.Attacked == null) if (eventArgs.Target == null)
{ {
return; return;
} }
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.AppendFormat("Entity: {0} ({1})\n", eventArgs.Attacked.Name, eventArgs.Attacked.Uid); builder.AppendFormat("Entity: {0} ({1})\n", eventArgs.Target.Name, eventArgs.Target.Uid);
if (eventArgs.Attacked.TryGetComponent<PowerNodeComponent>(out var node)) if (eventArgs.Target.TryGetComponent<PowerNodeComponent>(out var node))
{ {
builder.AppendFormat("Power Node:\n"); builder.AppendFormat("Power Node:\n");
if (node.Parent == null) if (node.Parent == null)
@@ -51,7 +51,7 @@ namespace Content.Server.GameObjects.Components.Power
} }
} }
if (eventArgs.Attacked.TryGetComponent<PowerDeviceComponent>(out var device)) if (eventArgs.Target.TryGetComponent<PowerDeviceComponent>(out var device))
{ {
builder.AppendFormat(@"Power Device: builder.AppendFormat(@"Power Device:
Load: {0} W Load: {0} W
@@ -76,7 +76,7 @@ namespace Content.Server.GameObjects.Components.Power
} }
} }
if (eventArgs.Attacked.TryGetComponent<PowerStorageNetComponent>(out var storage)) if (eventArgs.Target.TryGetComponent<PowerStorageNetComponent>(out var storage))
{ {
var stateSeconds = (DateTime.Now - storage.LastChargeStateChange).TotalSeconds; var stateSeconds = (DateTime.Now - storage.LastChargeStateChange).TotalSeconds;
builder.AppendFormat(@"Power Storage: builder.AppendFormat(@"Power Storage:
@@ -85,7 +85,7 @@ namespace Content.Server.GameObjects.Components.Power
", storage.Capacity, storage.Charge, storage.ChargeRate, storage.DistributionRate, storage.ChargePowernet, storage.LastChargeState, storage.GetChargeState(), stateSeconds); ", storage.Capacity, storage.Charge, storage.ChargeRate, storage.DistributionRate, storage.ChargePowernet, storage.LastChargeState, storage.GetChargeState(), stateSeconds);
} }
if (eventArgs.Attacked.TryGetComponent<PowerTransferComponent>(out var transfer)) if (eventArgs.Target.TryGetComponent<PowerTransferComponent>(out var transfer))
{ {
builder.AppendFormat(@"Power Transfer: builder.AppendFormat(@"Power Transfer:
Powernet: {0} Powernet: {0}

View File

@@ -19,7 +19,7 @@ namespace Content.Server.GameObjects.Components.Power
/// Component to transfer power to nearby components, can create powernets and connect to nodes /// Component to transfer power to nearby components, can create powernets and connect to nodes
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class PowerTransferComponent : Component, IAttackBy public class PowerTransferComponent : Component, IInteractUsing
{ {
public override string Name => "PowerTransfer"; public override string Name => "PowerTransfer";
@@ -140,9 +140,9 @@ namespace Content.Server.GameObjects.Components.Power
return Parent != null && Parent.Dirty == false && !Regenerating; return Parent != null && Parent.Dirty == false && !Regenerating;
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.TryGetComponent(out ToolComponent tool)) return false; if (!eventArgs.Using.TryGetComponent(out ToolComponent tool)) return false;
if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Cutting)) return false; if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Cutting)) return false;
Owner.Delete(); Owner.Delete();

View File

@@ -20,7 +20,7 @@ namespace Content.Server.GameObjects.Components.Power
/// Component that represents a wall light. It has a light bulb that can be replaced when broken. /// Component that represents a wall light. It has a light bulb that can be replaced when broken.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class PoweredLightComponent : Component, IAttackHand, IAttackBy public class PoweredLightComponent : Component, IInteractHand, IInteractUsing
{ {
public override string Name => "PoweredLight"; public override string Name => "PoweredLight";
@@ -49,12 +49,12 @@ namespace Content.Server.GameObjects.Components.Power
} }
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
return InsertBulb(eventArgs.AttackWith); return InsertBulb(eventArgs.Using);
} }
public bool AttackHand(AttackHandEventArgs eventArgs) public bool InteractHand(InteractHandEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out DamageableComponent damageableComponent)) if (!eventArgs.User.TryGetComponent(out DamageableComponent damageableComponent))
{ {

View File

@@ -13,7 +13,7 @@ using Robust.Shared.Map;
namespace Content.Server.GameObjects.Components.Power namespace Content.Server.GameObjects.Components.Power
{ {
[RegisterComponent] [RegisterComponent]
internal class WirePlacerComponent : Component, IAfterAttack internal class WirePlacerComponent : Component, IAfterInteract
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IServerEntityManager _entityManager; [Dependency] private readonly IServerEntityManager _entityManager;
@@ -24,7 +24,7 @@ namespace Content.Server.GameObjects.Components.Power
public override string Name => "WirePlacer"; public override string Name => "WirePlacer";
/// <inheritdoc /> /// <inheritdoc />
public void AfterAttack(AfterAttackEventArgs eventArgs) public void AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;

View File

@@ -25,7 +25,7 @@ namespace Content.Server.GameObjects.Components.Research
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class LatheComponent : SharedLatheComponent, IAttackBy, IActivate public class LatheComponent : SharedLatheComponent, IInteractUsing, IActivate
{ {
public const int VolumePerSheet = 3750; public const int VolumePerSheet = 3750;
@@ -154,14 +154,14 @@ namespace Content.Server.GameObjects.Components.Research
OpenUserInterface(actor.playerSession); OpenUserInterface(actor.playerSession);
} }
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!Owner.TryGetComponent(out MaterialStorageComponent storage) if (!Owner.TryGetComponent(out MaterialStorageComponent storage)
|| !eventArgs.AttackWith.TryGetComponent(out MaterialComponent material)) return false; || !eventArgs.Using.TryGetComponent(out MaterialComponent material)) return false;
var multiplier = 1; var multiplier = 1;
if (eventArgs.AttackWith.TryGetComponent(out StackComponent stack)) multiplier = stack.Count; if (eventArgs.Using.TryGetComponent(out StackComponent stack)) multiplier = stack.Count;
var totalAmount = 0; var totalAmount = 0;
@@ -198,7 +198,7 @@ namespace Content.Server.GameObjects.Components.Research
SetAppearance(LatheVisualState.Idle); SetAppearance(LatheVisualState.Idle);
}); });
eventArgs.AttackWith.Delete(); eventArgs.Using.Delete();
return false; return false;
} }

View File

@@ -16,7 +16,7 @@ namespace Content.Server.GameObjects.Components.Stack
// TODO: Naming and presentation and such could use some improvement. // TODO: Naming and presentation and such could use some improvement.
[RegisterComponent] [RegisterComponent]
public class StackComponent : SharedStackComponent, IAttackBy, IExamine public class StackComponent : SharedStackComponent, IInteractUsing, IExamine
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ISharedNotifyManager _sharedNotifyManager; [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager;
@@ -69,9 +69,9 @@ namespace Content.Server.GameObjects.Components.Stack
return false; return false;
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (eventArgs.AttackWith.TryGetComponent<StackComponent>(out var stack)) if (eventArgs.Using.TryGetComponent<StackComponent>(out var stack))
{ {
if (!stack.StackType.Equals(StackType)) if (!stack.StackType.Equals(StackType))
{ {

View File

@@ -141,7 +141,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
for (var i = 0; i < increments; i++) for (var i = 0; i < increments; i++)
{ {
var castAngle = new Angle(baseAngle + increment * i); var castAngle = new Angle(baseAngle + increment * i);
var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), 23), _range, ignore).First(); var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), 23), _range, ignore).FirstOrDefault();
if (res.HitEntity != null) if (res.HitEntity != null)
{ {
resSet.Add(res.HitEntity); resSet.Add(res.HitEntity);

View File

@@ -25,7 +25,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
{ {
[RegisterComponent] [RegisterComponent]
public class HitscanWeaponComponent : Component, IAttackBy public class HitscanWeaponComponent : Component, IInteractUsing
{ {
private const float MaxLength = 20; private const float MaxLength = 20;
public override string Name => "HitscanWeapon"; public override string Name => "HitscanWeapon";
@@ -68,9 +68,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.TryGetComponent(out PowerStorageComponent component)) if (!eventArgs.Using.TryGetComponent(out PowerStorageComponent component))
{ {
return false; return false;
} }

View File

@@ -15,7 +15,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
{ {
[RegisterComponent] [RegisterComponent]
public class AmmoBoxComponent : Component, IAttackBy, IMapInit public class AmmoBoxComponent : Component, IInteractUsing, IMapInit
// TODO: Potential improvements: // TODO: Potential improvements:
// Add verbs for stack splitting // Add verbs for stack splitting
// Behaviour is largely the same as BallisticMagazine except you can't insert it into a gun. // Behaviour is largely the same as BallisticMagazine except you can't insert it into a gun.
@@ -145,12 +145,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
} }
} }
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
var ammoBoxTransfer = CanTransferFrom(eventArgs.AttackWith); var ammoBoxTransfer = CanTransferFrom(eventArgs.Using);
if (ammoBoxTransfer.Result) { if (ammoBoxTransfer.Result) {
IEntity bullet; IEntity bullet;
if (eventArgs.AttackWith.TryGetComponent(out BallisticMagazineComponent magazineComponent)) if (eventArgs.Using.TryGetComponent(out BallisticMagazineComponent magazineComponent))
{ {
int fillCount = Math.Min(magazineComponent.CountLoaded, Capacity - CountLeft); int fillCount = Math.Min(magazineComponent.CountLoaded, Capacity - CountLeft);
for (int i = 0; i < fillCount; i++) for (int i = 0; i < fillCount; i++)
@@ -161,7 +161,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
eventArgs.User.PopupMessage(eventArgs.User, $"Transferred {fillCount} rounds"); eventArgs.User.PopupMessage(eventArgs.User, $"Transferred {fillCount} rounds");
return true; return true;
} }
if (eventArgs.AttackWith.TryGetComponent(out AmmoBoxComponent boxComponent)) if (eventArgs.Using.TryGetComponent(out AmmoBoxComponent boxComponent))
{ {
int fillCount = Math.Min(boxComponent.CountLeft, Capacity - CountLeft); int fillCount = Math.Min(boxComponent.CountLeft, Capacity - CountLeft);
for (int i = 0; i < fillCount; i++) for (int i = 0; i < fillCount; i++)

View File

@@ -15,7 +15,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
{ {
[RegisterComponent] [RegisterComponent]
public class BallisticMagazineComponent : Component, IMapInit, IAttackBy public class BallisticMagazineComponent : Component, IMapInit, IInteractUsing
{ {
public override string Name => "BallisticMagazine"; public override string Name => "BallisticMagazine";
@@ -189,12 +189,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
} }
} }
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
var ammoMagTransfer = CanTransferFrom(eventArgs.AttackWith); var ammoMagTransfer = CanTransferFrom(eventArgs.Using);
if (ammoMagTransfer.Result) { if (ammoMagTransfer.Result) {
IEntity bullet; IEntity bullet;
if (eventArgs.AttackWith.TryGetComponent(out BallisticMagazineComponent magazineComponent)) if (eventArgs.Using.TryGetComponent(out BallisticMagazineComponent magazineComponent))
{ {
int fillCount = Math.Min(magazineComponent.CountLoaded, Capacity - CountLoaded); int fillCount = Math.Min(magazineComponent.CountLoaded, Capacity - CountLoaded);
for (int i = 0; i < fillCount; i++) for (int i = 0; i < fillCount; i++)
@@ -205,7 +205,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
eventArgs.User.PopupMessage(eventArgs.User, $"Transferred {fillCount} rounds"); eventArgs.User.PopupMessage(eventArgs.User, $"Transferred {fillCount} rounds");
return true; return true;
} }
if (eventArgs.AttackWith.TryGetComponent(out AmmoBoxComponent boxComponent)) if (eventArgs.Using.TryGetComponent(out AmmoBoxComponent boxComponent))
{ {
int fillCount = Math.Min(boxComponent.CountLeft, Capacity - CountLoaded); int fillCount = Math.Min(boxComponent.CountLeft, Capacity - CountLoaded);
for (int i = 0; i < fillCount; i++) for (int i = 0; i < fillCount; i++)

View File

@@ -26,7 +26,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
/// Guns that have a magazine. /// Guns that have a magazine.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class BallisticMagazineWeaponComponent : BallisticWeaponComponent, IUse, IAttackBy, IMapInit public class BallisticMagazineWeaponComponent : BallisticWeaponComponent, IUse, IInteractUsing, IMapInit
{ {
private const float BulletOffset = 0.2f; private const float BulletOffset = 0.2f;
@@ -210,9 +210,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
return true; return true;
} }
public bool AttackBy(AttackByEventArgs eventArgs) public bool InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.TryGetComponent(out BallisticMagazineComponent component)) if (!eventArgs.Using.TryGetComponent(out BallisticMagazineComponent component))
{ {
return false; return false;
} }
@@ -226,7 +226,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
Owner.PopupMessage(eventArgs.User, "Magazine doesn't fit."); Owner.PopupMessage(eventArgs.User, "Magazine doesn't fit.");
return false; return false;
} }
return InsertMagazine(eventArgs.AttackWith); return InsertMagazine(eventArgs.Using);
} }
private void MagazineAmmoCountChanged() private void MagazineAmmoCountChanged()

View File

@@ -12,6 +12,7 @@ using Robust.Shared.Random;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using System.Collections.Generic; using System.Collections.Generic;
using Robust.Shared.Physics;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
{ {
@@ -61,7 +62,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
projectile.Transform.GridPosition = source.Transform.GridPosition; //move projectile to entity it is being fired from projectile.Transform.GridPosition = source.Transform.GridPosition; //move projectile to entity it is being fired from
projectile.GetComponent<ProjectileComponent>().IgnoreEntity(source);//make sure it doesn't hit the source entity projectile.GetComponent<ProjectileComponent>().IgnoreEntity(source);//make sure it doesn't hit the source entity
var finalvelocity = projectile.GetComponent<ProjectileComponent>().Velocity + velocity;//add velocity var finalvelocity = projectile.GetComponent<ProjectileComponent>().Velocity + velocity;//add velocity
projectile.GetComponent<PhysicsComponent>().LinearVelocity = finalangle.ToVec() * finalvelocity;//Rotate the bullets sprite to the correct direction var physicsComponent = projectile.GetComponent<PhysicsComponent>();
physicsComponent.Status = BodyStatus.InAir;
physicsComponent.LinearVelocity = finalangle.ToVec() * finalvelocity;//Rotate the bullets sprite to the correct direction
projectile.Transform.LocalRotation = finalangle.Theta; projectile.Transform.LocalRotation = finalangle.Theta;
} }
PlayFireSound(); PlayFireSound();

View File

@@ -28,7 +28,7 @@ using Robust.Shared.Utility;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components
{ {
[RegisterComponent] [RegisterComponent]
public class WiresComponent : SharedWiresComponent, IAttackBy, IExamine public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IRobustRandom _random; [Dependency] private readonly IRobustRandom _random;
@@ -298,9 +298,9 @@ namespace Content.Server.GameObjects.Components
_userInterface.SetState(new WiresBoundUserInterfaceState(clientList, _statuses.Values.ToList())); _userInterface.SetState(new WiresBoundUserInterfaceState(clientList, _statuses.Values.ToList()));
} }
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.AttackWith.TryGetComponent<ToolComponent>(out var tool)) if (!eventArgs.Using.TryGetComponent<ToolComponent>(out var tool))
return false; return false;
if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Screwing)) if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Screwing))
return false; return false;

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Interactable;
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Mobs;
@@ -30,26 +30,26 @@ using Robust.Shared.Players;
namespace Content.Server.GameObjects.EntitySystems namespace Content.Server.GameObjects.EntitySystems
{ {
/// <summary> /// <summary>
/// This interface gives components behavior when being clicked on or "attacked" by a user with an object in their hand /// This interface gives components behavior when being clicked on by a user with an object in their hand
/// who is in range and has unobstructed reach of the target entity (allows inside blockers). /// who is in range and has unobstructed reach of the target entity (allows inside blockers).
/// </summary> /// </summary>
public interface IAttackBy public interface IInteractUsing
{ {
/// <summary> /// <summary>
/// Called when using one object on another when user is in range of the target entity. /// Called when using one object on another when user is in range of the target entity.
/// </summary> /// </summary>
bool AttackBy(AttackByEventArgs eventArgs); bool InteractUsing(InteractUsingEventArgs eventArgs);
} }
public class AttackByEventArgs : EventArgs, ITargetedAttackEventArgs public class InteractUsingEventArgs : EventArgs, ITargetedInteractEventArgs
{ {
public IEntity User { get; set; } public IEntity User { get; set; }
public GridCoordinates ClickLocation { get; set; } public GridCoordinates ClickLocation { get; set; }
public IEntity AttackWith { get; set; } public IEntity Using { get; set; }
public IEntity Attacked { get; set; } public IEntity Target { get; set; }
} }
public interface ITargetedAttackEventArgs public interface ITargetedInteractEventArgs
{ {
/// <summary> /// <summary>
/// Performer of the attack /// Performer of the attack
@@ -58,45 +58,46 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Target of the attack /// Target of the attack
/// </summary> /// </summary>
IEntity Attacked { get; } IEntity Target { get; }
} }
/// <summary> /// <summary>
/// This interface gives components behavior when being clicked on or "attacked" by a user with an empty hand /// This interface gives components behavior when being clicked on by a user with an empty hand
/// who is in range and has unobstructed reach of the target entity (allows inside blockers). /// who is in range and has unobstructed reach of the target entity (allows inside blockers).
/// </summary> /// </summary>
public interface IAttackHand public interface IInteractHand
{ {
/// <summary> /// <summary>
/// Called when a player directly interacts with an empty hand when user is in range of the target entity. /// Called when a player directly interacts with an empty hand when user is in range of the target entity.
/// </summary> /// </summary>
bool AttackHand(AttackHandEventArgs eventArgs); bool InteractHand(InteractHandEventArgs eventArgs);
} }
public class AttackHandEventArgs : EventArgs, ITargetedAttackEventArgs public class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs
{ {
public IEntity User { get; set; } public IEntity User { get; set; }
public IEntity Attacked { get; set; } public IEntity Target { get; set; }
} }
/// <summary> /// <summary>
/// This interface gives components behavior when being clicked by objects outside the range of direct use /// This interface gives components behavior when being clicked on by a user with an object
/// outside the range of direct use
/// </summary> /// </summary>
public interface IRangedAttackBy public interface IRangedInteract
{ {
/// <summary> /// <summary>
/// Called when we try to interact with an entity out of range /// Called when we try to interact with an entity out of range
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
bool RangedAttackBy(RangedAttackByEventArgs eventArgs); bool RangedInteract(RangedInteractEventArgs eventArgs);
} }
[PublicAPI] [PublicAPI]
public class RangedAttackByEventArgs : EventArgs public class RangedInteractEventArgs : EventArgs
{ {
public IEntity User { get; set; } public IEntity User { get; set; }
public IEntity Weapon { get; set; } public IEntity Using { get; set; }
public GridCoordinates ClickLocation { get; set; } public GridCoordinates ClickLocation { get; set; }
} }
@@ -104,19 +105,19 @@ namespace Content.Server.GameObjects.EntitySystems
/// This interface gives components a behavior when clicking on another object and no interaction occurs, /// This interface gives components a behavior when clicking on another object and no interaction occurs,
/// at any range. /// at any range.
/// </summary> /// </summary>
public interface IAfterAttack public interface IAfterInteract
{ {
/// <summary> /// <summary>
/// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior /// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior
/// </summary> /// </summary>
void AfterAttack(AfterAttackEventArgs eventArgs); void AfterInteract(AfterInteractEventArgs eventArgs);
} }
public class AfterAttackEventArgs : EventArgs public class AfterInteractEventArgs : EventArgs
{ {
public IEntity User { get; set; } public IEntity User { get; set; }
public GridCoordinates ClickLocation { get; set; } public GridCoordinates ClickLocation { get; set; }
public IEntity Attacked { get; set; } public IEntity Target { get; set; }
} }
/// <summary> /// <summary>
@@ -148,10 +149,10 @@ namespace Content.Server.GameObjects.EntitySystems
void Activate(ActivateEventArgs eventArgs); void Activate(ActivateEventArgs eventArgs);
} }
public class ActivateEventArgs : EventArgs, ITargetedAttackEventArgs public class ActivateEventArgs : EventArgs, ITargetedInteractEventArgs
{ {
public IEntity User { get; set; } public IEntity User { get; set; }
public IEntity Attacked { get; set; } public IEntity Target { get; set; }
} }
/// <summary> /// <summary>
@@ -384,7 +385,7 @@ namespace Content.Server.GameObjects.EntitySystems
} }
// all activates should only fire when in range / unbostructed // all activates should only fire when in range / unbostructed
var activateEventArgs = new ActivateEventArgs {User = user, Attacked = used}; var activateEventArgs = new ActivateEventArgs {User = user, Target = used};
if (InteractionChecks.InRangeUnobstructed(activateEventArgs)) if (InteractionChecks.InRangeUnobstructed(activateEventArgs))
{ {
activateComp.Activate(activateEventArgs); activateComp.Activate(activateEventArgs);
@@ -480,8 +481,14 @@ namespace Content.Server.GameObjects.EntitySystems
var item = hands.GetActiveHand?.Owner; var item = hands.GetActiveHand?.Owner;
if(ActionBlockerSystem.CanChangeDirection(player)) if (ActionBlockerSystem.CanChangeDirection(player))
playerTransform.LocalRotation = new Angle(coordinates.ToMapPos(_mapManager) - playerTransform.MapPosition.Position); {
var diff = coordinates.ToMapPos(_mapManager) - playerTransform.MapPosition.Position;
if (diff.LengthSquared > 0.01f)
{
playerTransform.LocalRotation = new Angle(diff);
}
}
if (!ActionBlockerSystem.CanInteract(player)) if (!ActionBlockerSystem.CanInteract(player))
{ {
@@ -495,8 +502,8 @@ namespace Content.Server.GameObjects.EntitySystems
{ {
if (item != null) if (item != null)
{ {
// After attack: Check if we clicked on an empty location, if so the only interaction we can do is AfterAttack // After attack: Check if we clicked on an empty location, if so the only interaction we can do is AfterInteract
InteractAfterAttack(player, item, coordinates); InteractAfter(player, item, coordinates);
} }
return; return;
@@ -521,7 +528,7 @@ namespace Content.Server.GameObjects.EntitySystems
} }
} }
// RangedAttack/AfterAttack: Check distance between user and clicked item, if too large parse it in the ranged function // RangedInteract/AfterInteract: Check distance between user and clicked item, if too large parse it in the ranged function
// TODO: have range based upon the item being used? or base it upon some variables of the player himself? // TODO: have range based upon the item being used? or base it upon some variables of the player himself?
var distance = (playerTransform.WorldPosition - attacked.Transform.WorldPosition).LengthSquared; var distance = (playerTransform.WorldPosition - attacked.Transform.WorldPosition).LengthSquared;
if (distance > InteractionRangeSquared) if (distance > InteractionRangeSquared)
@@ -532,16 +539,16 @@ namespace Content.Server.GameObjects.EntitySystems
return; return;
} }
return; // Add some form of ranged AttackHand here if you need it someday, or perhaps just ways to modify the range of AttackHand return; // Add some form of ranged InteractHand here if you need it someday, or perhaps just ways to modify the range of InteractHand
} }
// We are close to the nearby object and the object isn't contained in our active hand // We are close to the nearby object and the object isn't contained in our active hand
// AttackBy/AfterAttack: We will either use the item on the nearby object // InteractUsing/AfterInteract: We will either use the item on the nearby object
if (item != null) if (item != null)
{ {
Interaction(player, item, attacked, coordinates); Interaction(player, item, attacked, coordinates);
} }
// AttackHand/Activate: Since our hand is empty we will use AttackHand/Activate // InteractHand/Activate: Since our hand is empty we will use InteractHand/Activate
else else
{ {
Interaction(player, attacked); Interaction(player, attacked);
@@ -549,9 +556,9 @@ namespace Content.Server.GameObjects.EntitySystems
} }
/// <summary> /// <summary>
/// We didn't click on any entity, try doing an AfterAttack on the click location /// We didn't click on any entity, try doing an AfterInteract on the click location
/// </summary> /// </summary>
private void InteractAfterAttack(IEntity user, IEntity weapon, GridCoordinates clickLocation) private void InteractAfter(IEntity user, IEntity weapon, GridCoordinates clickLocation)
{ {
var message = new AfterAttackMessage(user, weapon, null, clickLocation); var message = new AfterAttackMessage(user, weapon, null, clickLocation);
RaiseLocalEvent(message); RaiseLocalEvent(message);
@@ -560,18 +567,18 @@ namespace Content.Server.GameObjects.EntitySystems
return; return;
} }
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList(); var afterInteracts = weapon.GetAllComponents<IAfterInteract>().ToList();
var afterAttackEventArgs = new AfterAttackEventArgs {User = user, ClickLocation = clickLocation}; var afterInteractEventArgs = new AfterInteractEventArgs {User = user, ClickLocation = clickLocation};
foreach (var afterAttack in afterAttacks) foreach (var afterInteract in afterInteracts)
{ {
afterAttack.AfterAttack(afterAttackEventArgs); afterInteract.AfterInteract(afterInteractEventArgs);
} }
} }
/// <summary> /// <summary>
/// Uses a weapon/object on an entity /// Uses a weapon/object on an entity
/// Finds components with the AttackBy interface and calls their function /// Finds components with the InteractUsing interface and calls their function
/// </summary> /// </summary>
public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation) public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation)
{ {
@@ -582,10 +589,10 @@ namespace Content.Server.GameObjects.EntitySystems
return; return;
} }
var attackBys = attacked.GetAllComponents<IAttackBy>().ToList(); var attackBys = attacked.GetAllComponents<IInteractUsing>().ToList();
var attackByEventArgs = new AttackByEventArgs var attackByEventArgs = new InteractUsingEventArgs
{ {
User = user, ClickLocation = clickLocation, AttackWith = weapon, Attacked = attacked User = user, ClickLocation = clickLocation, Using = weapon, Target = attacked
}; };
// all AttackBys should only happen when in range / unobstructed, so no range check is needed // all AttackBys should only happen when in range / unobstructed, so no range check is needed
@@ -593,9 +600,9 @@ namespace Content.Server.GameObjects.EntitySystems
{ {
foreach (var attackBy in attackBys) foreach (var attackBy in attackBys)
{ {
if (attackBy.AttackBy(attackByEventArgs)) if (attackBy.InteractUsing(attackByEventArgs))
{ {
// If an AttackBy returns a status completion we finish our attack // If an InteractUsing returns a status completion we finish our attack
return; return;
} }
} }
@@ -609,21 +616,21 @@ namespace Content.Server.GameObjects.EntitySystems
} }
// If we aren't directly attacking the nearby object, lets see if our item has an after attack we can do // If we aren't directly attacking the nearby object, lets see if our item has an after attack we can do
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList(); var afterAttacks = weapon.GetAllComponents<IAfterInteract>().ToList();
var afterAttackEventArgs = new AfterAttackEventArgs var afterAttackEventArgs = new AfterInteractEventArgs
{ {
User = user, ClickLocation = clickLocation, Attacked = attacked User = user, ClickLocation = clickLocation, Target = attacked
}; };
foreach (var afterAttack in afterAttacks) foreach (var afterAttack in afterAttacks)
{ {
afterAttack.AfterAttack(afterAttackEventArgs); afterAttack.AfterInteract(afterAttackEventArgs);
} }
} }
/// <summary> /// <summary>
/// Uses an empty hand on an entity /// Uses an empty hand on an entity
/// Finds components with the AttackHand interface and calls their function /// Finds components with the InteractHand interface and calls their function
/// </summary> /// </summary>
public void Interaction(IEntity user, IEntity attacked) public void Interaction(IEntity user, IEntity attacked)
{ {
@@ -634,17 +641,17 @@ namespace Content.Server.GameObjects.EntitySystems
return; return;
} }
var attackHands = attacked.GetAllComponents<IAttackHand>().ToList(); var attackHands = attacked.GetAllComponents<IInteractHand>().ToList();
var attackHandEventArgs = new AttackHandEventArgs {User = user, Attacked = attacked}; var attackHandEventArgs = new InteractHandEventArgs {User = user, Target = attacked};
// all attackHands should only fire when in range / unbostructed // all attackHands should only fire when in range / unbostructed
if (InteractionChecks.InRangeUnobstructed(attackHandEventArgs)) if (InteractionChecks.InRangeUnobstructed(attackHandEventArgs))
{ {
foreach (var attackHand in attackHands) foreach (var attackHand in attackHands)
{ {
if (attackHand.AttackHand(attackHandEventArgs)) if (attackHand.InteractHand(attackHandEventArgs))
{ {
// If an AttackHand returns a status completion we finish our attack // If an InteractHand returns a status completion we finish our attack
return; return;
} }
} }
@@ -892,18 +899,18 @@ namespace Content.Server.GameObjects.EntitySystems
if (rangedMsg.Handled) if (rangedMsg.Handled)
return; return;
var rangedAttackBys = attacked.GetAllComponents<IRangedAttackBy>().ToList(); var rangedAttackBys = attacked.GetAllComponents<IRangedInteract>().ToList();
var rangedAttackByEventArgs = new RangedAttackByEventArgs var rangedAttackByEventArgs = new RangedInteractEventArgs
{ {
User = user, Weapon = weapon, ClickLocation = clickLocation User = user, Using = weapon, ClickLocation = clickLocation
}; };
// See if we have a ranged attack interaction // See if we have a ranged attack interaction
foreach (var t in rangedAttackBys) foreach (var t in rangedAttackBys)
{ {
if (t.RangedAttackBy(rangedAttackByEventArgs)) if (t.RangedInteract(rangedAttackByEventArgs))
{ {
// If an AttackBy returns a status completion we finish our attack // If an InteractUsing returns a status completion we finish our attack
return; return;
} }
} }
@@ -913,16 +920,16 @@ namespace Content.Server.GameObjects.EntitySystems
if (afterAtkMsg.Handled) if (afterAtkMsg.Handled)
return; return;
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList(); var afterAttacks = weapon.GetAllComponents<IAfterInteract>().ToList();
var afterAttackEventArgs = new AfterAttackEventArgs var afterAttackEventArgs = new AfterInteractEventArgs
{ {
User = user, ClickLocation = clickLocation, Attacked = attacked User = user, ClickLocation = clickLocation, Target = attacked
}; };
//See if we have a ranged attack interaction //See if we have a ranged attack interaction
foreach (var afterAttack in afterAttacks) foreach (var afterAttack in afterAttacks)
{ {
afterAttack.AfterAttack(afterAttackEventArgs); afterAttack.AfterInteract(afterAttackEventArgs);
} }
} }

View File

@@ -1,11 +1,8 @@
using System; using Content.Server.GameObjects.Components;
using System.Net;
using Content.Server.GameObjects.Components;
using Content.Server.GameObjects.Components.Mobs; 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;
@@ -13,7 +10,6 @@ using Content.Shared.Physics;
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;
@@ -26,13 +22,12 @@ using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Random; using Robust.Shared.Interfaces.Random;
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.Network;
using Robust.Shared.Physics;
using Robust.Shared.Players; using Robust.Shared.Players;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
@@ -50,6 +45,7 @@ namespace Content.Server.GameObjects.EntitySystems
[Dependency] private readonly IRobustRandom _robustRandom; [Dependency] private readonly IRobustRandom _robustRandom;
[Dependency] private readonly IConfigurationManager _configurationManager; [Dependency] private readonly IConfigurationManager _configurationManager;
[Dependency] private readonly IEntityManager _entityManager; [Dependency] private readonly IEntityManager _entityManager;
[Dependency] private readonly IPhysicsManager _physicsManager;
#pragma warning restore 649 #pragma warning restore 649
private AudioSystem _audioSystem; private AudioSystem _audioSystem;
@@ -155,25 +151,12 @@ namespace Content.Server.GameObjects.EntitySystems
physics.SetController<MoverController>(); physics.SetController<MoverController>();
} }
var weightless = false; var weightless = _physicsManager.IsWeightless(transform.GridPosition);
var tile = _mapManager.GetGrid(transform.GridID).GetTileRef(transform.GridPosition).Tile; if (weightless && collider != null)
if ((!_mapManager.GetGrid(transform.GridID).HasGravity || tile.IsEmpty) && collider != null)
{ {
weightless = true;
// No gravity: is our entity touching anything? // No gravity: is our entity touching anything?
var touching = false; var touching = IsAroundCollider(transform, mover, collider);
foreach (var entity in _entityManager.GetEntitiesInRange(transform.Owner, mover.GrabRange, true))
{
if (entity.TryGetComponent<CollidableComponent>(out var otherCollider))
{
if (otherCollider.Owner == transform.Owner) continue; // Don't try to push off of yourself!
touching |= ((collider.CollisionMask & otherCollider.CollisionLayer) != 0x0
|| (otherCollider.CollisionMask & collider.CollisionLayer) != 0x0) // Ensure collision
&& !entity.HasComponent<ItemComponent>(); // This can't be an item
}
}
if (!touching) if (!touching)
{ {
@@ -238,6 +221,33 @@ namespace Content.Server.GameObjects.EntitySystems
} }
} }
private bool IsAroundCollider(ITransformComponent transform, IMoverComponent mover, CollidableComponent collider)
{
foreach (var entity in _entityManager.GetEntitiesInRange(transform.Owner, mover.GrabRange, true))
{
if (entity == transform.Owner)
{
continue; // Don't try to push off of yourself!
}
if (!entity.TryGetComponent<CollidableComponent>(out var otherCollider))
{
continue;
}
var touching = ((collider.CollisionMask & otherCollider.CollisionLayer) != 0x0
|| (otherCollider.CollisionMask & collider.CollisionLayer) != 0x0) // Ensure collision
&& !entity.HasComponent<ItemComponent>(); // This can't be an item
if (touching)
{
return true;
}
}
return false;
}
private static void HandleDirChange(ICommonSession session, Direction dir, bool state) private static void HandleDirChange(ICommonSession session, Direction dir, bool state)
{ {
var playerSes = session as IPlayerSession; var playerSes = session as IPlayerSession;

View File

@@ -17,7 +17,7 @@ namespace Content.Server.BodySystem {
/// Component representing the many BodyParts attached to each other. /// Component representing the many BodyParts attached to each other.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class BodyManagerComponent : Component, IAttackHand { public class BodyManagerComponent : Component, IInteractHand {
public sealed override string Name => "BodyManager"; public sealed override string Name => "BodyManager";
#pragma warning disable CS0649 #pragma warning disable CS0649
@@ -117,7 +117,7 @@ namespace Content.Server.BodySystem {
///////// Server-specific stuff ///////// Server-specific stuff
///////// /////////
public bool AttackHand(AttackHandEventArgs eventArgs) public bool InteractHand(InteractHandEventArgs eventArgs)
{ {
//TODO: remove organs? //TODO: remove organs?
return false; return false;

View File

@@ -28,7 +28,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
{ {
[RegisterComponent] [RegisterComponent]
public class ServerSurgeryToolComponent : SharedSurgeryToolComponent, IAfterAttack public class ServerSurgeryToolComponent : SharedSurgeryToolComponent, IAfterInteract
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IMapManager _mapManager;
@@ -41,13 +41,13 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
private BodyManagerComponent _targetCache; private BodyManagerComponent _targetCache;
private IEntity _performerCache; private IEntity _performerCache;
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
if (eventArgs.Attacked == null) if (eventArgs.Target == null)
return; return;
if (eventArgs.Attacked.TryGetComponent<BodySystem.BodyManagerComponent>(out BodySystem.BodyManagerComponent bodyManager)) if (eventArgs.Target.TryGetComponent<BodySystem.BodyManagerComponent>(out BodySystem.BodyManagerComponent bodyManager))
{ {
_surgeryOptionsCache.Clear(); _surgeryOptionsCache.Clear();
var toSend = new Dictionary<string, string>(); var toSend = new Dictionary<string, string>();

View File

@@ -25,13 +25,13 @@ namespace Content.Server.Utility
/// Validates that attacker is in range of the attacked entity. Additionally shows a popup if /// Validates that attacker is in range of the attacked entity. Additionally shows a popup if
/// validation fails. /// validation fails.
/// </summary> /// </summary>
public static bool InRangeUnobstructed(ITargetedAttackEventArgs eventArgs, bool insideBlockerValid = true) public static bool InRangeUnobstructed(ITargetedInteractEventArgs eventArgs, bool insideBlockerValid = true)
{ {
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.User.Transform.MapPosition, if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.User.Transform.MapPosition,
eventArgs.Attacked.Transform.WorldPosition, ignoredEnt: eventArgs.Attacked, insideBlockerValid: insideBlockerValid)) eventArgs.Target.Transform.WorldPosition, ignoredEnt: eventArgs.Target, insideBlockerValid: insideBlockerValid))
{ {
var localizationManager = IoCManager.Resolve<ILocalizationManager>(); var localizationManager = IoCManager.Resolve<ILocalizationManager>();
eventArgs.Attacked.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!")); eventArgs.Target.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!"));
return false; return false;
} }
@@ -45,15 +45,15 @@ namespace Content.Server.Utility
/// If there is no attacked entity, validates that they are in range of the clicked position. /// If there is no attacked entity, validates that they are in range of the clicked position.
/// Additionally shows a popup if validation fails. /// Additionally shows a popup if validation fails.
/// </summary> /// </summary>
public static bool InRangeUnobstructed(AfterAttackEventArgs eventArgs, bool insideBlockerValid = true) public static bool InRangeUnobstructed(AfterInteractEventArgs eventArgs, bool insideBlockerValid = true)
{ {
if (eventArgs.Attacked != null) if (eventArgs.Target != null)
{ {
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.User.Transform.MapPosition, if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.User.Transform.MapPosition,
eventArgs.Attacked.Transform.WorldPosition, ignoredEnt: eventArgs.Attacked, insideBlockerValid: insideBlockerValid)) eventArgs.Target.Transform.WorldPosition, ignoredEnt: eventArgs.Target, insideBlockerValid: insideBlockerValid))
{ {
var localizationManager = IoCManager.Resolve<ILocalizationManager>(); var localizationManager = IoCManager.Resolve<ILocalizationManager>();
eventArgs.Attacked.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!")); eventArgs.Target.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!"));
return false; return false;
} }
} }