Add pulling (#1409)

* Initial framework for pulling.

* Make it possible to pull items via (temporary) keybind Ctrl+Click, make items follow the player correctly.

* Make other objects pullable, implement functionality for moving an object being pulled, make only one object able to be pulled at a time.

* Make sure that MoveTo won't allow collisions with the player

* Update everything to work with the new physics engine

* Update Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs

Co-authored-by: ComicIronic <comicironic@gmail.com>

* Physics update and convert to direct type casts

* Add notnull checks

* Add pull keybinds to the tutorial window

* Move PullController to shared

* Fix pulled items getting left behind

* Fix moving pulled objects into walls

* Remove flooring of coordinates when moving pulled objects

* Add missing null check in PutInHand

* Change pulling keybind to control and throwing to alt

* Change PhysicsComponent references to IPhysicsComponent

* Add trying to pull a pulled entity disabling the pull

* Add pulled status effect

* Fix merge conflicts

* Merge fixes

* Make players pullable

* Fix being able to pull yourself

* Change pull moving to use a velocity

* Update pulled and pulling icons to not be buckle

A tragedy

* Make pulled and pulling icons more consistent

* Remove empty not pulled and not pulling images

* Pulled icon update

* Pulled icon update

* Add clicking pulling status effect to stop the pull

* Fix spacewalking when pulling

* Merge conflict fixes

* Add a pull verb

* Fix nullable error

* Add pulling through the entity drop down menu

Co-authored-by: Jackson Lewis <inquisitivepenguin@protonmail.com>
Co-authored-by: ComicIronic <comicironic@gmail.com>
This commit is contained in:
DrSmugleaf
2020-07-27 00:54:32 +02:00
committed by GitHub
parent b9e1f9283d
commit 0a82aba88e
26 changed files with 450 additions and 15 deletions

View File

@@ -14,6 +14,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Items
{
[RegisterComponent]
[ComponentReference(typeof(ISharedHandsComponent))]
public class HandsComponent : SharedHandsComponent
{
private HandsGui? _gui;

View File

@@ -447,7 +447,9 @@ namespace Content.Client.GameObjects.EntitySystems
}
if (args.Function == EngineKeyFunctions.Use ||
args.Function == ContentKeyFunctions.Point)
args.Function == ContentKeyFunctions.Point ||
args.Function == ContentKeyFunctions.TryPullObject ||
args.Function == ContentKeyFunctions.MovePulledObject)
{
// TODO: Remove an entity from the menu when it is deleted
if (_entity.Deleted)

View File

@@ -136,6 +136,7 @@
"TrashSpawner",
"Pill",
"RCD",
"Pullable",
};
}
}

View File

@@ -27,6 +27,8 @@ namespace Content.Client.Input
human.AddFunction(ContentKeyFunctions.OpenCharacterMenu);
human.AddFunction(ContentKeyFunctions.ActivateItemInWorld);
human.AddFunction(ContentKeyFunctions.ThrowItemInHand);
human.AddFunction(ContentKeyFunctions.TryPullObject);
human.AddFunction(ContentKeyFunctions.MovePulledObject);
human.AddFunction(ContentKeyFunctions.OpenContextMenu);
human.AddFunction(ContentKeyFunctions.OpenCraftingMenu);
human.AddFunction(ContentKeyFunctions.OpenInventoryMenu);
@@ -36,6 +38,8 @@ namespace Content.Client.Input
human.AddFunction(ContentKeyFunctions.ToggleCombatMode);
human.AddFunction(ContentKeyFunctions.WideAttack);
human.AddFunction(ContentKeyFunctions.Point);
human.AddFunction(ContentKeyFunctions.TryPullObject);
human.AddFunction(ContentKeyFunctions.MovePulledObject);
var ghost = contexts.New("ghost", "common");
ghost.AddFunction(EngineKeyFunctions.MoveUp);

View File

@@ -81,6 +81,8 @@ Use hand/object in hand: [color=#a4885c]{22}[/color]
Do wide attack: [color=#a4885c]{23}[/color]
Use targeted entity: [color=#a4885c]{11}[/color]
Throw held item: [color=#a4885c]{12}[/color]
Pull entity: [color=#a4885c]{30}[/color]
Move pulled entity: [color=#a4885c]{29}[/color]
Examine entity: [color=#a4885c]{13}[/color]
Point somewhere: [color=#a4885c]{28}[/color]
Open entity context menu: [color=#a4885c]{14}[/color]
@@ -116,7 +118,9 @@ Toggle sandbox window: [color=#a4885c]{21}[/color]",
Key(SmartEquipBelt),
Key(FocusOOC),
Key(FocusAdminChat),
Key(Point)));
Key(Point),
Key(TryPullObject),
Key(MovePulledObject)));
//Gameplay
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" });

View File

@@ -3,11 +3,15 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.Components.Movement;
using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.Shared.GameObjects.Components.Items;
using Content.Server.GameObjects.EntitySystems.Click;
using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.BodySystem;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.Physics;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Server.GameObjects.EntitySystemMessages;
@@ -27,6 +31,7 @@ namespace Content.Server.GameObjects.Components.GUI
{
[RegisterComponent]
[ComponentReference(typeof(IHandsComponent))]
[ComponentReference(typeof(ISharedHandsComponent))]
public class HandsComponent : SharedHandsComponent, IHandsComponent, IBodyPartAdded, IBodyPartRemoved
{
#pragma warning disable 649
@@ -490,6 +495,34 @@ namespace Content.Server.GameObjects.Components.GUI
return false;
}
public void StartPull(PullableComponent pullable)
{
if (Owner == pullable.Owner)
{
return;
}
if (IsPulling)
{
StopPull();
}
PulledObject = pullable.Owner.GetComponent<ICollidableComponent>();
var controller = PulledObject!.EnsureController<PullController>();
controller!.StartPull(Owner.GetComponent<ICollidableComponent>());
AddPullingStatuses();
}
public void MovePulledObject(GridCoordinates puller, GridCoordinates to)
{
if (PulledObject != null &&
PulledObject.TryGetController(out PullController controller))
{
controller.TryMoveTo(puller, to);
}
}
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession? session = null)
{
base.HandleNetworkMessage(message, channel, session);
@@ -600,6 +633,42 @@ namespace Content.Server.GameObjects.Components.GUI
}
}
private void AddPullingStatuses()
{
if (PulledObject?.Owner != null &&
PulledObject.Owner.TryGetComponent(out ServerStatusEffectsComponent pulledStatus))
{
pulledStatus.ChangeStatusEffectIcon(StatusEffect.Pulled,
"/Textures/Interface/StatusEffects/Pull/pulled.png");
}
if (Owner.TryGetComponent(out ServerStatusEffectsComponent ownerStatus))
{
ownerStatus.ChangeStatusEffectIcon(StatusEffect.Pulling,
"/Textures/Interface/StatusEffects/Pull/pulling.png");
}
}
private void RemovePullingStatuses()
{
if (PulledObject?.Owner != null &&
PulledObject.Owner.TryGetComponent(out ServerStatusEffectsComponent pulledStatus))
{
pulledStatus.RemoveStatusEffect(StatusEffect.Pulled);
}
if (Owner.TryGetComponent(out ServerStatusEffectsComponent ownerStatus))
{
ownerStatus.RemoveStatusEffect(StatusEffect.Pulling);
}
}
public override void StopPull()
{
RemovePullingStatuses();
base.StopPull();
}
void IBodyPartAdded.BodyPartAdded(BodyPartAddedEventArgs eventArgs)
{
if (eventArgs.Part.PartType != BodyPartType.Hand)

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components.Buckle;
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Shared.GameObjects;
@@ -104,6 +105,14 @@ namespace Content.Server.GameObjects.Components.Mobs
controller.RemoveController();
break;
case StatusEffect.Pulling:
if (!player.TryGetComponent(out HandsComponent hands))
{
break;
}
hands.StopPull();
break;
}
break;

View File

@@ -0,0 +1,10 @@
using Robust.Shared.GameObjects;
namespace Content.Server.GameObjects.Components.Movement
{
[RegisterComponent]
public class PullableComponent: Component
{
public override string Name => "Pullable";
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Linq;
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.Components.Movement;
using Content.Server.GameObjects.Components.Timing;
using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.Server.Utility;
@@ -9,11 +11,13 @@ using Content.Shared.GameObjects.EntitySystemMessages;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Input;
using Content.Shared.Interfaces.GameObjects.Components;
using Content.Shared.Physics;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.Interfaces.Player;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Interfaces.GameObjects;
@@ -48,6 +52,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
new PointerInputCmdHandler(HandleWideAttack))
.Bind(ContentKeyFunctions.ActivateItemInWorld,
new PointerInputCmdHandler(HandleActivateItemInWorld))
.Bind(ContentKeyFunctions.TryPullObject, new PointerInputCmdHandler(HandleTryPullObject))
.Register<InteractionSystem>();
}
@@ -221,6 +226,72 @@ namespace Content.Server.GameObjects.EntitySystems.Click
return true;
}
private bool HandleTryPullObject(ICommonSession session, GridCoordinates coords, EntityUid uid)
{
// client sanitization
if (!_mapManager.GridExists(coords.GridID))
{
Logger.InfoS("system.interaction", $"Invalid Coordinates for pulling: client={session}, coords={coords}");
return false;
}
if (uid.IsClientSide())
{
Logger.WarningS("system.interaction",
$"Client sent pull interaction with client-side entity. Session={session}, Uid={uid}");
return false;
}
var player = session.AttachedEntity;
if (player == null)
{
Logger.WarningS("system.interaction",
$"Client sent pulling interaction with no attached entity. Session={session}, Uid={uid}");
return false;
}
if (!EntityManager.TryGetEntity(uid, out var pulledObject))
{
return false;
}
if (player == pulledObject)
{
return false;
}
if (!pulledObject.TryGetComponent<PullableComponent>(out var pull))
{
return false;
}
if (!player.TryGetComponent<HandsComponent>(out var hands))
{
return false;
}
var dist = player.Transform.GridPosition.Position - pulledObject.Transform.GridPosition.Position;
if (dist.LengthSquared > InteractionRangeSquared)
{
return false;
}
var physics = pull.Owner.GetComponent<IPhysicsComponent>();
var controller = physics.EnsureController<PullController>();
if (controller.GettingPulled)
{
hands.StopPull();
}
else
{
hands.StartPull(pull);
}
return false;
}
private void UserInteraction(IEntity player, GridCoordinates coordinates, EntityUid clickedUid)
{
// Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null

View File

@@ -52,7 +52,9 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
.Bind(ContentKeyFunctions.ActivateItemInHand, InputCmdHandler.FromDelegate(HandleActivateItem))
.Bind(ContentKeyFunctions.ThrowItemInHand, new PointerInputCmdHandler(HandleThrowItem))
.Bind(ContentKeyFunctions.SmartEquipBackpack, InputCmdHandler.FromDelegate(HandleSmartEquipBackpack))
.Bind(ContentKeyFunctions.SmartEquipBelt, InputCmdHandler.FromDelegate(HandleSmartEquipBelt)).Register<HandsSystem>();
.Bind(ContentKeyFunctions.SmartEquipBelt, InputCmdHandler.FromDelegate(HandleSmartEquipBelt))
.Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(HandleMovePulledObject))
.Register<HandsSystem>();
}
/// <inheritdoc />
@@ -199,13 +201,16 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
if (plyEnt == null || !plyEnt.IsValid())
return;
if (!plyEnt.TryGetComponent(out HandsComponent handsComp) || !plyEnt.TryGetComponent(out InventoryComponent inventoryComp))
if (!plyEnt.TryGetComponent(out HandsComponent handsComp) ||
!plyEnt.TryGetComponent(out InventoryComponent inventoryComp))
return;
if (!inventoryComp.TryGetSlotItem(equipementSlot, out ItemComponent equipmentItem)
|| !equipmentItem.Owner.TryGetComponent<ServerStorageComponent>(out var storageComponent))
{
_notifyManager.PopupMessage(plyEnt, plyEnt, Loc.GetString("You have no {0} to take something out of!", EquipmentSlotDefines.SlotNames[equipementSlot].ToLower()));
_notifyManager.PopupMessage(plyEnt, plyEnt,
Loc.GetString("You have no {0} to take something out of!",
EquipmentSlotDefines.SlotNames[equipementSlot].ToLower()));
return;
}
@@ -219,7 +224,9 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
{
if (storageComponent.StoredEntities.Count == 0)
{
_notifyManager.PopupMessage(plyEnt, plyEnt, Loc.GetString("There's nothing in your {0} to take out!", EquipmentSlotDefines.SlotNames[equipementSlot].ToLower()));
_notifyManager.PopupMessage(plyEnt, plyEnt,
Loc.GetString("There's nothing in your {0} to take out!",
EquipmentSlotDefines.SlotNames[equipementSlot].ToLower()));
}
else
{
@@ -229,5 +236,20 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
}
}
}
private bool HandleMovePulledObject(ICommonSession session, GridCoordinates coords, EntityUid uid)
{
var playerEntity = session.AttachedEntity;
if (playerEntity == null ||
!playerEntity.TryGetComponent<HandsComponent>(out var hands))
{
return false;
}
hands.MovePulledObject(playerEntity.Transform.GridPosition, coords);
return false;
}
}
}

View File

@@ -0,0 +1,76 @@
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Physics;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Localization;
namespace Content.Server.GlobalVerbs
{
/// <summary>
/// Global verb that pulls an entity.
/// </summary>
[GlobalVerb]
public class PullingVerb : GlobalVerb
{
public override bool RequireInteractionRange => false;
public override void GetData(IEntity user, IEntity target, VerbData data)
{
data.Visibility = VerbVisibility.Invisible;
if (user == target ||
!user.HasComponent<IActorComponent>() ||
!target.HasComponent<PullableComponent>())
{
return;
}
var dist = user.Transform.GridPosition.Position - target.Transform.GridPosition.Position;
if (dist.LengthSquared > SharedInteractionSystem.InteractionRangeSquared)
{
return;
}
if (!user.HasComponent<ISharedHandsComponent>() ||
!user.TryGetComponent(out ICollidableComponent userCollidable) ||
!target.TryGetComponent(out ICollidableComponent targetCollidable))
{
return;
}
var controller = targetCollidable.EnsureController<PullController>();
data.Visibility = VerbVisibility.Visible;
data.Text = controller.Puller == userCollidable
? Loc.GetString("Stop pulling")
: Loc.GetString("Pull");
}
public override void Activate(IEntity user, IEntity target)
{
if (!user.TryGetComponent(out ICollidableComponent userCollidable) ||
!target.TryGetComponent(out ICollidableComponent targetCollidable) ||
!target.TryGetComponent(out PullableComponent pullable) ||
!user.TryGetComponent(out HandsComponent hands))
{
return;
}
var controller = targetCollidable.EnsureController<PullController>();
if (controller.Puller == userCollidable)
{
hands.StopPull();
}
else
{
hands.StartPull(pullable);
}
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Content.Server.GameObjects.Components;
using Content.Shared.GameObjects.Components.Items;
using Content.Shared.GameObjects.EntitySystems;
using Robust.Server.GameObjects.Components.Container;
using Robust.Server.GameObjects.EntitySystemMessages;
@@ -9,7 +10,7 @@ using Robust.Shared.Map;
namespace Content.Server.Interfaces.GameObjects.Components.Items
{
public interface IHandsComponent : IComponent
public interface IHandsComponent : ISharedHandsComponent
{
/// <summary>
/// The hand name of the currently active hand.

View File

@@ -0,0 +1,9 @@
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Shared.GameObjects.Components.Items
{
public interface ISharedHandsComponent : IComponent
{
void StopPull();
}
}

View File

@@ -1,16 +1,34 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
#nullable enable
using System;
using Content.Shared.Physics;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Shared.GameObjects.Components.Items
{
public abstract class SharedHandsComponent : Component
public abstract class SharedHandsComponent : Component, ISharedHandsComponent
{
public sealed override string Name => "Hands";
public sealed override uint? NetID => ContentNetIDs.HANDS;
[ViewVariables]
protected ICollidableComponent? PulledObject;
[ViewVariables]
protected bool IsPulling => PulledObject != null;
public virtual void StopPull()
{
if (PulledObject != null &&
PulledObject.TryGetController(out PullController controller))
{
controller.StopPull();
}
PulledObject = null;
}
}
[Serializable, NetSerializable]
@@ -35,9 +53,9 @@ namespace Content.Shared.GameObjects.Components.Items
public class HandsComponentState : ComponentState
{
public readonly SharedHand[] Hands;
public readonly string ActiveIndex;
public readonly string? ActiveIndex;
public HandsComponentState(SharedHand[] hands, string activeIndex) : base(ContentNetIDs.HANDS)
public HandsComponentState(SharedHand[] hands, string? activeIndex) : base(ContentNetIDs.HANDS)
{
Hands = hands;
ActiveIndex = activeIndex;

View File

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

View File

@@ -132,6 +132,12 @@ namespace Content.Shared.GameObjects.EntitySystems
continue;
}
// Don't count pulled entities
if (otherCollider.HasController<PullController>())
{
continue;
}
// TODO: Item check.
var touching = ((collider.CollisionMask & otherCollider.CollisionLayer) != 0x0
|| (otherCollider.CollisionMask & collider.CollisionLayer) != 0x0) // Ensure collision

View File

@@ -22,6 +22,8 @@ namespace Content.Shared.Input
public static readonly BoundKeyFunction OpenTutorial = "OpenTutorial";
public static readonly BoundKeyFunction SwapHands = "SwapHands";
public static readonly BoundKeyFunction ThrowItemInHand = "ThrowItemInHand";
public static readonly BoundKeyFunction TryPullObject = "TryPullObject";
public static readonly BoundKeyFunction MovePulledObject = "MovePulledObject";
public static readonly BoundKeyFunction ToggleCombatMode = "ToggleCombatMode";
public static readonly BoundKeyFunction MouseMiddle = "MouseMiddle";
public static readonly BoundKeyFunction OpenEntitySpawnWindow = "OpenEntitySpawnWindow";

View File

@@ -0,0 +1,114 @@
#nullable enable
using System;
using Content.Shared.GameObjects.Components.Items;
using Content.Shared.GameObjects.EntitySystems;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
namespace Content.Shared.Physics
{
public class PullController : VirtualController
{
private const float DistBeforePull = 1.0f;
private const float DistBeforeStopPull = SharedInteractionSystem.InteractionRange;
private ICollidableComponent? _puller;
public bool GettingPulled => _puller != null;
private GridCoordinates? _movingTo;
public ICollidableComponent? Puller => _puller;
public void StartPull(ICollidableComponent? pull)
{
_puller = pull;
}
public void StopPull()
{
_puller = null;
ControlledComponent?.TryRemoveController<PullController>();
}
public void TryMoveTo(GridCoordinates from, GridCoordinates to)
{
if (_puller == null || ControlledComponent == null)
{
return;
}
var mapManager = IoCManager.Resolve<IMapManager>();
if (!from.InRange(mapManager, to, SharedInteractionSystem.InteractionRange))
{
return;
}
var dist = _puller.Owner.Transform.GridPosition.Position - to.Position;
if (Math.Sqrt(dist.LengthSquared) > DistBeforeStopPull ||
Math.Sqrt(dist.LengthSquared) < 0.25f)
{
return;
}
_movingTo = to;
}
public override void UpdateBeforeProcessing()
{
if (_puller == null || ControlledComponent == null)
{
return;
}
// Are we outside of pulling range?
var dist = _puller.Owner.Transform.WorldPosition - ControlledComponent.Owner.Transform.WorldPosition;
if (dist.Length > DistBeforeStopPull)
{
_puller.Owner.GetComponent<ISharedHandsComponent>().StopPull();
}
else if (_movingTo.HasValue)
{
var diff = _movingTo.Value.Position - ControlledComponent.Owner.Transform.GridPosition.Position;
LinearVelocity = diff.Normalized * 5;
}
else if (dist.Length > DistBeforePull)
{
LinearVelocity = dist.Normalized * _puller.LinearVelocity.Length * 1.1f;
}
else
{
LinearVelocity = Vector2.Zero;
}
}
public override void UpdateAfterProcessing()
{
base.UpdateAfterProcessing();
if (ControlledComponent == null)
{
_movingTo = null;
return;
}
if (_movingTo == null)
{
return;
}
if (ControlledComponent.Owner.Transform.GridPosition.Position.EqualsApprox(_movingTo.Value.Position, 0.01))
{
_movingTo = null;
}
}
}
}

View File

@@ -49,6 +49,7 @@
state_closed: generic_door
- type: LoopingSound
- type: Anchorable
- type: Pullable
placement:
snap:
- Wall

View File

@@ -47,3 +47,4 @@
state_open: crate_open
state_closed: crate_door
- type: LoopingSound
- type: Pullable

View File

@@ -138,6 +138,7 @@
arc: fist
- type: Grammar
proper: true
- type: Pullable
- type: entity
save: false

View File

@@ -19,3 +19,4 @@
mass: 5
- type: Sprite
drawdepth: Items
- type: Pullable

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

View File

@@ -102,6 +102,15 @@ binds:
type: state
key: MouseLeft
canFocus: true
mod1: Alt
- function: TryPullObject
type: state
canFocus: true
key: MouseLeft
mod1: Control
- function: MovePulledObject
type: state
key: MouseRight
mod1: Control
- function: OpenContextMenu
type: state

View File

@@ -62,6 +62,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=placeable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=preemptively/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=prefs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pullable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Serilog/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Soundfont/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=soundfonts/@EntryIndexedValue">True</s:Boolean>