diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 654f3912dd..21da2fdd73 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -18,6 +18,8 @@ namespace Content.Client.Input human.AddFunction(ContentKeyFunctions.OpenCharacterMenu); human.AddFunction(ContentKeyFunctions.ExamineEntity); human.AddFunction(ContentKeyFunctions.UseItemInHand); + human.AddFunction(ContentKeyFunctions.ActivateItemInWorld); + human.AddFunction(ContentKeyFunctions.ThrowItemInHand); } } } diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 554fd8bd2f..f35b0d5009 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -28,9 +28,10 @@ using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Materials; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.Components.Construction; -using Content.Server.Players; -using Content.Server.Mobs; using Content.Server.GameObjects.Components.Mobs; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Mobs; +using Content.Server.Players; namespace Content.Server { @@ -101,6 +102,7 @@ namespace Content.Server factory.Register(); factory.Register(); + factory.RegisterReference(); factory.Register(); factory.Register(); diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 6ff4ac25cf..ef43a7f7e0 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -240,7 +240,7 @@ namespace Content.Server.GameObjects var activehand = hands.GetActiveHand; if (activehand != null && activehand.Owner.TryGetComponent(out ClothingComponent clothing)) { - hands.Drop(hands.ActiveIndex); + hands.Drop(hands.ActiveIndex, null); if (!Equip(msg.Inventoryslot, clothing)) { hands.PutInHand(clothing); diff --git a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs index a848b7f170..0f9130d333 100644 --- a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs @@ -13,6 +13,7 @@ using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Interfaces.GameObjects.Components; using SS14.Shared.Interfaces.Network; using SS14.Shared.IoC; +using SS14.Shared.Map; using SS14.Shared.Serialization; namespace Content.Server.GameObjects @@ -141,8 +142,9 @@ namespace Content.Server.GameObjects /// Drops the item in a slot. /// /// The slot to drop the item from. + /// /// True if an item was dropped, false otherwise. - public bool Drop(string slot) + public bool Drop(string slot, GridLocalCoordinates? coords) { if (!CanDrop(slot)) { @@ -160,7 +162,9 @@ namespace Content.Server.GameObjects // TODO: The item should be dropped to the container our owner is in, if any. var itemTransform = item.Owner.GetComponent(); - itemTransform.LocalPosition = Owner.GetComponent().LocalPosition; + + itemTransform.LocalPosition = coords ?? Owner.GetComponent().LocalPosition; + Dirty(); return true; } diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs index 079630b481..36d7ac8bd3 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs @@ -20,7 +20,7 @@ namespace Content.Server.GameObjects /// /// Storage component for containing entities within this one, matches a UI on the client which shows stored entities /// - public class ServerStorageComponent : SharedStorageComponent, IAttackby, IUse + public class ServerStorageComponent : SharedStorageComponent, IAttackby, IUse, IActivate { private Container storage; @@ -102,7 +102,7 @@ namespace Content.Server.GameObjects Logger.DebugS("Storage", "Storage (UID {0}) attacked by user (UID {1}) with entity (UID {2}).", Owner.Uid, user.Uid, attackwith.Uid); var hands = user.GetComponent(); //Check that we can drop the item from our hands first otherwise we obviously cant put it inside - if (hands.Drop(hands.ActiveIndex)) + if (hands.Drop(hands.ActiveIndex, null)) { var inserted = Insert(attackwith); if (inserted) @@ -240,5 +240,11 @@ namespace Content.Server.GameObjects break; } } + + /// + void IActivate.Activate(IEntity user) + { + ((IUse) this).UseEntity(user); + } } } diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index 4980c49df2..afd9d2006d 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -89,6 +89,18 @@ namespace Content.Server.GameObjects.EntitySystems bool UseEntity(IEntity user); } + /// + /// This interface gives components behavior when being activated in the world. + /// + public interface IActivate + { + /// + /// Called when this component is activated by another entity. + /// + /// Entity that activated this component. + void Activate(IEntity user); + } + /// /// Governs interactions during clicking on entities /// @@ -101,6 +113,26 @@ namespace Content.Server.GameObjects.EntitySystems { var inputSys = EntitySystemManager.GetEntitySystem(); inputSys.BindMap.BindFunction(ContentKeyFunctions.UseItemInHand, new PointerInputCmdHandler(HandleUseItemInHand)); + inputSys.BindMap.BindFunction(ContentKeyFunctions.ActivateItemInWorld, new PointerInputCmdHandler((HandleUseItemInWorld))); + } + + private void HandleUseItemInWorld(ICommonSession session, GridLocalCoordinates coords, EntityUid uid) + { + if(!EntityManager.TryGetEntity(uid, out var used)) + return; + + if(!used.TryGetComponent(out IActivate activateComp)) + return; + + var playerEnt = ((IPlayerSession) session).AttachedEntity; + + if(playerEnt == null || !playerEnt.IsValid()) + return; + + if (!playerEnt.Transform.LocalPosition.InRange(used.Transform.LocalPosition, INTERACTION_RANGE)) + return; + + activateComp.Activate(playerEnt); } private void HandleUseItemInHand(ICommonSession session, GridLocalCoordinates coords, EntityUid uid) @@ -112,7 +144,7 @@ namespace Content.Server.GameObjects.EntitySystems { //Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null if (!EntityManager.TryGetEntity(clickedUid, out var attacked)) - return; + attacked = null; //Verify player has a transform component if (!player.TryGetComponent(out var playerTransform)) diff --git a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs index cf8f94a723..429606aea6 100644 --- a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs @@ -1,15 +1,24 @@ -using Content.Shared.Input; +using System; +using Content.Server.GameObjects.Components.Projectiles; +using Content.Shared.Input; +using SS14.Server.GameObjects; using SS14.Server.GameObjects.EntitySystems; using SS14.Server.Interfaces.Player; using SS14.Shared.GameObjects; +using SS14.Shared.GameObjects.EntitySystemMessages; using SS14.Shared.GameObjects.Systems; using SS14.Shared.Input; +using SS14.Shared.Interfaces.GameObjects.Components; +using SS14.Shared.Map; +using SS14.Shared.Maths; using SS14.Shared.Players; namespace Content.Server.GameObjects.EntitySystems { internal class HandsSystem : EntitySystem { + private const float ThrowSpeed = 1.0f; + /// public override void Initialize() { @@ -17,10 +26,11 @@ namespace Content.Server.GameObjects.EntitySystems var input = EntitySystemManager.GetEntitySystem(); input.BindMap.BindFunction(ContentKeyFunctions.SwapHands, InputCmdHandler.FromDelegate(HandleSwapHands)); - input.BindMap.BindFunction(ContentKeyFunctions.Drop, InputCmdHandler.FromDelegate(HandleDrop)); + input.BindMap.BindFunction(ContentKeyFunctions.Drop, new PointerInputCmdHandler(HandleDrop)); input.BindMap.BindFunction(ContentKeyFunctions.ActivateItemInHand, InputCmdHandler.FromDelegate(HandleActivateItem)); + input.BindMap.BindFunction(ContentKeyFunctions.ThrowItemInHand, new PointerInputCmdHandler(HandleThrowItem)); } - + /// public override void Shutdown() { @@ -29,11 +39,36 @@ namespace Content.Server.GameObjects.EntitySystems input.BindMap.UnbindFunction(ContentKeyFunctions.SwapHands); input.BindMap.UnbindFunction(ContentKeyFunctions.Drop); input.BindMap.UnbindFunction(ContentKeyFunctions.ActivateItemInHand); + input.BindMap.UnbindFunction(ContentKeyFunctions.ThrowItemInHand); } base.Shutdown(); } + /// + public override void SubscribeEvents() + { + SubscribeEvent(HandleParented); + } + + private static void HandleParented(object sender, EntitySystemMessage args) + { + var msg = (EntParentChangedMessage) args; + + if (!msg.Entity.TryGetComponent(out ITransformComponent transform)) + return; + + // if item is in a container + if(transform.IsMapTransform) + return; + + if(!msg.Entity.TryGetComponent(out PhysicsComponent physics)) + return; + + // set velocity to zero + physics.LinearVelocity = Vector2.Zero; + } + private static bool TryGetAttachedComponent(IPlayerSession session, out T component) where T : Component { @@ -59,12 +94,25 @@ namespace Content.Server.GameObjects.EntitySystems handsComp.SwapHands(); } - private static void HandleDrop(ICommonSession session) + private static void HandleDrop(ICommonSession session, GridLocalCoordinates coords, EntityUid uid) { - if (!TryGetAttachedComponent(session as IPlayerSession, out HandsComponent handsComp)) + var ent = ((IPlayerSession) session).AttachedEntity; + + if(ent == null || !ent.IsValid()) return; - handsComp.Drop(handsComp.ActiveIndex); + if (!ent.TryGetComponent(out HandsComponent handsComp)) + return; + + var transform = ent.Transform; + + GridLocalCoordinates? dropPos = null; + if (transform.LocalPosition.InRange(coords, InteractionSystem.INTERACTION_RANGE)) + { + dropPos = coords; + } + + handsComp.Drop(handsComp.ActiveIndex, dropPos); } private static void HandleActivateItem(ICommonSession session) @@ -74,5 +122,53 @@ namespace Content.Server.GameObjects.EntitySystems handsComp.ActivateItem(); } + + private static void HandleThrowItem(ICommonSession session, GridLocalCoordinates coords, EntityUid uid) + { + var plyEnt = ((IPlayerSession)session).AttachedEntity; + + if (plyEnt == null || !plyEnt.IsValid()) + return; + + if (!plyEnt.TryGetComponent(out HandsComponent handsComp)) + return; + + if (handsComp.CanDrop(handsComp.ActiveIndex)) + { + var throwEnt = handsComp.GetHand(handsComp.ActiveIndex).Owner; + handsComp.Drop(handsComp.ActiveIndex, null); + + if (!throwEnt.TryGetComponent(out ProjectileComponent projComp)) + { + projComp = throwEnt.AddComponent(); + } + + projComp.IgnoreEntity(plyEnt); + + var transform = plyEnt.Transform; + var dirVec = (coords.ToWorld().Position - transform.WorldPosition).Normalized; + + if (!throwEnt.TryGetComponent(out PhysicsComponent physComp)) + { + physComp = throwEnt.AddComponent(); + } + + physComp.LinearVelocity = dirVec * ThrowSpeed; + + + var wHomoDir = Vector3.UnitX; + + transform.InvWorldMatrix.Transform(ref wHomoDir, out var lHomoDir); + + lHomoDir.Normalize(); + var angle = new Angle(lHomoDir.Xy); + + transform.LocalRotation = angle; + } + else + { + return; + } + } } } diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index d984536d1e..7f91514119 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -1,6 +1,7 @@ using Content.Server.GameObjects; using SS14.Shared.Interfaces.GameObjects; using System.Collections.Generic; +using SS14.Shared.Map; namespace Content.Server.Interfaces.GameObjects { @@ -65,8 +66,9 @@ namespace Content.Server.Interfaces.GameObjects /// Drops an item on the ground, removing it from the hand. /// /// The hand to drop from. + /// /// True if an item was successfully dropped, false otherwise. - bool Drop(string index); + bool Drop(string index, GridLocalCoordinates? coords); /// /// Checks whether the item in the specified hand can be dropped. diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index 73140d87a5..0e3f6b5bf4 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -10,6 +10,8 @@ namespace Content.Shared.Input public static readonly BoundKeyFunction ActivateItemInHand = "ActivateItemInHand"; public static readonly BoundKeyFunction OpenCharacterMenu = "OpenCharacterMenu"; public static readonly BoundKeyFunction ExamineEntity = "ExamineEntity"; - public static readonly BoundKeyFunction UseItemInHand = "UseItemInHand"; + public static readonly BoundKeyFunction UseItemInHand = "UseItemInHand"; // use hand item on world entity + public static readonly BoundKeyFunction ActivateItemInWorld = "ActivateItemInWorld"; // default action on world entity + public static readonly BoundKeyFunction ThrowItemInHand = "ThrowItemInHand"; } } diff --git a/Resources/keybinds_content.yml b/Resources/keybinds_content.yml index 273803e48e..a787e2cbc3 100644 --- a/Resources/keybinds_content.yml +++ b/Resources/keybinds_content.yml @@ -19,3 +19,10 @@ binds: - function: UseItemInHand key: MouseLeft type: state +- function: ActivateItemInWorld + key: E + type: state +- function: ThrowItemInHand + key: MouseLeft + mod1: Control + type: state diff --git a/engine b/engine index 22fdca62bb..71121f8fef 160000 --- a/engine +++ b/engine @@ -1 +1 @@ -Subproject commit 22fdca62bb1a7ea01318d2ecf64514f0f8fe5531 +Subproject commit 71121f8fefe8f3f99b170b4fbf26f75ac30e9aa3