コード例 #1
0
        public override void DoAttack(EntityUid user, EntityCoordinates coordinates, bool wideAttack, EntityUid?target = null)
        {
            // TODO PREDICTION move server-side interaction logic into the shared system for interaction prediction.
            if (!ValidateInteractAndFace(user, coordinates))
            {
                return;
            }

            if (!_actionBlockerSystem.CanAttack(user, target))
            {
                return;
            }

            if (!wideAttack)
            {
                // Check if interacted entity is in the same container, the direct child, or direct parent of the user.
                if (target != null && !Deleted(target.Value) && !ContainerSystem.IsInSameOrParentContainer(user, target.Value) && !CanAccessViaStorage(user, target.Value))
                {
                    Logger.WarningS("system.interaction",
                                    $"User entity {ToPrettyString(user):user} clicked on object {ToPrettyString(target.Value):target} that isn't the parent, child, or in the same container");
                    return;
                }

                // TODO: Replace with body attack range when we get something like arm length or telekinesis or something.
                var unobstructed = (target == null)
                    ? InRangeUnobstructed(user, coordinates)
                    : InRangeUnobstructed(user, target.Value);

                if (!unobstructed)
                {
                    return;
                }
            }

            // Verify user has a hand, and find what object they are currently holding in their active hand
            if (TryComp(user, out HandsComponent? hands))
            {
                var item = hands.GetActiveHandItem?.Owner;

                if (item != null && !Deleted(item.Value))
                {
                    if (wideAttack)
                    {
                        var ev = new WideAttackEvent(item.Value, user, coordinates);
                        RaiseLocalEvent(item.Value, ev, false);

                        if (ev.Handled)
                        {
                            _adminLogSystem.Add(LogType.AttackArmedWide, LogImpact.Medium, $"{ToPrettyString(user):user} wide attacked with {ToPrettyString(item.Value):used} at {coordinates}");
                            return;
                        }
                    }
                    else
                    {
                        var ev = new ClickAttackEvent(item.Value, user, coordinates, target);
                        RaiseLocalEvent(item.Value, ev, false);

                        if (ev.Handled)
                        {
                            if (target != null)
                            {
                                _adminLogSystem.Add(LogType.AttackArmedClick, LogImpact.Medium,
                                                    $"{ToPrettyString(user):user} attacked {ToPrettyString(target.Value):target} with {ToPrettyString(item.Value):used} at {coordinates}");
                            }
                            else
                            {
                                _adminLogSystem.Add(LogType.AttackArmedClick, LogImpact.Medium,
                                                    $"{ToPrettyString(user):user} attacked with {ToPrettyString(item.Value):used} at {coordinates}");
                            }

                            return;
                        }
                    }
                }
                else if (!wideAttack && target != null && HasComp <SharedItemComponent>(target.Value))
                {
                    // We pick up items if our hand is empty, even if we're in combat mode.
                    InteractHand(user, target.Value);
                    return;
                }
            }

            // TODO: Make this saner?
            // Attempt to do unarmed combat. We don't check for handled just because at this point it doesn't matter.
            if (wideAttack)
            {
                var ev = new WideAttackEvent(user, user, coordinates);
                RaiseLocalEvent(user, ev, false);
                if (ev.Handled)
                {
                    _adminLogSystem.Add(LogType.AttackUnarmedWide, $"{ToPrettyString(user):user} wide attacked at {coordinates}");
                }
            }
            else
            {
                var ev = new ClickAttackEvent(user, user, coordinates, target);
                RaiseLocalEvent(user, ev, false);
                if (ev.Handled)
                {
                    if (target != null)
                    {
                        _adminLogSystem.Add(LogType.AttackUnarmedClick, LogImpact.Medium,
                                            $"{ToPrettyString(user):user} attacked {ToPrettyString(target.Value):target} at {coordinates}");
                    }
                    else
                    {
                        _adminLogSystem.Add(LogType.AttackUnarmedClick, LogImpact.Medium,
                                            $"{ToPrettyString(user):user} attacked at {coordinates}");
                    }
                }
            }
        }
コード例 #2
0
        public void DoAttack(EntityUid user, EntityCoordinates coordinates, bool wideAttack, EntityUid targetUid = default)
        {
            if (!ValidateInteractAndFace(user, coordinates))
            {
                return;
            }

            if (!_actionBlockerSystem.CanAttack(user))
            {
                return;
            }

            if (!wideAttack)
            {
                // Check if interacted entity is in the same container, the direct child, or direct parent of the user.
                if (targetUid != default && !user.IsInSameOrParentContainer(targetUid) && !CanAccessViaStorage(user, targetUid))
                {
                    Logger.WarningS("system.interaction",
                                    $"User entity named {EntityManager.GetComponent<MetaDataComponent>(user).EntityName} clicked on object {EntityManager.GetComponent<MetaDataComponent>(targetUid).EntityName} that isn't the parent, child, or in the same container");
                    return;
                }

                // TODO: Replace with body attack range when we get something like arm length or telekinesis or something.
                if (!user.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true))
                {
                    return;
                }
            }

            // Verify user has a hand, and find what object they are currently holding in their active hand
            if (EntityManager.TryGetComponent <HandsComponent?>(user, out var hands))
            {
                if (hands.GetActiveHand?.Owner is { Valid : true } item)
                {
                    if (wideAttack)
                    {
                        var ev = new WideAttackEvent(item, user, coordinates);
                        RaiseLocalEvent(item, ev, false);

                        if (ev.Handled)
                        {
                            _adminLogSystem.Add(LogType.AttackArmedWide, LogImpact.Medium, $"{user} wide attacked with {item} at {coordinates}");
                            return;
                        }
                    }
                    else
                    {
                        var ev = new ClickAttackEvent(item, user, coordinates, targetUid);
                        RaiseLocalEvent(item, ev, false);

                        if (ev.Handled)
                        {
                            if (targetUid != default)
                            {
                                _adminLogSystem.Add(LogType.AttackArmedClick, LogImpact.Medium,
                                                    $"{user} attacked {targetUid} with {item} at {coordinates}");
                            }
                            else
                            {
                                _adminLogSystem.Add(LogType.AttackArmedClick, LogImpact.Medium,
                                                    $"{user} attacked with {item} at {coordinates}");
                            }

                            return;
                        }
                    }
                }
                else if (!wideAttack && targetUid != default && _entityManager.HasComponent <ItemComponent>(targetUid))
                {
                    // We pick up items if our hand is empty, even if we're in combat mode.
                    InteractHand(user, targetUid);
                    return;
                }
            }
コード例 #3
0
        public override void DoAttack(EntityUid user, EntityCoordinates coordinates, bool wideAttack, EntityUid?target = null)
        {
            // TODO PREDICTION move server-side interaction logic into the shared system for interaction prediction.
            if (!ValidateInteractAndFace(user, coordinates))
            {
                return;
            }

            // Check general interaction blocking.
            if (!_actionBlockerSystem.CanInteract(user, target))
            {
                return;
            }

            // Check combat-specific action blocking.
            if (!_actionBlockerSystem.CanAttack(user, target))
            {
                return;
            }

            if (!wideAttack)
            {
                // Check if interacted entity is in the same container, the direct child, or direct parent of the user.
                if (target != null && !Deleted(target.Value) && !ContainerSystem.IsInSameOrParentContainer(user, target.Value) && !CanAccessViaStorage(user, target.Value))
                {
                    Logger.WarningS("system.interaction",
                                    $"User entity {ToPrettyString(user):user} clicked on object {ToPrettyString(target.Value):target} that isn't the parent, child, or in the same container");
                    return;
                }

                // TODO: Replace with body attack range when we get something like arm length or telekinesis or something.
                var unobstructed = (target == null)
                    ? InRangeUnobstructed(user, coordinates)
                    : InRangeUnobstructed(user, target.Value);

                if (!unobstructed)
                {
                    return;
                }
            }
            else if (ContainerSystem.IsEntityInContainer(user))
            {
                // No wide attacking while in containers (holos, lockers, etc).
                // Can't think of a valid case where you would want this.
                return;
            }

            // Verify user has a hand, and find what object they are currently holding in their active hand
            if (TryComp(user, out HandsComponent? hands))
            {
                var item = hands.ActiveHandEntity;

                if (!Deleted(item))
                {
                    var meleeVee = new MeleeAttackAttemptEvent();
                    RaiseLocalEvent(item.Value, ref meleeVee, true);

                    if (meleeVee.Cancelled)
                    {
                        return;
                    }

                    if (wideAttack)
                    {
                        var ev = new WideAttackEvent(item.Value, user, coordinates);
                        RaiseLocalEvent(item.Value, ev, false);

                        if (ev.Handled)
                        {
                            _adminLogger.Add(LogType.AttackArmedWide, LogImpact.Low, $"{ToPrettyString(user):user} wide attacked with {ToPrettyString(item.Value):used} at {coordinates}");
                            return;
                        }
                    }
                    else
                    {
                        var ev = new ClickAttackEvent(item.Value, user, coordinates, target);
                        RaiseLocalEvent(item.Value, ev, false);

                        if (ev.Handled)
                        {
                            if (target != null)
                            {
                                _adminLogger.Add(LogType.AttackArmedClick, LogImpact.Low,
                                                 $"{ToPrettyString(user):user} attacked {ToPrettyString(target.Value):target} with {ToPrettyString(item.Value):used} at {coordinates}");
                            }
                            else
                            {
                                _adminLogger.Add(LogType.AttackArmedClick, LogImpact.Low,
                                                 $"{ToPrettyString(user):user} attacked with {ToPrettyString(item.Value):used} at {coordinates}");
                            }

                            return;
                        }
                    }
                }
                else if (!wideAttack && target != null && HasComp <ItemComponent>(target.Value))
                {
                    // We pick up items if our hand is empty, even if we're in combat mode.
                    InteractHand(user, target.Value);
                    return;
                }
            }

            // TODO: Make this saner?
            // Attempt to do unarmed combat. We don't check for handled just because at this point it doesn't matter.

            var used = user;

            if (_inventory.TryGetSlotEntity(user, "gloves", out var gloves) && HasComp <MeleeWeaponComponent>(gloves))
            {
                used = (EntityUid)gloves;
            }

            if (wideAttack)
            {
                var ev = new WideAttackEvent(used, user, coordinates);
                RaiseLocalEvent(used, ev, false);
                if (ev.Handled)
                {
                    _adminLogger.Add(LogType.AttackUnarmedWide, LogImpact.Low, $"{ToPrettyString(user):user} wide attacked at {coordinates}");
                }
            }
            else
            {
                var ev = new ClickAttackEvent(used, user, coordinates, target);
                RaiseLocalEvent(used, ev, false);
                if (ev.Handled)
                {
                    if (target != null)
                    {
                        _adminLogger.Add(LogType.AttackUnarmedClick, LogImpact.Low,
                                         $"{ToPrettyString(user):user} attacked {ToPrettyString(target.Value):target} at {coordinates}");
                    }
                    else
                    {
                        _adminLogger.Add(LogType.AttackUnarmedClick, LogImpact.Low,
                                         $"{ToPrettyString(user):user} attacked at {coordinates}");
                    }
                }
            }
        }
コード例 #4
0
        private void OnWideAttack(EntityUid uid, MeleeWeaponComponent comp, WideAttackEvent args)
        {
            args.Handled = true;
            var curTime = _gameTiming.CurTime;

            if (curTime < comp.CooldownEnd)
            {
                return;
            }

            var owner = EntityManager.GetEntity(uid);

            var location = args.User.Transform.Coordinates;
            var diff     = args.ClickLocation.ToMapPos(owner.EntityManager) - location.ToMapPos(owner.EntityManager);
            var angle    = Angle.FromWorldVec(diff);

            // This should really be improved. GetEntitiesInArc uses pos instead of bounding boxes.
            var entities = ArcRayCast(args.User.Transform.WorldPosition, angle, comp.ArcWidth, comp.Range, owner.Transform.MapID, args.User);

            var hitEntities = new List <IEntity>();

            foreach (var entity in entities)
            {
                if (!entity.Transform.IsMapTransform || entity == args.User)
                {
                    continue;
                }

                if (ComponentManager.HasComponent <IDamageableComponent>(entity.Uid))
                {
                    hitEntities.Add(entity);
                }
            }

            // Raise event before doing damage so we can cancel damage if handled
            var hitEvent = new MeleeHitEvent(hitEntities, args.User);

            RaiseLocalEvent(uid, hitEvent, false);
            SendAnimation(comp.Arc, angle, args.User, owner, hitEntities);

            if (!hitEvent.Handled)
            {
                if (entities.Count != 0)
                {
                    SoundSystem.Play(Filter.Pvs(owner), comp.HitSound.GetSound(), entities.First().Transform.Coordinates);
                }
                else
                {
                    SoundSystem.Play(Filter.Pvs(owner), comp.MissSound.GetSound(), args.User.Transform.Coordinates);
                }

                foreach (var entity in hitEntities)
                {
                    if (entity.TryGetComponent <IDamageableComponent>(out var damageComponent))
                    {
                        damageComponent.TryChangeDamage(comp.DamageType, comp.Damage);
                    }
                }
            }

            comp.LastAttackTime = curTime;
            comp.CooldownEnd    = comp.LastAttackTime + TimeSpan.FromSeconds(comp.ArcCooldownTime);

            RaiseLocalEvent(uid, new RefreshItemCooldownEvent(comp.LastAttackTime, comp.CooldownEnd), false);
        }
コード例 #5
0
        public void DoAttack(IEntity user, EntityCoordinates coordinates, bool wideAttack, EntityUid targetUid = default)
        {
            if (!ValidateInteractAndFace(user, coordinates))
            {
                return;
            }

            if (!Get <ActionBlockerSystem>().CanAttack(user))
            {
                return;
            }

            IEntity?targetEnt = null;

            if (!wideAttack)
            {
                // Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null
                EntityManager.TryGetEntity(targetUid, out targetEnt);

                // Check if interacted entity is in the same container, the direct child, or direct parent of the user.
                if (targetEnt != null && !user.IsInSameOrParentContainer(targetEnt))
                {
                    Logger.WarningS("system.interaction",
                                    $"User entity named {user.Name} clicked on object {targetEnt.Name} that isn't the parent, child, or in the same container");
                    return;
                }

                // TODO: Replace with body attack range when we get something like arm length or telekinesis or something.
                if (!user.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true))
                {
                    return;
                }
            }

            // Verify user has a hand, and find what object he is currently holding in his active hand
            if (user.TryGetComponent <IHandsComponent>(out var hands))
            {
                var item = hands.GetActiveHand?.Owner;

                if (item != null)
                {
                    if (wideAttack)
                    {
                        var ev = new WideAttackEvent(item, user, coordinates);
                        RaiseLocalEvent(item.Uid, ev, false);

                        if (ev.Handled)
                        {
                            return;
                        }
                    }
                    else
                    {
                        var ev = new ClickAttackEvent(item, user, coordinates, targetUid);
                        RaiseLocalEvent(item.Uid, ev, false);

                        if (ev.Handled)
                        {
                            return;
                        }
                    }
                }
                else if (!wideAttack &&
                         (targetEnt != null || EntityManager.TryGetEntity(targetUid, out targetEnt)) &&
                         targetEnt.HasComponent <ItemComponent>())
                {
                    // We pick up items if our hand is empty, even if we're in combat mode.
                    InteractHand(user, targetEnt);
                    return;
                }
            }

            // TODO: Make this saner?
            // Attempt to do unarmed combat. We don't check for handled just because at this point it doesn't matter.
            if (wideAttack)
            {
                RaiseLocalEvent(user.Uid, new WideAttackEvent(user, user, coordinates), false);
            }
            else
            {
                RaiseLocalEvent(user.Uid, new ClickAttackEvent(user, user, coordinates, targetUid), false);
            }
        }