public static bool SharedIsTargetAlreadyScheduledForAnyActiveDrone(
            ICharacter character,
            Vector2Ushort worldPosition,
            bool logError)
        {
            foreach (var objectDrone in character.SharedGetCurrentlyControlledDrones())
            {
                var droneTargetPosition = objectDrone.GetPublicState <DronePublicState>()
                                          .TargetObjectPosition;
                if (droneTargetPosition != worldPosition)
                {
                    continue;
                }

                // the drone is already sent there
                if (logError)
                {
                    if (IsServer)
                    {
                        Logger.Info("Drone already sent there: " + worldPosition, character);
                    }
                    else
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(ClientCurrentCharacterHelper.Character,
                                                                            Notification_DroneAlreadySent,
                                                                            isOutOfRange: false);
                    }
                }

                return(true);
            }

            return(false);
        }
        public static bool ClientTryStartDrone(
            IItem itemDrone,
            Vector2Ushort worldPosition,
            bool showErrorNotification)
        {
            var character = ClientCurrentCharacterHelper.Character;

            if (SharedIsMaxDronesToControlNumberExceeded(character,
                                                         showErrorNotification) ||
                SharedIsTargetAlreadyScheduledForAnyActiveDrone(character,
                                                                worldPosition,
                                                                showErrorNotification))
            {
                return(false);
            }

            var targetObject = SharedGetCompatibleTarget(character,
                                                         worldPosition,
                                                         out var hasIncompatibleTarget,
                                                         out var isPveActionForbidden);

            if (targetObject is null)
            {
                // nothing to mine there
                if (showErrorNotification)
                {
                    if (isPveActionForbidden)
                    {
                        PveSystem.ClientShowNotificationActionForbidden();
                    }

                    CannotInteractMessageDisplay.ClientOnCannotInteract(
                        character,
                        hasIncompatibleTarget
                            ? Notification_CannotMineThat
                            : Notification_NothingToMineThere,
                        isOutOfRange: false);
                }

                return(false);
            }

            if (!SharedIsValidStartLocation(character, worldPosition, out var hasObstacles))
            {
                if (showErrorNotification)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(
                        character,
                        hasObstacles
                            ? CoreStrings.Notification_ObstaclesOnTheWay
                            : CoreStrings.Notification_TooFar,
                        isOutOfRange: true);
                }

                return(false);
            }

            ClientDroneStartQueue.Add(itemDrone, worldPosition);
            return(true);
        }
Пример #3
0
        public override void SharedUpdate(double deltaTime)
        {
            // don't invoke the base SharedUpdate implementation as we don't advance the timer here
            if (!ReferenceEquals(this.ItemFishingRod, this.CharacterPublicState.SelectedItem))
            {
                // player changed the selected item
                this.SetCompleted(isCancelled: true);
                this.AbortAction();
                return;
            }

            if (FishingSystem.SharedIsTooFar(this.Character, this.FishingTargetPosition))
            {
                if (Api.IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(this.Character,
                                                                        CoreStrings.Notification_TooFar,
                                                                        isOutOfRange: true);
                }

                this.Cancel();
                return;
            }

            if (this.SharedFishingSession != null &&
                this.SharedFishingSession.IsDestroyed)
            {
                this.Complete();
            }
        }
Пример #4
0
 public static void ClientOnCannotInteract(
     IWorldObject worldObject,
     string message,
     bool isOutOfRange = false)
 {
     CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                         message,
                                                         isOutOfRange);
 }
Пример #5
0
        public static void ClientOnCannotInteractNotOwner(IWorldObject worldObject, bool isFactionAccess)
        {
            var message = isFactionAccess
                              ? WorldObjectAccessModeSystem.NotificationDontHaveAccess
                              : DialogCannotSetOwners_MessageNotOwner;

            CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                                message,
                                                                isOutOfRange: false);
        }
Пример #6
0
 public static void ClientOnCannotInteractNotOwner(IWorldObject worldObject)
 {
     CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                         DialogCannotSetOwners_MessageNotOwner,
                                                         isOutOfRange: false);
 }
Пример #7
0
        public static bool SharedCheckCanInteract(
            ICharacter character,
            IDynamicWorldObject vehicle,
            bool writeToLog)
        {
            if (vehicle is null ||
                vehicle.IsDestroyed)
            {
                return(false);
            }

            // it's possible to repair any vehicle within a certain distance to the character
            var canInteract = character.Position.DistanceSquaredTo(vehicle.Position)
                              <= MaxDistanceForRepairAction * MaxDistanceForRepairAction;

            if (!canInteract)
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Character cannot interact with {vehicle} for repair - too far",
                        character);

                    if (IsClient)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(vehicle,
                                                                            CoreStrings.Notification_TooFar,
                                                                            isOutOfRange: true);
                    }
                }

                return(false);
            }

            var physicsSpace    = character.PhysicsBody.PhysicsSpace;
            var characterCenter = character.Position + character.PhysicsBody.CenterOffset;

            if (ObstacleTestHelper.SharedHasObstaclesInTheWay(characterCenter,
                                                              physicsSpace,
                                                              vehicle,
                                                              sendDebugEvents: writeToLog))
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Character cannot interact with {vehicle} for repair - obstacles in the way",
                        character);

                    if (IsClient)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(vehicle,
                                                                            CoreStrings.Notification_ObstaclesOnTheWay,
                                                                            isOutOfRange: true);
                    }
                }

                return(false);
            }

            using var tempCharactersNearby = Api.Shared.GetTempList <ICharacter>();
            if (IsClient)
            {
                Client.Characters.GetKnownPlayerCharacters(tempCharactersNearby);
            }
            else
            {
                Server.World.GetScopedByPlayers(vehicle, tempCharactersNearby);
            }

            foreach (var otherPlayerCharacter in tempCharactersNearby.AsList())
            {
                if (ReferenceEquals(character, otherPlayerCharacter))
                {
                    continue;
                }

                if (PlayerCharacter.GetPublicState(otherPlayerCharacter).CurrentPublicActionState
                    is VehicleRepairActionState.PublicState repairActionState &&
                    ReferenceEquals(repairActionState.TargetWorldObject, vehicle))
                {
                    // already repairing by another player
                    if (!writeToLog)
                    {
                        return(false);
                    }

                    Logger.Important($"Cannot start repairing {vehicle} - already repairing by another player",
                                     character);
                    if (IsClient)
                    {
                        NotificationSystem.ClientShowNotification(
                            CoreStrings.Notification_ErrorCannotInteract,
                            CoreStrings.Notification_ErrorObjectUsedByAnotherPlayer,
                            NotificationColor.Bad,
                            icon: ((IProtoVehicle)vehicle.ProtoGameObject).Icon);
                    }

                    return(false);
                }
            }

            return(true);
        }
        protected override bool ClientItemUseFinish(ClientItemData data)
        {
            var character             = ClientCurrentCharacterHelper.Character;
            var characterTilePosition = character.TilePosition;
            var mouseTilePosition     = Client.Input.MousePointedTilePosition;
            var dronesNumberToLaunch  = Api.Client.Input.IsKeyHeld(InputKey.Shift, evenIfHandled: true)
                                           ? this.MaxDronesToControl
                                           : 1;

            using var tempExceptDrones  = Api.Shared.GetTempList <IItem>();
            using var tempExceptTargets = Api.Shared.GetTempList <Vector2Ushort>();

            for (var index = 0; index < dronesNumberToLaunch; index++)
            {
                var showErrorNotification = index == 0;
                var itemDrone             = CharacterDroneControlSystem.ClientSelectNextDrone(tempExceptDrones.AsList());
                if (itemDrone is null)
                {
                    if (CharacterDroneControlSystem.SharedIsMaxDronesToControlNumberExceeded(
                            character,
                            clientShowErrorNotification: showErrorNotification))
                    {
                        break;
                    }

                    if (showErrorNotification)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(
                            character,
                            CharacterDroneControlSystem.Notification_ErrorNoDrones_Title,
                            isOutOfRange: false);
                    }

                    break;
                }

                tempExceptDrones.Add(itemDrone);
                Vector2Ushort targetPosition;

                if (index == 0)
                {
                    targetPosition = mouseTilePosition;
                    var targetObject = CharacterDroneControlSystem
                                       .SharedGetCompatibleTarget(character,
                                                                  mouseTilePosition,
                                                                  out var hasIncompatibleTarget,
                                                                  out var isPveActionForbidden);
                    if (targetObject is null)
                    {
                        if (showErrorNotification)
                        {
                            if (isPveActionForbidden)
                            {
                                PveSystem.ClientShowNotificationActionForbidden();
                            }

                            CannotInteractMessageDisplay.ClientOnCannotInteract(
                                character,
                                hasIncompatibleTarget
                                    ? CharacterDroneControlSystem.Notification_CannotMineThat
                                    : CharacterDroneControlSystem.Notification_NothingToMineThere,
                                isOutOfRange: false);
                        }

                        return(false);
                    }

                    if (!WorldObjectClaimSystem.SharedIsAllowInteraction(character,
                                                                         targetObject,
                                                                         showClientNotification: showErrorNotification))
                    {
                        return(false);
                    }

                    if (CharacterDroneControlSystem.SharedIsTargetAlreadyScheduledForAnyActiveDrone(
                            character,
                            mouseTilePosition,
                            logError: false))
                    {
                        // already scheduled a drone mining there...try find another target of the same type
                        targetPosition = TryGetNextTargetPosition();
                        if (targetPosition == default)
                        {
                            // no further targets
                            CannotInteractMessageDisplay.ClientOnCannotInteract(
                                character,
                                CharacterDroneControlSystem.Notification_DroneAlreadySent,
                                isOutOfRange: false);
                            return(false);
                        }
                    }
                }
                else
                {
                    targetPosition = TryGetNextTargetPosition();
                    if (targetPosition == default)
                    {
                        // no further targets
                        break;
                    }
                }

                if (!CharacterDroneControlSystem.ClientTryStartDrone(itemDrone,
                                                                     targetPosition,
                                                                     showErrorNotification: showErrorNotification))
                {
                    break;
                }

                tempExceptTargets.Add(targetPosition);
            }

            // always return false as we don't want to play any device sounds
            return(false);

            Vector2Ushort TryGetNextTargetPosition()
            {
                var targetObjectProto = CharacterDroneControlSystem
                                        .SharedGetCompatibleTarget(character,
                                                                   mouseTilePosition,
                                                                   out _,
                                                                   out _)?
                                        .ProtoWorldObject;

                if (targetObjectProto is null)
                {
                    return(default);
Пример #9
0
        public static void ClientStartRelocation(IStaticWorldObject objectStructure)
        {
            var protoStructure = objectStructure.ProtoStaticWorldObject;
            var character      = Client.Characters.CurrentPlayerCharacter;

            if (IsInObjectPlacementMode ||
                ConstructionPlacementSystem.IsInObjectPlacementMode)
            {
                // already relocating/placing something
                return;
            }

            if (!SharedIsRelocatable(objectStructure))
            {
                return;
            }

            if (!CreativeModeSystem.SharedIsInCreativeMode(character) &&
                !LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition,
                                                   character,
                                                   requireFactionPermission: true,
                                                   out var hasNoFactionPermission,
                                                   out _))
            {
                // the building location or destination is in an area that is not owned by the player
                SharedShowCannotRelocateNotification(
                    character,
                    protoStructure,
                    hasNoFactionPermission);
                return;
            }

            var isPvEorWithinInteractionArea = PveSystem.SharedIsPve(false) ||
                                               protoStructure.SharedIsInsideCharacterInteractionArea(
                Api.Client.Characters.CurrentPlayerCharacter,
                objectStructure,
                writeToLog: false);

            if (!isPvEorWithinInteractionArea)
            {
                CannotInteractMessageDisplay.ClientOnCannotInteract(
                    character,
                    CoreStrings.Notification_TooFar,
                    isOutOfRange: true);
                return;
            }

            if (LandClaimSystem.SharedIsUnderRaidBlock(character, objectStructure))
            {
                // the building is in an area under the raid
                ConstructionSystem.SharedShowCannotBuildNotification(
                    character,
                    LandClaimSystem.ErrorRaidBlockActionRestricted_Message,
                    protoStructure);
                return;
            }

            if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure))
            {
                // the building is in an area under shield protection
                LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection(
                    character);
                return;
            }

            ClientDisableConstructionRelocation();

            var sceneObject = Client.Scene.CreateSceneObject("StructureRelocationHelper");

            componentObjectPlacementHelper = sceneObject.AddComponent <ClientComponentObjectPlacementHelper>();
            componentRelocationHelper      = sceneObject.AddComponent <ClientComponentObjectRelocationHelper>();

            componentObjectPlacementHelper
            .Setup(protoStructure,
                   isCancelable: true,
                   isRepeatCallbackIfHeld: false,
                   isDrawConstructionGrid: true,
                   isBlockingInput: true,
                   validateCanPlaceCallback: ClientValidateCanRelocate,
                   placeSelectedCallback: ClientConstructionPlaceSelectedCallback,
                   delayRemainsSeconds: 0.1);
            componentObjectPlacementHelper.HideBlueprintOnOverlapWithTheSameObject = false;

            componentRelocationHelper.Setup(objectStructure);

            void ClientValidateCanRelocate(
                Vector2Ushort tilePosition,
                bool logErrors,
                out string errorMessage,
                out bool canPlace,
                out bool isTooFar)
            {
                if (tilePosition == objectStructure.TilePosition)
                {
                    canPlace     = true;
                    isTooFar     = false;
                    errorMessage = null;
                    return;
                }

                if (!SharedCheckTileRequirementsForRelocation(character,
                                                              objectStructure,
                                                              tilePosition,
                                                              out errorMessage,
                                                              logErrors: logErrors))
                {
                    // time requirements are not valid
                    canPlace = false;
                    isTooFar = false;
                    return;
                }

                if (!SharedValidateCanCharacterRelocateStructure(character,
                                                                 objectStructure,
                                                                 tilePosition,
                                                                 out errorMessage,
                                                                 logErrors: logErrors))
                {
                    canPlace = true;
                    isTooFar = true;
                    return;
                }

                if (SharedHasObstacle(
                        character,
                        objectStructure,
                        tilePosition.ToVector2D() + protoStructure.Layout.Center))
                {
                    if (logErrors)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(
                            character,
                            CoreStrings.Notification_ObstaclesOnTheWay,
                            isOutOfRange: true);
                    }

                    errorMessage = CoreStrings.Notification_ObstaclesOnTheWay;
                    canPlace     = true;
                    isTooFar     = true;
                    return;
                }

                canPlace = true;
                isTooFar = false;
            }

            void ClientConstructionPlaceSelectedCallback(Vector2Ushort tilePosition)
            {
                if (SharedHasObstacle(
                        character,
                        objectStructure,
                        tilePosition.ToVector2D() + protoStructure.Layout.Center))
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(
                        character,
                        CoreStrings.Notification_ObstaclesOnTheWay,
                        isOutOfRange: true);
                    return;
                }

                ClientTimersSystem.AddAction(0.1, ClientDisableConstructionRelocation);
                if (tilePosition != objectStructure.TilePosition)
                {
                    Instance.CallServer(_ => _.ServerRemote_RelocateStructure(objectStructure, tilePosition));
                }
            }
        }
Пример #10
0
        public static bool CheckCanInteractForConstruction(
            ICharacter character,
            IStaticWorldObject worldObject,
            bool writeToLog,
            bool checkRaidblock)
        {
            var characterPosition      = character.Position;
            var canInteract            = false;
            var staticWorldObjectProto = ProtoObjectConstructionSite.SharedGetConstructionProto(worldObject)
                                         ?? worldObject.ProtoStaticWorldObject;

            var startTilePosition = worldObject.TilePosition;

            foreach (var tileOffset in staticWorldObjectProto.Layout.TileOffsets)
            {
                var tilePosition = startTilePosition + tileOffset;

                if (characterPosition.DistanceSquaredTo(
                        new Vector2D(tilePosition.X + 0.5, tilePosition.Y + 0.5))
                    <= MaxDistanceForBuildRepairAction * MaxDistanceForBuildRepairAction)
                {
                    canInteract = true;
                    break;
                }
            }

            if (!canInteract)
            {
                canInteract = CreativeModeSystem.SharedIsInCreativeMode(character);
            }

            if (!canInteract)
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Character cannot interact with {worldObject} for (de)construction - too far.",
                        character);

                    if (IsClient)
                    {
                        CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                                            CoreStrings.Notification_TooFar,
                                                                            isOutOfRange: true);
                    }
                }

                return(false);
            }

            if (checkRaidblock &&
                LandClaimSystem.SharedIsUnderRaidBlock(character, worldObject))
            {
                // the building is in an area under the raid
                if (writeToLog)
                {
                    LandClaimSystem.SharedSendNotificationActionForbiddenUnderRaidblock(character);
                }

                return(false);
            }

            return(true);
        }
Пример #11
0
 private void ClientRemote_OnCannotInteractNoAccess(IStaticWorldObject worldObject)
 {
     CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject,
                                                         NotificationDontHaveAccess,
                                                         isOutOfRange: false);
 }
Пример #12
0
        protected override void SharedValidateRequest(FishingActionRequest request)
        {
            var character             = request.Character;
            var fishingTargetPosition = request.FishingTargetPosition;
            var itemRod = request.Item;

            if (itemRod is null ||
                itemRod != character.SharedGetPlayerSelectedHotbarItem() ||
                !(itemRod.ProtoItem is IProtoItemToolFishing))
            {
                throw new Exception("The fishing rod is not selected");
            }

            var fishingRodPublicState = itemRod.GetPublicState <ItemFishingRodPublicState>();

            if (fishingRodPublicState.CurrentProtoBait is null ||
                SharedFindBaitItem(character, fishingRodPublicState.CurrentProtoBait) is null)
            {
                // no bait available
                throw new Exception("There is no bait available of the required type");
            }

            var world = IsServer
                            ? (IWorldService)Server.World
                            : (IWorldService)Client.World;
            var tile = world.GetTile(fishingTargetPosition.ToVector2Ushort());

            if (!(tile.ProtoTile is IProtoTileWater protoTileWater) ||
                !protoTileWater.IsFishingAllowed)
            {
                if (IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(character,
                                                                        Notification_CannotFishHere,
                                                                        isOutOfRange: false);
                }

                throw new Exception("Cannot fish here");
            }

            // check obstacle objects (such as bridges)
            using var testResults = world.GetPhysicsSpace()
                                    .TestPoint(fishingTargetPosition,
                                               CollisionGroups.Default,
                                               sendDebugEvent: false);

            foreach (var testResult in testResults.AsList())
            {
                if (testResult.PhysicsBody.AssociatedWorldObject is null)
                {
                    continue;
                }

                // an obstacle found
                if (IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(character,
                                                                        Notification_CannotFishHere,
                                                                        isOutOfRange: false);
                }

                throw new Exception("Cannot fish here");
            }

            if (SharedIsTooFar(character, fishingTargetPosition))
            {
                if (IsClient)
                {
                    CannotInteractMessageDisplay.ClientOnCannotInteract(character,
                                                                        CoreStrings.Notification_TooFar,
                                                                        isOutOfRange: true);
                }

                throw new Exception("Too far");
            }
        }