void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (!InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }

            if (eventArgs.Target == null)
            {
                return;
            }

            if (!eventArgs.Target.TryGetComponent(out DamageableComponent damagecomponent))
            {
                return;
            }
            if (Owner.TryGetComponent(out StackComponent stackComponent))
            {
                if (!stackComponent.Use(1))
                {
                    Owner.Delete();
                    return;
                }

                damagecomponent.TakeHealing(Damage, Heal);
                return;
            }
            damagecomponent.TakeHealing(Damage, Heal);
            Owner.Delete();
        }
        void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (!InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }

            if (eventArgs.Target == null)
            {
                return;
            }
            if (eventArgs.Target.TryGetComponent <BodySystem.BodyManagerComponent>(out BodySystem.BodyManagerComponent bodyManager))
            {
                _surgeryOptionsCache.Clear();
                var toSend = new Dictionary <string, string>();
                foreach (var(key, value) in bodyManager.PartDictionary)
                {
                    if (value.SurgeryCheck(_surgeryToolClass))
                    {
                        _surgeryOptionsCache.Add(key, value);
                        toSend.Add(key, value.Name);
                    }
                }
                if (_surgeryOptionsCache.Count > 0)
                {
                    OpenSurgeryUI(eventArgs.User);
                    UpdateSurgeryUI(eventArgs.User, toSend);
                    _performerCache = eventArgs.User;
                    _targetCache    = bodyManager;
                }
            }
        }
        /// <summary>
        /// Called when clicking on entities while holding in active hand
        /// </summary>
        /// <param name="eventArgs"></param>
        void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (!InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }

            //Make sure we have the attacking entity
            if (eventArgs.Target == null || !_internalContents.Injector)
            {
                return;
            }

            var targetEntity = eventArgs.Target;

            //Handle injecting/drawing for solutions
            if (targetEntity.TryGetComponent <SolutionComponent>(out var targetSolution) && targetSolution.Injectable)
            {
                if (_toggleState == InjectorToggleMode.Inject)
                {
                    TryInject(targetSolution, eventArgs.User);
                }
                else if (_toggleState == InjectorToggleMode.Draw)
                {
                    TryDraw(targetSolution, eventArgs.User);
                }
            }
예제 #4
0
        private void InteractionActivate(IEntity user, IEntity used)
        {
            var activateMsg = new ActivateInWorldMessage(user, used);

            RaiseLocalEvent(activateMsg);
            if (activateMsg.Handled)
            {
                return;
            }

            if (!used.TryGetComponent(out IActivate activateComp))
            {
                return;
            }

            // all activates should only fire when in range / unbostructed
            var activateEventArgs = new ActivateEventArgs {
                User = user, Target = used
            };

            if (InteractionChecks.InRangeUnobstructed(activateEventArgs))
            {
                activateComp.Activate(activateEventArgs);
            }
        }
예제 #5
0
        /// <inheritdoc />
        public void AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (!InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }
            if (!_mapManager.TryGetGrid(eventArgs.ClickLocation.GridID, out var grid))
            {
                return;
            }
            var snapPos  = grid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center);
            var snapCell = grid.GetSnapGridCell(snapPos, SnapGridOffset.Center);

            if (grid.GetTileRef(snapPos).Tile.IsEmpty)
            {
                return;
            }
            foreach (var snapComp in snapCell)
            {
                if (snapComp.Owner.TryGetComponent <WireComponent>(out var wire) && wire.WireType == _blockingWireType)
                {
                    return;
                }
            }
            if (Owner.TryGetComponent(out StackComponent stack) && !stack.Use(1))
            {
                return;
            }
            _entityManager.SpawnEntity(_wirePrototypeID, grid.GridTileToLocal(snapPos));
        }
예제 #6
0
        public override Outcome Execute(float frameTime)
        {
            if (!ContainerHelpers.TryGetContainer(_target, out var container))
            {
                return(Outcome.Success);
            }

            if (!InteractionChecks.InRangeUnobstructed(_owner, container.Owner.Transform.MapPosition, ignoredEnt: container.Owner))
            {
                return(Outcome.Failed);
            }

            if (!container.Owner.TryGetComponent(out EntityStorageComponent? storageComponent) ||
                storageComponent.IsWeldedShut)
            {
                return(Outcome.Failed);
            }

            if (!storageComponent.Open)
            {
                var activateArgs = new ActivateEventArgs {
                    User = _owner, Target = _target
                };
                storageComponent.Activate(activateArgs);
            }

            var blackboard = UtilityAiHelpers.GetBlackboard(_owner);

            blackboard?.GetState <LastOpenedStorageState>().SetValue(container.Owner);

            return(Outcome.Success);
        }
        /// <summary>
        /// Uses an empty hand on an entity
        /// Finds components with the InteractHand interface and calls their function
        /// </summary>
        public void Interaction(IEntity user, IEntity attacked)
        {
            var message = new AttackHandMessage(user, attacked);

            RaiseLocalEvent(message);
            if (message.Handled)
            {
                return;
            }

            var attackHands         = attacked.GetAllComponents <IInteractHand>().ToList();
            var attackHandEventArgs = new InteractHandEventArgs {
                User = user, Target = attacked
            };

            // all attackHands should only fire when in range / unbostructed
            if (InteractionChecks.InRangeUnobstructed(attackHandEventArgs))
            {
                foreach (var attackHand in attackHands)
                {
                    if (attackHand.InteractHand(attackHandEventArgs))
                    {
                        // If an InteractHand returns a status completion we finish our attack
                        return;
                    }
                }
            }

            // Else we run Activate.
            InteractionActivate(user, attacked);
        }
예제 #8
0
        private bool TryStartStructureConstruction(IEntity placingEnt, GridCoordinates loc, string prototypeName, Angle angle)
        {
            var prototype = _prototypeManager.Index <ConstructionPrototype>(prototypeName);

            if (!InteractionChecks.InRangeUnobstructed(placingEnt, loc.ToMap(_mapManager),
                                                       ignoredEnt: placingEnt, insideBlockerValid: prototype.CanBuildInImpassable))
            {
                return(false);
            }

            if (prototype.Stages.Count < 2)
            {
                throw new InvalidOperationException($"Prototype '{prototypeName}' does not have enough stages.");
            }

            var stage0 = prototype.Stages[0];

            if (!(stage0.Forward is ConstructionStepMaterial matStep))
            {
                throw new NotImplementedException();
            }

            // Try to find the stack with the material in the user's hand.
            var hands      = placingEnt.GetComponent <HandsComponent>();
            var activeHand = hands.GetActiveHand?.Owner;

            if (activeHand == null)
            {
                return(false);
            }

            if (!activeHand.TryGetComponent(out StackComponent stack) || !ConstructionComponent.MaterialStackValidFor(matStep, stack))
            {
                return(false);
            }

            if (!stack.Use(matStep.Amount))
            {
                return(false);
            }

            // OK WE'RE GOOD CONSTRUCTION STARTED.
            Get <AudioSystem>().PlayAtCoords("/Audio/items/deconstruct.ogg", loc);
            if (prototype.Stages.Count == 2)
            {
                // Exactly 2 stages, so don't make an intermediate frame.
                var ent = _serverEntityManager.SpawnEntity(prototype.Result, loc);
                ent.Transform.LocalRotation = angle;
            }
            else
            {
                var frame        = _serverEntityManager.SpawnEntity("structureconstructionframe", loc);
                var construction = frame.GetComponent <ConstructionComponent>();
                construction.Init(prototype);
                frame.Transform.LocalRotation = angle;
            }

            return(true);
        }
예제 #9
0
        void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (!InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }

            UseFood(eventArgs.Target);
        }
예제 #10
0
        /// <inheritdoc />
        public void AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (!InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }

            if (!_mapManager.TryGetGrid(eventArgs.ClickLocation.GridID, out var grid))
            {
                return;
            }

            var snapPos  = grid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center);
            var snapCell = grid.GetSnapGridCell(snapPos, SnapGridOffset.Center);

            if (grid.GetTileRef(snapPos).Tile.IsEmpty)
            {
                return;
            }

            var found = false;

            foreach (var snapComp in snapCell)
            {
                if (!snapComp.Owner.HasComponent <PowerTransferComponent>())
                {
                    continue;
                }

                found = true;
                break;
            }

            if (found)
            {
                return;
            }

            bool hasItemSpriteComp = Owner.TryGetComponent(out SpriteComponent itemSpriteComp);

            if (Owner.TryGetComponent(out StackComponent stack) && !stack.Use(1))
            {
                return;
            }

            GridCoordinates coordinates = grid.GridTileToLocal(snapPos);
            var             newWire     = _entityManager.SpawnEntity("Wire", coordinates);

            if (newWire.TryGetComponent(out SpriteComponent wireSpriteComp) && hasItemSpriteComp)
            {
                wireSpriteComp.Color = itemSpriteComp.Color;
            }

            //TODO: There is no way to set this wire as above or below the floor
        }
예제 #11
0
        public bool InteractUsing(InteractUsingEventArgs eventArgs)
        {
            // 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
            if (Prototype.CanBuildInImpassable == false)
            {
                if (!InteractionChecks.InRangeUnobstructed(eventArgs, false))
                {
                    return(false);
                }
            }

            var stage = Prototype.Stages[Stage];

            if (TryProcessStep(stage.Forward, eventArgs.Using, eventArgs.User))
            {
                Stage++;
                if (Stage == Prototype.Stages.Count - 1)
                {
                    // Oh boy we get to finish construction!
                    var entMgr = IoCManager.Resolve <IServerEntityManager>();
                    var ent    = entMgr.SpawnEntity(Prototype.Result, Transform.GridPosition);
                    ent.GetComponent <ITransformComponent>().LocalRotation = Transform.LocalRotation;
                    Owner.Delete();
                    return(true);
                }

                stage = Prototype.Stages[Stage];
                if (stage.Icon != null)
                {
                    Sprite.LayerSetSprite(0, stage.Icon);
                }
            }

            else if (TryProcessStep(stage.Backward, eventArgs.Using, eventArgs.User))
            {
                Stage--;
                if (Stage == 0)
                {
                    // Deconstruction complete.
                    Owner.Delete();
                    return(true);
                }

                stage = Prototype.Stages[Stage];
                if (stage.Icon != null)
                {
                    Sprite.LayerSetSprite(0, stage.Icon);
                }
            }

            return(true);
        }
예제 #12
0
        ///<summary>
        /// Method to handle clicking on a tile to then appropriately RCD it. This can have several behaviours depending on mode.
        /// @param eventAargs = An action event telling us what tile was clicked on. We use this to exrapolate where to place the new tile / remove the old one etc.
        ///</summary>

        public void AfterInteract(AfterInteractEventArgs eventArgs)
        {
            var mapGrid     = _mapManager.GetGrid(eventArgs.ClickLocation.GridID);
            var tile        = mapGrid.GetTileRef(eventArgs.ClickLocation);
            var coordinates = mapGrid.GridTileToLocal(tile.GridIndices);

            //Less expensive checks first. Failing those ones, we need to check that the tile isn't obstructed.
            if (_ammo <= 0 || coordinates == GridCoordinates.InvalidGrid || !InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }

            var targetTile = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];

            var canPlaceTile = targetTile.IsSubFloor; //Boolean to check if we're able to build the desired tile. This defaults to checking for subfloors, but is overridden by "deconstruct" which sets it to the inverse.

            switch (this._mode)
            {
            //Floor mode just needs the tile to be a space tile (subFloor)
            case RcdMode.Floors:
                break;

            //We don't want to place a space tile on something that's already a space tile. Let's do the inverse of the last check.
            case RcdMode.Deconstruct:
                canPlaceTile = !targetTile.IsSubFloor;
                break;

            //Walls are a special behaviour, and require us to build a new object with a transform rather than setting a grid tile, thus we early return to avoid the tile set code.
            case RcdMode.Walls:
                var snapPos = mapGrid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center);
                var ent     = _serverEntityManager.SpawnEntity("solid_wall", mapGrid.GridTileToLocal(snapPos));
                ent.Transform.LocalRotation = Owner.Transform.LocalRotation;     //Now apply icon smoothing.
                _entitySystemManager.GetEntitySystem <AudioSystem>().PlayFromEntity("/Audio/Items/deconstruct.ogg", Owner);
                _ammo--;
                return;     //Alright we're done here

            default:
                return;     //I don't know why this would happen, but sure I guess. Get out of here invalid state!
            }

            ITileDefinition desiredTile = null;

            desiredTile = _tileDefinitionManager[_outputTile];
            if (canPlaceTile) //If desiredTile is null by this point, something has gone horribly wrong and you need to fix it.
            {
                mapGrid.SetTile(eventArgs.ClickLocation, new Tile(desiredTile.TileId));
                _entitySystemManager.GetEntitySystem <AudioSystem>().PlayFromEntity("/Audio/Items/deconstruct.ogg", Owner);
                _ammo--;
            }
        }
        /// <summary>
        /// Uses a weapon/object on an entity
        /// Finds components with the InteractUsing interface and calls their function
        /// </summary>
        public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation)
        {
            var attackMsg = new AttackByMessage(user, weapon, attacked, clickLocation);

            RaiseLocalEvent(attackMsg);
            if (attackMsg.Handled)
            {
                return;
            }

            var attackBys         = attacked.GetAllComponents <IInteractUsing>().ToList();
            var attackByEventArgs = new InteractUsingEventArgs
            {
                User = user, ClickLocation = clickLocation, Using = weapon, Target = attacked
            };

            // all AttackBys should only happen when in range / unobstructed, so no range check is needed
            if (InteractionChecks.InRangeUnobstructed(attackByEventArgs))
            {
                foreach (var attackBy in attackBys)
                {
                    if (attackBy.InteractUsing(attackByEventArgs))
                    {
                        // If an InteractUsing returns a status completion we finish our attack
                        return;
                    }
                }
            }

            var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation);

            RaiseLocalEvent(afterAtkMsg);
            if (afterAtkMsg.Handled)
            {
                return;
            }

            // 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 <IAfterInteract>().ToList();
            var afterAttackEventArgs = new AfterInteractEventArgs
            {
                User = user, ClickLocation = clickLocation, Target = attacked
            };

            foreach (var afterAttack in afterAttacks)
            {
                afterAttack.AfterInteract(afterAttackEventArgs);
            }
        }
        public static void FlashAreaHelper(IEntity source, float range, float duration, string sound = null)
        {
            foreach (var entity in IoCManager.Resolve<IEntityManager>().GetEntitiesInRange(source.Transform.GridPosition, range))
            {
                if (!InteractionChecks.InRangeUnobstructed(source, entity.Transform.MapPosition, range, ignoredEnt:entity))
                    continue;

                if(entity.TryGetComponent(out FlashableComponent flashable))
                    flashable.Flash(duration);
            }

            if (!string.IsNullOrEmpty(sound))
            {
                IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>().PlayAtCoords(sound, source.Transform.GridPosition);
            }
        }
예제 #15
0
        public bool TryUnbuckle(IEntity user, bool force = false)
        {
            if (BuckledTo == null)
            {
                return(false);
            }

            if (!force)
            {
                if (!ActionBlockerSystem.CanInteract(user))
                {
                    _notifyManager.PopupMessage(user, user,
                                                Loc.GetString("You can't do that!"));
                    return(false);
                }

                var strapPosition = Owner.Transform.MapPosition;
                var range         = SharedInteractionSystem.InteractionRange / 2;

                if (!InteractionChecks.InRangeUnobstructed(user, strapPosition, range))
                {
                    _notifyManager.PopupMessage(user, user,
                                                Loc.GetString("You can't reach there!"));
                    return(false);
                }
            }

            if (BuckledTo.Owner.TryGetComponent(out StrapComponent strap))
            {
                strap.Remove(this);
                _entitySystem.GetEntitySystem <AudioSystem>()
                .PlayFromEntity(strap.UnbuckleSound, Owner);
            }

            Owner.Transform.DetachParent();
            Owner.Transform.WorldRotation = BuckledTo.Owner.Transform.WorldRotation;
            BuckledTo = null;

            if (Owner.TryGetComponent(out AppearanceComponent appearance))
            {
                appearance.SetData(BuckleVisuals.Buckled, false);
            }

            if (Owner.TryGetComponent(out StunnableComponent stunnable) && stunnable.KnockedDown)
            {
                StandingStateHelper.Down(Owner);
            }
예제 #16
0
        public bool CanPickup(IEntity user)
        {
            if (!ActionBlockerSystem.CanPickup(user))
            {
                return(false);
            }

            if (user.Transform.MapID != Owner.Transform.MapID)
            {
                return(false);
            }

            var userPos = user.Transform.MapPosition;
            var itemPos = Owner.Transform.WorldPosition;

            return(InteractionChecks.InRangeUnobstructed(user, itemPos, ignoredEnt: Owner, insideBlockerValid: true));
        }
        public void AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (!InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return;
            }

            var attacked = eventArgs.Target;
            var mapGrid  = _mapManager.GetGrid(eventArgs.ClickLocation.GridID);
            var tile     = mapGrid.GetTileRef(eventArgs.ClickLocation);
            var tileDef  = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];

            if (tileDef.IsSubFloor && attacked == null && _stack.Use(1))
            {
                var desiredTile = _tileDefinitionManager[_outputTile];
                mapGrid.SetTile(eventArgs.ClickLocation, new Tile(desiredTile.TileId));
                EntitySystem.Get <AudioSystem>().PlayAtCoords("/Audio/Items/genhit.ogg", eventArgs.ClickLocation);
            }
        }
        // TODO: When I spawn new entities they seem to duplicate clothing or something?
        public override Outcome Execute(float frameTime)
        {
            if (_target == null ||
                _target.Deleted ||
                !_target.HasComponent <ItemComponent>() ||
                ContainerHelpers.IsInContainer(_target) ||
                !InteractionChecks.InRangeUnobstructed(_owner, _target.Transform.MapPosition))
            {
                return(Outcome.Failed);
            }

            if (!_owner.TryGetComponent(out HandsComponent handsComponent))
            {
                return(Outcome.Failed);
            }

            var emptyHands = false;

            foreach (var hand in handsComponent.ActivePriorityEnumerable())
            {
                if (handsComponent.GetItem(hand) == null)
                {
                    if (handsComponent.ActiveHand != hand)
                    {
                        handsComponent.ActiveHand = hand;
                    }

                    emptyHands = true;
                    break;
                }
            }

            if (!emptyHands)
            {
                return(Outcome.Failed);
            }

            var interactionSystem = IoCManager.Resolve <IEntitySystemManager>().GetEntitySystem <InteractionSystem>();

            interactionSystem.Interaction(_owner, _target);
            return(Outcome.Success);
        }
        private void HandleDragDropMessage(DragDropMessage msg, EntitySessionEventArgs args)
        {
            var performer = args.SenderSession.AttachedEntity;

            if (!EntityManager.TryGetEntity(msg.Dropped, out var dropped))
            {
                return;
            }
            if (!EntityManager.TryGetEntity(msg.Target, out var target))
            {
                return;
            }

            var interactionArgs = new DragDropEventArgs(performer, msg.DropLocation, dropped, target);

            // must be in range of both the target and the object they are drag / dropping
            if (!InteractionChecks.InRangeUnobstructed(interactionArgs))
            {
                return;
            }

            // trigger dragdrops on the dropped entity
            foreach (var dragDrop in dropped.GetAllComponents <IDragDrop>())
            {
                if (dragDrop.CanDragDrop(interactionArgs) &&
                    dragDrop.DragDrop(interactionArgs))
                {
                    return;
                }
            }

            // trigger dragdropons on the targeted entity
            foreach (var dragDropOn in target.GetAllComponents <IDragDropOn>())
            {
                if (dragDropOn.CanDragDropOn(interactionArgs) &&
                    dragDropOn.DragDropOn(interactionArgs))
                {
                    return;
                }
            }
        }
예제 #20
0
        public override bool TryUseFood(IEntity user, IEntity target, UtensilComponent utensilUsed = null)
        {
            if (user == null)
            {
                return(false);
            }

            var trueTarget = target ?? user;

            if (!trueTarget.TryGetComponent(out StomachComponent stomach))
            {
                return(false);
            }

            if (!InteractionChecks.InRangeUnobstructed(user, trueTarget.Transform.MapPosition))
            {
                return(false);
            }

            var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume);
            var split          = _contents.SplitSolution(transferAmount);

            if (!stomach.TryTransferSolution(split))
            {
                _contents.TryAddSolution(split);
                trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!"));
                return(false);
            }

            if (_useSound != null)
            {
                _entitySystem.GetEntitySystem <AudioSystem>()
                .PlayFromEntity(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f));
            }

            trueTarget.PopupMessage(user, Loc.GetString("You swallow the pill."));

            Owner.Delete();
            return(true);
        }
        public bool CanPickup(IEntity user)
        {
            if (!ActionBlockerSystem.CanPickup(user))
            {
                return(false);
            }

            if (user.Transform.MapID != Owner.Transform.MapID)
            {
                return(false);
            }

            if (Owner.TryGetComponent(out ICollidableComponent physics) &&
                physics.Anchored)
            {
                return(false);
            }

            var itemPos = Owner.Transform.MapPosition;

            return(InteractionChecks.InRangeUnobstructed(user, itemPos, ignoredEnt: Owner, ignoreInsideBlocker: true));
        }
예제 #22
0
        public override Outcome Execute(float frameTime)
        {
            if (!InteractionChecks.InRangeUnobstructed(_owner, _target.Transform.MapPosition))
            {
                return(Outcome.Failed);
            }

            if (!_target.TryGetComponent(out EntityStorageComponent storageComponent) ||
                storageComponent.IsWeldedShut)
            {
                return(Outcome.Failed);
            }

            if (storageComponent.Open)
            {
                var activateArgs = new ActivateEventArgs {
                    User = _owner, Target = _target
                };
                storageComponent.Activate(activateArgs);
            }

            return(Outcome.Success);
        }
        public override Outcome Execute(float frameTime)
        {
            if (_useTarget.Transform.GridID != _owner.Transform.GridID)
            {
                return(Outcome.Failed);
            }

            if (!InteractionChecks.InRangeUnobstructed(_owner, _useTarget.Transform.MapPosition))
            {
                return(Outcome.Failed);
            }

            if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
            {
                combatModeComponent.IsInCombatMode = false;
            }

            // Click on da thing
            var interactionSystem = IoCManager.Resolve <IEntitySystemManager>().GetEntitySystem <InteractionSystem>();

            interactionSystem.UseItemInHand(_owner, _useTarget.Transform.GridPosition, _useTarget.Uid);

            return(Outcome.Success);
        }
예제 #24
0
        public virtual bool TryUseFood(IEntity user, IEntity target, UtensilComponent utensilUsed = null)
        {
            if (user == null)
            {
                return(false);
            }

            if (UsesRemaining <= 0)
            {
                user.PopupMessage(user, Loc.GetString("{0:TheName} is empty!", Owner));
                return(false);
            }

            var trueTarget = target ?? user;

            if (!trueTarget.TryGetComponent(out StomachComponent stomach))
            {
                return(false);
            }

            var utensils = utensilUsed != null
                ? new List <UtensilComponent> {
                utensilUsed
            }
                : null;

            if (_utensilsNeeded != UtensilType.None)
            {
                utensils = new List <UtensilComponent>();
                var types = UtensilType.None;

                if (user.TryGetComponent(out HandsComponent hands))
                {
                    foreach (var item in hands.GetAllHeldItems())
                    {
                        if (!item.Owner.TryGetComponent(out UtensilComponent utensil))
                        {
                            continue;
                        }

                        utensils.Add(utensil);
                        types |= utensil.Types;
                    }
                }

                if (!types.HasFlag(_utensilsNeeded))
                {
                    trueTarget.PopupMessage(user, Loc.GetString("You need to be holding a {0} to eat that!", _utensilsNeeded));
                    return(false);
                }
            }

            if (!InteractionChecks.InRangeUnobstructed(user, trueTarget.Transform.MapPosition))
            {
                return(false);
            }

            var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume);
            var split          = _contents.SplitSolution(transferAmount);

            if (!stomach.TryTransferSolution(split))
            {
                _contents.TryAddSolution(split);
                trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!"));
                return(false);
            }

            _entitySystem.GetEntitySystem <AudioSystem>()
            .PlayFromEntity(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f));
            trueTarget.PopupMessage(user, Loc.GetString("Nom"));

            // If utensils were used
            if (utensils != null)
            {
                foreach (var utensil in utensils)
                {
                    utensil.TryBreak(user);
                }
            }

            if (UsesRemaining > 0)
            {
                return(true);
            }

            if (string.IsNullOrEmpty(_trashPrototype))
            {
                Owner.Delete();
                return(true);
            }

            //We're empty. Become trash.
            var position = Owner.Transform.GridPosition;
            var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position);

            // If the user is holding the item
            if (user.TryGetComponent(out HandsComponent handsComponent) &&
                handsComponent.IsHolding(Owner))
            {
                Owner.Delete();

                // Put the trash in the user's hand
                if (finisher.TryGetComponent(out ItemComponent item) &&
                    handsComponent.CanPutInHand(item))
                {
                    handsComponent.PutInHand(item);
                }
            }
        public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession?session = null)
        {
            base.HandleNetworkMessage(message, channel, session);

            if (session == null)
            {
                throw new ArgumentException(nameof(session));
            }

            switch (message)
            {
            case RemoveEntityMessage remove:
            {
                EnsureInitialCalculated();

                var player = session.AttachedEntity;

                if (player == null)
                {
                    break;
                }

                var ownerTransform  = Owner.Transform;
                var playerTransform = player.Transform;

                if (!playerTransform.GridPosition.InRange(_mapManager, ownerTransform.GridPosition, 2) ||
                    !ownerTransform.IsMapTransform &&
                    !playerTransform.ContainsEntity(ownerTransform))
                {
                    break;
                }

                var entity = _entityManager.GetEntity(remove.EntityUid);

                if (entity == null || _storage?.Contains(entity) == false)
                {
                    break;
                }

                var item = entity.GetComponent <ItemComponent>();
                if (item == null ||
                    !player.TryGetComponent(out HandsComponent hands))
                {
                    break;
                }

                if (!hands.CanPutInHand(item))
                {
                    break;
                }

                hands.PutInHand(item);

                break;
            }

            case InsertEntityMessage _:
            {
                EnsureInitialCalculated();

                var player = session.AttachedEntity;

                if (player == null)
                {
                    break;
                }

                var storagePosition = Owner.Transform.MapPosition;

                if (!InteractionChecks.InRangeUnobstructed(player, storagePosition))
                {
                    break;
                }

                PlayerInsertEntity(player);

                break;
            }

            case CloseStorageUIMessage _:
            {
                if (!(session is IPlayerSession playerSession))
                {
                    break;
                }

                UnsubscribeSession(playerSession);
                break;
            }
            }
        }
예제 #26
0
        private bool IsRCDStillValid(AfterInteractEventArgs eventArgs, IMapGrid mapGrid, TileRef tile, MapIndices snapPos, RcdMode startingMode)
        {
            //Less expensive checks first. Failing those ones, we need to check that the tile isn't obstructed.
            if (_ammo <= 0)
            {
                _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"The RCD is out of ammo!");
                return(false);
            }

            if (_mode != startingMode)
            {
                return(false);
            }

            var coordinates = mapGrid.GridTileToLocal(tile.GridIndices);

            if (coordinates == GridCoordinates.InvalidGrid || !InteractionChecks.InRangeUnobstructed(eventArgs))
            {
                return(false);
            }

            switch (_mode)
            {
            //Floor mode just needs the tile to be a space tile (subFloor)
            case RcdMode.Floors:
                if (!tile.Tile.IsEmpty)
                {
                    _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"You can only build a floor on space!");
                    return(false);
                }

                return(true);

            //We don't want to place a space tile on something that's already a space tile. Let's do the inverse of the last check.
            case RcdMode.Deconstruct:
                if (tile.Tile.IsEmpty)
                {
                    return(false);
                }

                //They tried to decon a turf but the turf is blocked
                if (eventArgs.Target == null && tile.IsBlockedTurf(true))
                {
                    _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"That tile is obstructed!");
                    return(false);
                }
                //They tried to decon a non-turf but it's not in the whitelist
                if (eventArgs.Target != null && !eventArgs.Target.TryGetComponent(out RCDDeconstructWhitelist rcd_decon))
                {
                    _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"You can't deconstruct that!");
                    return(false);
                }

                return(true);

            //Walls are a special behaviour, and require us to build a new object with a transform rather than setting a grid tile, thus we early return to avoid the tile set code.
            case RcdMode.Walls:
                if (tile.Tile.IsEmpty)
                {
                    _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"Cannot build a wall on space!");
                    return(false);
                }

                if (tile.IsBlockedTurf(true))
                {
                    _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"That tile is obstructed!");
                    return(false);
                }
                return(true);

            case RcdMode.Airlock:
                if (tile.Tile.IsEmpty)
                {
                    _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"Cannot build an airlock on space!");
                    return(false);
                }
                if (tile.IsBlockedTurf(true))
                {
                    _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"That tile is obstructed!");
                    return(false);
                }
                return(true);

            default:
                return(false);    //I don't know why this would happen, but sure I guess. Get out of here invalid state!
            }
        }
예제 #27
0
        private bool TryBuckle(IEntity user, IEntity to)
        {
            if (user == null || user == to)
            {
                return(false);
            }

            if (!ActionBlockerSystem.CanInteract(user))
            {
                _notifyManager.PopupMessage(user, user,
                                            Loc.GetString("You can't do that!"));
                return(false);
            }

            var strapPosition = Owner.Transform.MapPosition;
            var range         = SharedInteractionSystem.InteractionRange / 2;

            if (!InteractionChecks.InRangeUnobstructed(user, strapPosition, range))
            {
                _notifyManager.PopupMessage(user, user,
                                            Loc.GetString("You can't reach there!"));
                return(false);
            }

            if (!user.TryGetComponent(out HandsComponent hands))
            {
                _notifyManager.PopupMessage(user, user,
                                            Loc.GetString("You don't have hands!"));
                return(false);
            }

            if (hands.GetActiveHand != null)
            {
                _notifyManager.PopupMessage(user, user,
                                            Loc.GetString("Your hand isn't free!"));
                return(false);
            }

            if (BuckledTo != null)
            {
                _notifyManager.PopupMessage(Owner, user,
                                            Loc.GetString(Owner == user
                        ? "You are already buckled in!"
                        : "{0:They} are already buckled in!", Owner));
                return(false);
            }

            if (!to.TryGetComponent(out StrapComponent strap))
            {
                _notifyManager.PopupMessage(Owner, user,
                                            Loc.GetString(Owner == user
                        ? "You can't buckle yourself there!"
                        : "You can't buckle {0:them} there!", Owner));
                return(false);
            }

            var parent = to.Transform.Parent;

            while (parent != null)
            {
                if (parent == user.Transform)
                {
                    _notifyManager.PopupMessage(Owner, user,
                                                Loc.GetString(Owner == user
                            ? "You can't buckle yourself there!"
                            : "You can't buckle {0:them} there!", Owner));
                    return(false);
                }

                parent = parent.Parent;
            }

            if (!strap.HasSpace(this))
            {
                _notifyManager.PopupMessage(Owner, user,
                                            Loc.GetString(Owner == user
                        ? "You can't fit there!"
                        : "{0:They} can't fit there!", Owner));
                return(false);
            }

            _entitySystem.GetEntitySystem <AudioSystem>()
            .PlayFromEntity(strap.BuckleSound, Owner);

            if (!strap.TryAdd(this))
            {
                _notifyManager.PopupMessage(Owner, user,
                                            Loc.GetString(Owner == user
                        ? "You can't buckle yourself there!"
                        : "You can't buckle {0:them} there!", Owner));
                return(false);
            }

            BuckledTo = strap;

            if (Owner.TryGetComponent(out AppearanceComponent appearance))
            {
                appearance.SetData(BuckleVisuals.Buckled, true);
            }

            var ownTransform   = Owner.Transform;
            var strapTransform = strap.Owner.Transform;

            ownTransform.GridPosition = strapTransform.GridPosition;
            ownTransform.AttachParent(strapTransform);

            switch (strap.Position)
            {
            case StrapPosition.None:
                ownTransform.WorldRotation = strapTransform.WorldRotation;
                break;

            case StrapPosition.Stand:
                StandingStateHelper.Standing(Owner);
                ownTransform.WorldRotation = strapTransform.WorldRotation;
                break;

            case StrapPosition.Down:
                StandingStateHelper.Down(Owner);
                ownTransform.WorldRotation = Angle.South;
                break;
            }

            BuckleStatus();

            return(true);
        }