public static bool SharedValidateCanUnstuck(ICharacter character)
        {
            using var tempAreas = Api.Shared.GetTempList <ILogicObject>();
            var bounds = new RectangleInt(
                offset: character.TilePosition - (1, 1),
                size: (2, 2));

            LandClaimSystem.SharedGetAreasInBounds(bounds, tempAreas, addGracePadding: false);
            foreach (var area in tempAreas.AsList())
            {
                if (LandClaimSystem.SharedIsAreaUnderRaid(area))
                {
                    Logger.Info("Cannot unstuck when located in an area under raid", character);
                    LandClaimSystem.SharedSendNotificationActionForbiddenUnderRaidblock(character);
                    return(false);
                }

                if (LandClaimShieldProtectionSystem.SharedIsAreaUnderShieldProtection(area))
                {
                    Logger.Info("Cannot unstuck when located in an area under shield protection", character);
                    LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection(character);
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 2
0
        protected sealed override void ServerUpdate(ServerUpdateData data)
        {
            var character    = data.GameObject;
            var privateState = data.PrivateState;
            var publicState  = data.PublicState;

            var objectTurret = privateState.ObjectTurret;

            if (objectTurret is null)
            {
                return;
            }

            var objectTurretPrivateState = objectTurret.GetPrivateState <ObjectTurretPrivateState>();
            var turretMode = objectTurretPrivateState.TurretMode;

            if (turretMode == TurretMode.Disabled)
            {
                return;
            }

            var objectTurretPublicState = objectTurret.GetPublicState <ObjectTurretPublicState>();

            if (objectTurretPublicState.ElectricityConsumerState != ElectricityConsumerState.PowerOnActive)
            {
                return;
            }

            if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectTurret))
            {
                return;
            }

            this.ServerRebuildFinalCacheIfNeeded(privateState, publicState);

            ServerUpdateAggroState(privateState, data.DeltaTime);
            this.ServerUpdateTurret(data, turretMode);

            // update weapon state (fires the weapon if needed)
            WeaponSystem.SharedUpdateCurrentWeapon(
                character,
                privateState.WeaponState,
                data.DeltaTime);
        }
        public string Execute(
            ShieldProtectionStatus status,
            [CurrentCharacterIfNull] ICharacter character = null)
        {
            if (!LandClaimShieldProtectionConstants.SharedIsEnabled)
            {
                return("S.H.I.E.L.D. protection is not available");
            }

            if (status == ShieldProtectionStatus.Active)
            {
                status = ShieldProtectionStatus.Activating;
            }

            using var tempAreas = Api.Shared.GetTempList <ILogicObject>();
            LandClaimSystem.SharedGetAreasInBounds(
                new RectangleInt(character.TilePosition, (1, 1)),
                tempAreas,
                addGracePadding: false);

            var area = tempAreas.AsList().FirstOrDefault();

            if (area is null)
            {
                return("No base exist near " + character.Name);
            }

            var areasGroup = LandClaimSystem.SharedGetLandClaimAreasGroup(area);

            LandClaimShieldProtectionSystem.SharedGetShieldProtectionMaxStatsForBase(areasGroup,
                                                                                     out _,
                                                                                     out _);

            var privateState = LandClaimAreasGroup.GetPrivateState(areasGroup);

            privateState.ShieldProtectionCooldownExpirationTime = 0;

            var publicState = LandClaimAreasGroup.GetPublicState(areasGroup);

            publicState.Status = status;
            publicState.ShieldActivationTime = Server.Game.FrameTime;

            return($"Status of the S.H.I.E.L.D. changed to {status}.");
        }
Ejemplo n.º 4
0
            private void UpdateCallback()
            {
                var areasGroup = LandClaimArea.GetPublicState(this.area).LandClaimAreasGroup;
                var status     = LandClaimShieldProtectionSystem.SharedGetShieldPublicStatus(areasGroup);

                switch (status)
                {
                case ShieldProtectionStatus.Active:
                    this.markControl.IsUnderShield = true;
                    break;

                // ReSharper disable once CompareOfFloatsByEqualityOperator
                case ShieldProtectionStatus.Activating:
                    // flicker the icon for half a second
                    this.markControl.IsUnderShield = Math.Round(Api.Client.Core.ClientRealTime % 1.0)
                                                     == 0.0;
                    break;

                default:
                    this.markControl.IsUnderShield = false;
                    break;
                }
            }
        public string Execute(
            double chargePercent = 100,
            [CurrentCharacterIfNull] ICharacter character = null)
        {
            if (!LandClaimShieldProtectionConstants.SharedIsEnabled)
            {
                return("S.H.I.E.L.D. protection is not available");
            }

            var chargeFraction = MathHelper.Clamp(chargePercent / 100, min: 0, max: 1);

            using var tempAreas = Api.Shared.GetTempList <ILogicObject>();
            LandClaimSystem.SharedGetAreasInBounds(
                new RectangleInt(character.TilePosition, (1, 1)),
                tempAreas,
                addGracePadding: false);

            var area = tempAreas.AsList().FirstOrDefault();

            if (area is null)
            {
                return("No base exist near " + character.Name);
            }

            var areasGroup = LandClaimSystem.SharedGetLandClaimAreasGroup(area);

            LandClaimShieldProtectionSystem.SharedGetShieldProtectionMaxStatsForBase(areasGroup,
                                                                                     out _,
                                                                                     out var electricityCapacity);

            var privateState = LandClaimAreasGroup.GetPrivateState(areasGroup);

            privateState.ShieldProtectionCurrentChargeElectricity = electricityCapacity * chargeFraction;
            privateState.ShieldProtectionCooldownExpirationTime   = 0; // reset the cooldown

            return($"Charge amount of the S.H.I.E.L.D. modified to {chargeFraction * 100}% and cooldown reset.");
        }
Ejemplo n.º 6
0
        public static double ServerCalculateTotalDamage(
            WeaponFinalCache weaponCache,
            IWorldObject targetObject,
            FinalStatsCache targetFinalStatsCache,
            double damagePreMultiplier,
            bool clampDefenseTo1)
        {
            if (targetObject is IStaticWorldObject staticWorldObject &&
                (!RaidingProtectionSystem.SharedCanRaid(staticWorldObject,
                                                        showClientNotification: false) ||
                 !LandClaimShieldProtectionSystem.SharedCanRaid(staticWorldObject,
                                                                showClientNotification: false) ||
                 !PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                            staticWorldObject,
                                                            showClientNotification: false) ||
                 !NewbieProtectionSystem.SharedIsAllowStructureDamage(weaponCache.Character,
                                                                      staticWorldObject,
                                                                      showClientNotification: false)))
            {
                return(0);
            }

            if (targetObject.ProtoGameObject is IProtoVehicle &&
                !PveSystem.SharedIsAllowVehicleDamage(weaponCache,
                                                      (IDynamicWorldObject)targetObject,
                                                      showClientNotification: false))
            {
                return(0);
            }

            if (weaponCache.ProtoExplosive is not null &&
                targetObject is IStaticWorldObject targetStaticWorldObject)
            {
                // special case - apply the explosive damage to static object
                return(ServerCalculateTotalDamageByExplosive(weaponCache.Character,
                                                             weaponCache.ProtoExplosive,
                                                             targetStaticWorldObject,
                                                             damagePreMultiplier));
            }

            if (ServerIsRestrictedPvPDamage(weaponCache,
                                            targetObject,
                                            out var isPvPcase,
                                            out var isFriendlyFireCase))
            {
                return(0);
            }

            var damageValue = damagePreMultiplier * weaponCache.DamageValue;
            var invertedArmorPiercingCoef = weaponCache.InvertedArmorPiercingCoef;

            var totalDamage = 0d;

            // calculate total damage by summing all the damage components
            foreach (var damageDistribution in weaponCache.DamageDistributions)
            {
                var defenseStatName = SharedGetDefenseStatName(damageDistribution.DamageType);
                var defenseFraction = targetFinalStatsCache[defenseStatName];
                defenseFraction = MathHelper.Clamp(defenseFraction, 0, clampDefenseTo1 ? 1 : double.MaxValue);

                totalDamage += ServerCalculateDamageComponent(
                    damageValue,
                    invertedArmorPiercingCoef,
                    damageDistribution,
                    defenseFraction);
            }

            // multiply on final multiplier (usually used for expanding projectiles)
            totalDamage *= weaponCache.FinalDamageMultiplier;

            var damagingCharacter = weaponCache.Character;

            if (isPvPcase)
            {
                // apply PvP damage multiplier
                totalDamage *= WeaponConstants.DamagePvpMultiplier;
            }
            else if (damagingCharacter is not null &&
                     !damagingCharacter.IsNpc &&
                     targetObject.ProtoGameObject
                     is IProtoCharacterMob protoCharacterMob &&
                     !protoCharacterMob.IsBoss)
            {
                // apply PvE damage multiplier
                totalDamage *= WeaponConstants.DamagePveMultiplier;
            }
Ejemplo n.º 7
0
        public virtual bool SharedOnDamage(
            WeaponFinalCache weaponCache,
            IStaticWorldObject targetObject,
            double damagePreMultiplier,
            out double obstacleBlockDamageCoef,
            out double damageApplied)
        {
            var objectPublicState       = GetPublicState(targetObject);
            var previousStructurePoints = objectPublicState.StructurePointsCurrent;

            if (previousStructurePoints <= 0f)
            {
                // already destroyed static world object
                obstacleBlockDamageCoef = 0;
                damageApplied           = 0;
                return(false);
            }

            var serverDamage = this.SharedCalculateDamageByWeapon(
                weaponCache,
                damagePreMultiplier,
                targetObject,
                out obstacleBlockDamageCoef);

            if (serverDamage < 0)
            {
                Logger.Warning(
                    $"Server damage less than 0 and this is suspicious. {this} calculated damage: {serverDamage:0.###}");
                serverDamage = 0;
            }

            if (IsClient)
            {
                // simply call these methods to display a client notification only!
                // they are not used for anything else here
                // to calculate damage they're used in WeaponDamageSystem.ServerCalculateTotalDamage method.
                RaidingProtectionSystem.SharedCanRaid(targetObject,
                                                      showClientNotification: true);
                LandClaimShieldProtectionSystem.SharedCanRaid(targetObject,
                                                              showClientNotification: true);
                PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                          targetObject,
                                                          showClientNotification: true);
                NewbieProtectionSystem.SharedIsAllowStructureDamage(weaponCache.Character,
                                                                    targetObject,
                                                                    showClientNotification: true);

                damageApplied = 0;
                return(true);
            }

            if (serverDamage <= 0)
            {
                // no damage applied
                damageApplied = 0;
                return(true);
            }

            // apply damage
            damageApplied = serverDamage;
            var newStructurePoints = (float)(previousStructurePoints - serverDamage);

            if (newStructurePoints < 0)
            {
                newStructurePoints = 0;
            }

            Logger.Info(
                $"Damage applied to {targetObject} by {weaponCache.Character}:\n{serverDamage} dmg, current structure points {newStructurePoints}/{this.StructurePointsMax}, {weaponCache.Weapon}");

            objectPublicState.StructurePointsCurrent = newStructurePoints;

            try
            {
                this.ServerOnStaticObjectDamageApplied(
                    weaponCache,
                    targetObject,
                    previousStructurePoints,
                    newStructurePoints);
            }
            catch (Exception ex)
            {
                Logger.Exception(ex, $"Problem on processing {nameof(this.ServerOnStaticObjectDamageApplied)}()");
            }

            if (newStructurePoints <= 0f)
            {
                this.ServerOnStaticObjectZeroStructurePoints(weaponCache, weaponCache.Character, targetObject);
            }

            return(true);
        }
Ejemplo n.º 8
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));
                }
            }
        }
Ejemplo n.º 9
0
        public static bool SharedValidateCanCharacterRelocateStructure(
            ICharacter character,
            IStaticWorldObject objectStructure,
            Vector2Ushort toPosition,
            out string errorMessage,
            bool logErrors)
        {
            if (!SharedIsRelocatable(objectStructure))
            {
                errorMessage = null;
                return(false);
            }

            if (!SharedCheckTileRequirementsForRelocation(character,
                                                          objectStructure,
                                                          toPosition,
                                                          out errorMessage,
                                                          logErrors))
            {
                return(false);
            }

            if (!(objectStructure.ProtoGameObject is IProtoObjectStructure protoStructure))
            {
                return(false);
            }

            var maxRelocationDistance = PveSystem.SharedIsPve(true)
                                            ? MaxRelocationDistancePvE
                                            : MaxRelocationDistancePvP;

            if (objectStructure.TilePosition.TileSqrDistanceTo(toPosition)
                > maxRelocationDistance * maxRelocationDistance)
            {
                if (logErrors)
                {
                    ConstructionSystem.SharedShowCannotPlaceNotification(
                        character,
                        CoreStrings.Notification_TooFar,
                        protoStructure);
                }

                errorMessage = CoreStrings.Notification_TooFar;
                return(false);
            }

            var itemInHands = character.SharedGetPlayerSelectedHotbarItem();

            if (!(itemInHands.ProtoGameObject is IProtoItemToolToolbox))
            {
                return(false);
            }

            if (CreativeModeSystem.SharedIsInCreativeMode(character))
            {
                errorMessage = null;
                return(true);
            }

            if (!LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition,
                                                   character,
                                                   requireFactionPermission: true,
                                                   out var hasNoFactionPermission,
                                                   ownedArea: out _) ||
                !IsOwnedLand(toPosition, out hasNoFactionPermission))
            {
                errorMessage = string.Format(CoreStrings.Faction_Permission_Required_Format,
                                             CoreStrings.Faction_Permission_LandClaimManagement_Title);

                // the building location or destination is in an area that is not owned by the player
                if (logErrors)
                {
                    SharedShowCannotRelocateNotification(
                        character,
                        protoStructure,
                        hasNoFactionPermission);
                }

                return(false);
            }

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

                return(false);
            }

            if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure))
            {
                // the building is in an area under shield protection
                errorMessage = CoreStrings.ShieldProtection_ActionRestrictedBaseUnderShieldProtection;
                if (logErrors)
                {
                    LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection(
                        character);
                }

                return(false);
            }

            errorMessage = null;
            return(true);

            bool IsOwnedLand(
                Vector2Ushort startTilePosition,
                out bool hasNoFactionPermission)
            {
                var worldObjectLayoutTileOffsets = objectStructure.ProtoStaticWorldObject.Layout.TileOffsets;

                foreach (var tileOffset in worldObjectLayoutTileOffsets)
                {
                    if (!LandClaimSystem.SharedIsOwnedLand(startTilePosition.AddAndClamp(tileOffset),
                                                           character,
                                                           requireFactionPermission: true,
                                                           out hasNoFactionPermission,
                                                           out _))
                    {
                        return(false);
                    }
                }

                hasNoFactionPermission = false;
                return(true);
            }
        }
Ejemplo n.º 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);
            }

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

                return(false);
            }

            return(true);
        }
Ejemplo n.º 11
0
        public static bool SharedValidateCanCharacterRelocateStructure(
            ICharacter character,
            IStaticWorldObject objectStructure,
            Vector2Ushort toPosition,
            bool logErrors)
        {
            if (!SharedIsRelocatable(objectStructure))
            {
                return(false);
            }

            if (!SharedCheckTileRequirementsForRelocation(character,
                                                          objectStructure,
                                                          toPosition,
                                                          logErrors))
            {
                return(false);
            }

            if (!(objectStructure.ProtoGameObject is IProtoObjectStructure protoStructure))
            {
                return(false);
            }

            if (objectStructure.TilePosition.TileSqrDistanceTo(toPosition)
                > MaxRelocationDistance * MaxRelocationDistance)
            {
                if (logErrors)
                {
                    ConstructionSystem.SharedShowCannotPlaceNotification(
                        character,
                        CoreStrings.Notification_TooFar,
                        protoStructure);
                }

                return(false);
            }

            var itemInHands = character.SharedGetPlayerSelectedHotbarItem();

            if (!(itemInHands.ProtoGameObject is IProtoItemToolToolbox))
            {
                return(false);
            }

            if (CreativeModeSystem.SharedIsInCreativeMode(character))
            {
                return(true);
            }

            if (!LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition, character, out _) ||
                !IsOwnedLand(toPosition))
            {
                // the building location or destination is in an area that is not owned by the player
                if (logErrors)
                {
                    ConstructionSystem.SharedShowCannotPlaceNotification(
                        character,
                        LandClaimSystem.ErrorNotLandOwner_Message,
                        protoStructure);
                }

                return(false);
            }

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

                return(false);
            }

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

                return(false);
            }

            return(true);

            bool IsOwnedLand(Vector2Ushort startTilePosition)
            {
                var worldObjectLayoutTileOffsets = objectStructure.ProtoStaticWorldObject.Layout.TileOffsets;

                foreach (var tileOffset in worldObjectLayoutTileOffsets)
                {
                    if (!LandClaimSystem.SharedIsOwnedLand(startTilePosition.AddAndClamp(tileOffset), character, out _))
                    {
                        return(false);
                    }
                }

                return(true);
            }
        }
Ejemplo n.º 12
0
        public ObjectLandClaimCanUpgradeCheckResult SharedCanUpgrade(
            IStaticWorldObject worldObjectLandClaim,
            IProtoObjectLandClaim protoUpgradedLandClaim,
            ICharacter character,
            out IConstructionUpgradeEntryReadOnly upgradeEntry,
            bool writeErrors = true)
        {
            if (!this.SharedCanInteract(character,
                                        worldObjectLandClaim,
                                        writeToLog: writeErrors))
            {
                upgradeEntry = null;
                return(ObjectLandClaimCanUpgradeCheckResult.ErrorUnknown);
            }

            upgradeEntry = null;
            foreach (var entry in this.ConfigUpgrade.Entries)
            {
                if (entry.ProtoStructure == protoUpgradedLandClaim)
                {
                    upgradeEntry = entry;
                    break;
                }
            }

            var currentLandClaimArea = GetPublicState(worldObjectLandClaim).LandClaimAreaObject;
            var founderName          = LandClaimArea.GetPrivateState(currentLandClaimArea).LandClaimFounder;

            var result = ObjectLandClaimCanUpgradeCheckResult.Success;

            if (upgradeEntry == null)
            {
                result = ObjectLandClaimCanUpgradeCheckResult.ErrorUnknown;
            }

            if (result == ObjectLandClaimCanUpgradeCheckResult.Success)
            {
                if (character.Name != founderName &&
                    !CreativeModeSystem.SharedIsInCreativeMode(character))
                {
                    result = ObjectLandClaimCanUpgradeCheckResult.ErrorNotFounder;
                }
            }

            if (result == ObjectLandClaimCanUpgradeCheckResult.Success)
            {
                // validate player know the tech, have enough items, etc
                if (!upgradeEntry.CheckRequirementsSatisfied(character))
                {
                    upgradeEntry = null;
                    result       = ObjectLandClaimCanUpgradeCheckResult.ErrorRequirementsNotSatisfied;
                }
            }

            if (result == ObjectLandClaimCanUpgradeCheckResult.Success &&
                LandClaimShieldProtectionSystem.SharedIsAreaUnderShieldProtection(currentLandClaimArea))
            {
                // the building is in an area under shield protection
                result = ObjectLandClaimCanUpgradeCheckResult.ErrorUnderShieldProtection;
            }

            if (result == ObjectLandClaimCanUpgradeCheckResult.Success)
            {
                // check there will be no intersection with other areas
                var landClaimCenterTilePosition =
                    LandClaimSystem.SharedCalculateLandClaimObjectCenterTilePosition(worldObjectLandClaim);

                if (!LandClaimSystem.SharedCheckCanPlaceOrUpgradeLandClaimThereConsideringShieldProtection(
                        protoUpgradedLandClaim,
                        landClaimCenterTilePosition,
                        character))
                {
                    result = ObjectLandClaimCanUpgradeCheckResult.ErrorAreaIntersectionWithShieldProtectedArea;
                }

                if (!LandClaimSystem.SharedCheckCanPlaceOrUpgradeLandClaimThere(
                        protoUpgradedLandClaim,
                        landClaimCenterTilePosition,
                        character))
                {
                    result = ObjectLandClaimCanUpgradeCheckResult.ErrorAreaIntersection;
                }

                if (!LandClaimSystem.SharedCheckNoLandClaimByDemoPlayers(
                        protoUpgradedLandClaim,
                        landClaimCenterTilePosition,
                        character,
                        exceptAreasGroup: LandClaimSystem.SharedGetLandClaimAreasGroup(currentLandClaimArea)))
                {
                    result = ObjectLandClaimCanUpgradeCheckResult.ErrorAreaIntersectionDemoPlayer;
                }

                if (IsServer &&
                    !LandClaimSystem.ServerCheckFutureBaseWillExceedSafeStorageCapacity(
                        protoUpgradedLandClaim,
                        landClaimCenterTilePosition,
                        character))
                {
                    result = ObjectLandClaimCanUpgradeCheckResult.ErrorExceededSafeStorageCapacity;
                }
            }

            if (result == ObjectLandClaimCanUpgradeCheckResult.Success)
            {
                if (!InteractionCheckerSystem.SharedHasInteraction(character,
                                                                   worldObjectLandClaim,
                                                                   requirePrivateScope: true))
                {
                    result = ObjectLandClaimCanUpgradeCheckResult.ErrorNoActiveInteraction;
                }
            }

            if (result == ObjectLandClaimCanUpgradeCheckResult.Success &&
                LandClaimSystem.SharedIsUnderRaidBlock(character, worldObjectLandClaim))
            {
                // the building is in an area under raid
                LandClaimSystem.SharedSendNotificationActionForbiddenUnderRaidblock(character);
                result = ObjectLandClaimCanUpgradeCheckResult.ErrorUnderRaid;
            }

            if (writeErrors &&
                result != ObjectLandClaimCanUpgradeCheckResult.Success)
            {
                Logger.Warning(
                    $"Can't upgrade: {worldObjectLandClaim} to {protoUpgradedLandClaim}: error code - {result}",
                    character);
            }

            return(result);
        }