Пример #1
0
        public void SharedValidatePlacement(
            ICharacter character,
            Vector2Ushort targetPosition,
            bool logErrors,
            out bool canPlace,
            out bool isTooFar)
        {
            if (NewbieProtectionSystem.SharedIsNewbie(character))
            {
                if (logErrors)
                {
                    Logger.Warning("Newbie cannot plant bombs");
                    NewbieProtectionSystem.SharedNotifyNewbieCannotPerformAction(character, this);
                }

                canPlace = false;
                isTooFar = false;
                return;
            }

            // check if there is a direct line of sight
            // check that there are no other objects on the way between them (defined by default layer)
            var physicsSpace      = character.PhysicsBody.PhysicsSpace;
            var characterCenter   = character.Position + character.PhysicsBody.CenterOffset;
            var worldObjectCenter = targetPosition.ToVector2D() + (0.5, 0.5);

            // local method for testing if there is an obstacle from current to the specified position
            bool TestHasObstacle(Vector2D toPosition)
            {
                using var obstaclesOnTheWay = physicsSpace.TestLine(
                          characterCenter,
                          toPosition,
                          CollisionGroup.GetDefault(),
                          sendDebugEvent: false);
                foreach (var test in obstaclesOnTheWay.AsList())
                {
                    var testPhysicsBody = test.PhysicsBody;
                    if (testPhysicsBody.AssociatedProtoTile != null)
                    {
                        // obstacle tile on the way
                        return(true);
                    }

                    var testWorldObject = testPhysicsBody.AssociatedWorldObject;
                    if (testWorldObject == character)
                    {
                        // not an obstacle - it's the character or world object itself
                        continue;
                    }

                    switch (testWorldObject.ProtoWorldObject)
                    {
                    case IProtoObjectDeposit _:     // allow deposits
                    case ObjectWallDestroyed _:     // allow destroyed walls
                        continue;
                    }

                    // obstacle object on the way
                    return(true);
                }

                // no obstacles
                return(false);
            }

            // let's test by casting rays from character center to the center of the planted bomb
            if (TestHasObstacle(worldObjectCenter))
            {
                // has obstacle
                if (logErrors)
                {
                    if (IsClient)
                    {
                        this.ClientShowCannotPlaceObstaclesOnTheWayNotification();
                    }
                    else
                    {
                        Logger.Warning($"{character} cannot place {this} - obstacles on the way");
                        this.CallClient(character, _ => _.ClientRemote_CannotPlaceObstacles());
                    }
                }

                canPlace = false;
                isTooFar = false;
                return;
            }

            if (!this.ObjectExplosiveProto.CheckTileRequirements(targetPosition,
                                                                 character,
                                                                 logErrors))
            {
                // explosive static object placement requirements failed
                canPlace = false;
                isTooFar = false;
                return;
            }

            // validate distance to the character
            if (this.SharedIsTooFarToPlace(character, targetPosition, logErrors))
            {
                canPlace = true;
                isTooFar = true;
                return;
            }

            canPlace = true;
            isTooFar = false;
        }
Пример #2
0
        public void SharedValidatePlacement(
            ICharacter character,
            Vector2Ushort targetPosition,
            bool logErrors,
            out bool canPlace,
            out bool isTooFar,
            out object errorCodeOrMessage)
        {
            if (NewbieProtectionSystem.SharedIsNewbie(character))
            {
                if (logErrors)
                {
                    NewbieProtectionSystem.SharedNotifyNewbieCannotPerformAction(character, this);
                }

                canPlace           = false;
                isTooFar           = false;
                errorCodeOrMessage = null;
                return;
            }

            // check whether somebody nearby is already placing a bomb there
            var tempCharactersNearby = Api.Shared.GetTempList <ICharacter>();

            if (IsServer)
            {
                Server.World.GetScopedByPlayers(character, tempCharactersNearby);
            }
            else
            {
                Client.Characters.GetKnownPlayerCharacters(tempCharactersNearby);
            }

            foreach (var otherCharacter in tempCharactersNearby.AsList())
            {
                if (otherCharacter != character &&
                    otherCharacter.IsInitialized &&
                    PlayerCharacter.GetPublicState(otherCharacter).CurrentPublicActionState
                    is ItemExplosiveActionPublicState explosiveActionState &&
                    explosiveActionState.TargetPosition == targetPosition)
                {
                    // someone is already planting a bomb here
                    canPlace           = false;
                    isTooFar           = false;
                    errorCodeOrMessage = null;
                    return;
                }
            }

            // check if there is a direct line of sight
            // check that there are no other objects on the way between them (defined by default layer)
            var physicsSpace      = character.PhysicsBody.PhysicsSpace;
            var characterCenter   = character.Position + character.PhysicsBody.CenterOffset;
            var worldObjectCenter = targetPosition.ToVector2D() + (0.5, 0.5);

            // local method for testing if there is an obstacle from current to the specified position
            bool TestHasObstacle(Vector2D toPosition)
            {
                using var obstaclesInTheWay = physicsSpace.TestLine(
                          characterCenter,
                          toPosition,
                          CollisionGroup.Default,
                          sendDebugEvent: false);
                foreach (var test in obstaclesInTheWay.AsList())
                {
                    var testPhysicsBody = test.PhysicsBody;
                    if (testPhysicsBody.AssociatedProtoTile is not null)
                    {
                        // obstacle tile on the way
                        return(true);
                    }

                    var testWorldObject = testPhysicsBody.AssociatedWorldObject;
                    if (testWorldObject is null)
                    {
                        // some barrier on the way
                        return(true);
                    }

                    if (testWorldObject == character)
                    {
                        // not an obstacle - it's the character or world object itself
                        continue;
                    }

                    switch (testWorldObject.ProtoWorldObject)
                    {
                    case IProtoObjectDeposit:     // allow deposits
                    case ObjectWallDestroyed:     // allow destroyed walls
                        continue;
                    }

                    // obstacle object on the way
                    return(true);
                }

                // no obstacles
                return(false);
            }

            if (!this.ObjectExplosiveProto.CheckTileRequirements(targetPosition,
                                                                 character,
                                                                 out errorCodeOrMessage,
                                                                 logErrors))
            {
                // explosive static object placement requirements failed
                canPlace = false;
                isTooFar = false;
                return;
            }

            // let's check whether there are any obstacles by casting rays
            // from character's center to the center of the planted bomb
            if (TestHasObstacle(worldObjectCenter))
            {
                // has obstacle
                if (logErrors)
                {
                    if (IsClient)
                    {
                        this.ClientShowCannotPlaceObstaclesInTheWayNotification();
                    }
                    else
                    {
                        Logger.Warning($"{character} cannot place {this} - obstacles in the way");
                        this.CallClient(character, _ => _.ClientRemote_CannotPlaceObstacles());
                    }
                }

                canPlace           = false;
                isTooFar           = false;
                errorCodeOrMessage = CoreStrings.Notification_ObstaclesOnTheWay;
                return;
            }

            // validate distance to the character
            if (this.SharedIsTooFarToPlace(character, targetPosition, logErrors))
            {
                canPlace = true;
                isTooFar = true;
                return;
            }

            canPlace = true;
            isTooFar = false;
        }