Exemple #1
0
        public virtual double ServerCalculateTotalDamageByExplosive(
            ICharacter byCharacter,
            IStaticWorldObject targetStaticWorldObject)
        {
            var structureExplosiveDefenseCoef =
                targetStaticWorldObject.ProtoStaticWorldObject.StructureExplosiveDefenseCoef;

            structureExplosiveDefenseCoef = MathHelper.Clamp(structureExplosiveDefenseCoef, 0, 1);

            var explosiveDefensePenetrationCoef = this.StructureDefensePenetrationCoef;

            explosiveDefensePenetrationCoef = MathHelper.Clamp(explosiveDefensePenetrationCoef, 0, 1);

            if (!PveSystem.SharedIsAllowStaticObjectDamage(byCharacter,
                                                           targetStaticWorldObject,
                                                           showClientNotification: false))
            {
                return(0);
            }

            var damage = this.StructureDamage
                         * (1 - structureExplosiveDefenseCoef * (1 - explosiveDefensePenetrationCoef));

            return(damage);
        }
        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);
        }
        private static async Task <string> ClientOnWelcomeMessageReceivedFromServer(Task <string> t)
        {
            var message = t.Result;
            await PveSystem.ClientAwaitPvEModeFromServer();

            if (string.IsNullOrWhiteSpace(message))
            {
                // no welcome message
                if (!Client.CurrentGame.IsConnectedToOfficialServer)
                {
                    // don't have any welcome message
                    return(string.Empty);
                }

                // use official server welcome message
                message = GetOfficialServerWelcomeMessage();
            }
            else if (Client.CurrentGame.IsConnectedToOfficialServer)
            {
                // append official welcome message to the custom welcome message
                // ReSharper disable once CanExtractXamlLocalizableStringCSharp
                message += "[br][br]─────────────────────────────────────[br]" + GetOfficialServerWelcomeMessage();
            }

            return(message);
        }
        public static IStaticWorldObject SharedGetCompatibleTarget(
            ICharacter character,
            Vector2Ushort worldPosition,
            out bool hasIncompatibleTarget,
            out bool isPveActionForbidden)
        {
            isPveActionForbidden = false;
            var tile = IsServer
                           ? Server.World.GetTile(worldPosition)
                           : Client.World.GetTile(worldPosition);

            var targetObject = tile.StaticObjects.FirstOrDefault();

            if (targetObject is null)
            {
                hasIncompatibleTarget = false;
                return(null);
            }

            if (!PveSystem.SharedIsAllowStaticObjectDamage(character, targetObject, showClientNotification: false))
            {
                hasIncompatibleTarget = true;
                isPveActionForbidden  = true;
                return(null);
            }

            if (!SharedIsValidDroneTarget(targetObject))
            {
                hasIncompatibleTarget = true;
                return(null);
            }

            hasIncompatibleTarget = false;
            return(targetObject);
        }
Exemple #5
0
        private static bool SharedHasObstacle(
            ICharacter character,
            IStaticWorldObject forStructureRelocation,
            Vector2D position)
        {
            if (PveSystem.SharedIsPve(false))
            {
                return(false);
            }

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

            return(TestHasObstacle(position));

            // local method for testing if there is an obstacle from current to the specified position
            bool TestHasObstacle(Vector2D toPosition)
            {
                using var obstaclesInTheWay = character.PhysicsBody.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 ||
                        ReferenceEquals(testWorldObject, character) ||
                        ReferenceEquals(testWorldObject, forStructureRelocation))
                    {
                        // 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);
            }
        }
Exemple #6
0
        protected override void PrepareTileRequirements(ConstructionTileRequirements tileRequirements)
        {
            base.PrepareTileRequirements(tileRequirements);

            // disallow placing mining bombs on the floor on the PvE servers
            tileRequirements.Add(
                new ConstructionTileRequirements.Validator(
                    ConstructionTileRequirements.ErrorNoFreeSpace,
                    c => !PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false) ||
                    c.Tile.StaticObjects.All(
                        o => o.ProtoStaticWorldObject.Kind != StaticObjectKind.Floor)));
        }
Exemple #7
0
        public override bool SharedCanInteract(ICharacter character, IStaticWorldObject worldObject, bool writeToLog)
        {
            if (!base.SharedCanInteract(character, worldObject, writeToLog))
            {
                return(false);
            }

            var ownerName = GetPublicState(worldObject).OwnerName;

            if (ownerName == character.Name)
            {
                return(true);
            }

            if (PveSystem.SharedIsPve(false))
            {
                if (IsClient && PartySystem.ClientIsPartyMember(ownerName) ||
                    (IsServer &&
                     PartySystem.ServerIsSameParty(Server.Characters.GetPlayerCharacter(ownerName),
                                                   character)))
                {
                    // in PvE party members can pickup items of their party members
                }
                else
                {
                    // other players in PvE cannot pickup player's loot
                    if (writeToLog && IsClient)
                    {
                        PveSystem.ClientShowNotificationActionForbidden();
                    }

                    return(false);
                }
            }

            if (NewbieProtectionSystem.SharedIsNewbie(character))
            {
                // newbie cannot pickup other players' loot
                if (writeToLog)
                {
                    NewbieProtectionSystem.SharedShowNewbieCannotDamageOtherPlayersOrLootBags(character,
                                                                                              isLootBag: true);
                }

                return(false);
            }

            // non-newbie character can pickup players' loot
            // please note this validation has an override for derived ObjectPlayerLootContainerProtected
            return(true);
        }
Exemple #8
0
        private void RefreshDepletion()
        {
            this.ValueCurrent = this.publicState?.StructurePointsCurrent ?? 0;
            if (this.ValueCurrent <= 0)
            {
                if (PveSystem.ClientIsPve(logErrorIfDataIsNotYetAvailable: true))
                {
                    // PvE mode doesn't require the deposit under the extractor
                    this.DepletionDurationText = TitleDepositInfinite;
                    this.ValueCurrent          = this.ValueMax = 1;
                }
                else
                {
                    this.DepletionDurationText = TitleDepositDepleted;
                }

                this.DepletedInPrefixVisibility = Visibility.Collapsed;
                return;
            }

            var lifetimeTotalDurationSeconds = this.protoDeposit.LifetimeTotalDurationSeconds;

            if (lifetimeTotalDurationSeconds == 0)
            {
                this.DepletionDurationText      = TitleDepositInfinite;
                this.DepletedInPrefixVisibility = Visibility.Collapsed;
                return;
            }

            this.DepletedInPrefixVisibility = Visibility.Visible;
            var structurePointsFraction = this.ValueCurrent / this.ValueMax;

            var remainsNoExtraction = structurePointsFraction
                                      * lifetimeTotalDurationSeconds;

            var remainsWithExtraction = remainsNoExtraction
                                        / this.protoDeposit.DecaySpeedMultiplierWhenExtractingActive;

            if (remainsNoExtraction == remainsWithExtraction)
            {
                // display a single duration
                this.DepletionDurationText = FormatDuration(remainsNoExtraction);
            }
            else
            {
                // display an interval
                this.DepletionDurationText = FormatInterval(remainsWithExtraction, remainsNoExtraction);
            }
        }
Exemple #9
0
        protected override double SharedCalculateDamageByWeapon(
            WeaponFinalCache weaponCache,
            double damagePreMultiplier,
            IStaticWorldObject targetObject,
            out double obstacleBlockDamageCoef)
        {
            if (!PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                           targetObject,
                                                           showClientNotification: false))
            {
                obstacleBlockDamageCoef = 0;
                return(0);
            }

            if (weaponCache.ProtoWeapon is IProtoItemToolMining protoItemToolMining)
            {
                // mining mineral with a mining device
                // block next damage completely - only one mineral could be mined at once
                obstacleBlockDamageCoef = 1;

                // get damage multiplier ("mining speed")
                var damageMultiplier = weaponCache.CharacterFinalStatsCache.GetMultiplier(StatName.MiningSpeed);

                return(protoItemToolMining.ServerGetDamageToMineral(targetObject)
                       * damageMultiplier
                       * RateActionMiningSpeedMultiplier.SharedValue);
            }

            if (weaponCache.ProtoWeapon is ItemNoWeapon)
            {
                // no damage with hands
                obstacleBlockDamageCoef = 1;

                if (IsClient)
                {
                    NotificationSystem.ClientShowNotification(NotificationUsePickaxe,
                                                              icon: this.Icon);
                }

                return(0);
            }

            // not a mining tool - call default damage apply method
            return(base.SharedCalculateDamageByWeapon(weaponCache,
                                                      damagePreMultiplier,
                                                      targetObject,
                                                      out obstacleBlockDamageCoef));
        }
Exemple #10
0
        protected override double SharedCalculateDamageByWeapon(
            WeaponFinalCache weaponCache,
            double damagePreMultiplier,
            IStaticWorldObject targetObject,
            out double obstacleBlockDamageCoef)
        {
            // ReSharper disable once VariableHidesOuterVariable
            if (!PveSystem.SharedIsAllowStaticObjectDamage(weaponCache.Character,
                                                           targetObject,
                                                           showClientNotification: false))
            {
                obstacleBlockDamageCoef = 0;
                return(0);
            }

            if (weaponCache.ProtoWeapon is IProtoItemToolWoodcutting protoItemToolWoodCutting)
            {
                // get damage multiplier ("woodcutting speed")
                obstacleBlockDamageCoef = 1;
                var damageMultiplier = weaponCache.CharacterFinalStatsCache.GetMultiplier(
                    StatName.WoodcuttingSpeed);

                return(protoItemToolWoodCutting.ServerGetDamageToTree(targetObject)
                       * damageMultiplier
                       * ToolsConstants.ActionWoodcuttingSpeedMultiplier
                       * this.SharedGetDamageMultiplierByGrowthProgress(targetObject));
            }

            if (weaponCache.ProtoWeapon is ItemNoWeapon)
            {
                // no damage with hands
                obstacleBlockDamageCoef = 1;

                if (IsClient)
                {
                    NotificationSystem.ClientShowNotification(NotificationUseAxe,
                                                              icon: this.Icon);
                }

                return(0);
            }

            // not a wood-cutting tool - call default damage apply method
            return(base.SharedCalculateDamageByWeapon(weaponCache,
                                                      damagePreMultiplier,
                                                      targetObject,
                                                      out obstacleBlockDamageCoef));
        }
        public static async void ClientPutCurrentVehicle()
        {
            if (!PveSystem.ClientIsPve(logErrorIfDataIsNotYetAvailable: true))
            {
                // this feature is available only in PvE
                return;
            }

            var vehicleAssemblyBay = InteractionCheckerSystem.SharedGetCurrentInteraction(
                ClientCurrentCharacterHelper.Character);
            var isSuccess = await Instance.CallServer(_ => _.ServerRemote_PutCurrentVehicle());

            if (isSuccess)
            {
                Client.Audio.PlayOneShot(SoundResourcePutVehicle, vehicleAssemblyBay);
            }
        }
Exemple #12
0
        public double Get(TechTier tier, bool isSpecialized)
        {
            if (PveSystem.SharedIsPve(false))
            {
                return(0);
            }

            var tierIndex = (int)tier - (int)TechConstants.PvPTimeGateStartsFromTier;

            if (tierIndex < 0)
            {
                return(0);
            }

            var index = 2 * tierIndex + (isSpecialized ? 1 : 0);

            return(this.TimeGates[index]);
        }
Exemple #13
0
        private bool ValidateTarget(IStaticWorldObject targetObject, out Vector2D targetPoint)
        {
            targetPoint = Vector2D.Zero;
            if (!PveSystem.SharedIsAllowStaticObjectDamage(CurrentCharacter,
                                                           targetObject,
                                                           showClientNotification: false))
            {
                return(false);
            }
            var shape = targetObject.PhysicsBody.Shapes.FirstOrDefault(s => s.CollisionGroup == CollisionGroups.HitboxMelee);

            if (shape == null)
            {
                Api.Logger.Error("Automaton: target object has no HitBoxMelee shape " + targetObject);
                return(false);
            }
            targetPoint = ShapeCenter(shape) + targetObject.PhysicsBody.Position;
            return(AdditionalValidation(targetObject) && CheckForObstacles(targetObject, targetPoint));
        }
        protected override double SharedCalculateDamageByWeapon(
            WeaponFinalCache weaponCache,
            double damagePreMultiplier,
            IStaticWorldObject targetObject,
            out double obstacleBlockDamageCoef)
        {
            obstacleBlockDamageCoef = 1;
            if (!PveSystem.SharedIsAllowStructureDamage(weaponCache.Character,
                                                        targetObject,
                                                        showClientNotification: false))
            {
                return(0);
            }

            if (weaponCache.ProtoWeapon is IProtoItemToolWoodcutting protoItemToolWoodCutting)
            {
                // get damage multiplier ("woodcutting speed")
                var damageMultiplier = weaponCache.Character
                                       .SharedGetFinalStatMultiplier(StatName.WoodcuttingSpeed);

                return(protoItemToolWoodCutting.DamageToTree
                       * damageMultiplier
                       * ToolsConstants.ActionWoodcuttingSpeedMultiplier);
            }

            if (weaponCache.ProtoWeapon is ItemNoWeapon)
            {
                // no damage with hands
                if (IsClient)
                {
                    NotificationSystem.ClientShowNotification(NotificationUseAxe,
                                                              icon: this.Icon);
                }

                return(0);
            }

            // not a wood-cutting tool - call default damage apply method
            return(base.SharedCalculateDamageByWeapon(weaponCache,
                                                      damagePreMultiplier,
                                                      targetObject,
                                                      out obstacleBlockDamageCoef));
        }
        public virtual bool SharedCanInteract(ICharacter character, TWorldObject worldObject, bool writeToLog)
        {
            if (!this.IsInteractableObject)
            {
                return(false);
            }

            if (character.GetPublicState <ICharacterPublicState>().IsDead ||
                IsServer && !character.ServerIsOnline)
            {
                return(false);
            }

            if (worldObject is IStaticWorldObject staticWorldObject)
            {
                if (PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false))
                {
                    if (!PveSystem.SharedValidateInteractionIsNotForbidden(character,
                                                                           staticWorldObject,
                                                                           writeToLog))
                    {
                        // action forbidden by PvE system
                        return(false);
                    }
                }
                else // PvP servers have newbie protection system
                {
                    if (!NewbieProtectionSystem.SharedValidateInteractionIsNotForbidden(
                            character,
                            staticWorldObject,
                            writeToLog))
                    {
                        // action forbidden by newbie protection system
                        return(false);
                    }
                }
            }

            return(this.SharedIsInsideCharacterInteractionArea(character,
                                                               worldObject,
                                                               writeToLog));
        }
Exemple #16
0
        protected override double SharedCalculateDamageByWeapon(
            WeaponFinalCache weaponCache,
            double damagePreMultiplier,
            IDynamicWorldObject targetObject,
            out double obstacleBlockDamageCoef)
        {
            if (PveSystem.SharedIsPve(false) &&
                (weaponCache.Character is null ||
                 !weaponCache.Character.IsNpc))
            {
                // no PvP damage in PvE (only creature damage is allowed)
                obstacleBlockDamageCoef = 0;
                return(0);
            }

            return(base.SharedCalculateDamageByWeapon(weaponCache,
                                                      damagePreMultiplier,
                                                      targetObject,
                                                      out obstacleBlockDamageCoef));
        }
Exemple #17
0
        private static double SharedGetSpeedMultiplier(IStaticWorldObject objectDeposit)
        {
            return(GetDepositExtractionRateMultiplier()
                   * StructureConstants.DepositsExtractionSpeedMultiplier);

            double GetDepositExtractionRateMultiplier()
            {
                if (PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false))
                {
                    return(ExtractorPvE);
                }

                // extractor in PvP
                if (objectDeposit is null)
                {
                    return(ExtractorPvpWithoutDeposit);
                }

                var protoObjectDeposit = (IProtoObjectDeposit)objectDeposit.ProtoStaticWorldObject;

                return(ExtractorPvpWithDeposit);
            }
        }
        public static bool SharedIsAllowInteraction(
            ICharacter character,
            IStaticWorldObject worldObject,
            bool showClientNotification)
        {
            if (!SharedIsEnabled)
            {
                return(true);
            }

            if (character is null ||
                !PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false))
            {
                return(true);
            }

            var worldObjectPublicState = worldObject.AbstractPublicState as IWorldObjectPublicStateWithClaim;

            if (worldObjectPublicState?.WorldObjectClaim is null ||
                WorldObjectClaim.SharedIsClaimedForPlayer(worldObjectPublicState.WorldObjectClaim, character))
            {
                return(true);
            }

            if (IsClient && showClientNotification)
            {
                NotificationSystem.ClientShowNotification(
                    CoreStrings.WorldObjectClaim_Title,
                    CoreStrings.WorldObjectClaim_Description
                    + "[br]"
                    + CoreStrings.WorldObjectClaim_Description2,
                    NotificationColor.Bad,
                    icon: TextureResourceClaimedObject);
            }

            return(false);
        }
Exemple #19
0
        private static async Task <WelcomeMessageRemoteData> ClientOnWelcomeMessageReceivedFromServer(
            Task <WelcomeMessageRemoteData> t)
        {
            const string h1s  = "[h1]",
                         h1c  = "[/h1]",
                         br   = "[br]",
                         brbr = br + br;

            var data = t.Result;
            var sb   = new StringBuilder();

            var welcomeMessage = data.WelcomeMessage;
            await PveSystem.ClientAwaitPvEModeFromServer();

            // Header 0 - Community server
            if (!Client.CurrentGame.IsConnectedToOfficialServer)
            {
                sb.AppendLine(h1s + HeaderDescriptionCommunity + h1c)
                .AppendLine(br)
                .AppendLine(DescriptionCommunity)
                .AppendLine(brbr);
            }

            // Header 1 - Server welcome message (section displayed only when available)
            if (!string.IsNullOrWhiteSpace(welcomeMessage))
            {
                sb.AppendLine(h1s + HeaderWelcomeMessage + h1c)
                .AppendLine(br)
                .AppendLine(welcomeMessage)
                .AppendLine(brbr);
            }

            // Header 2 - PvP or PvE server description
            var isPveServer = PveSystem.ClientIsPve(logErrorIfDataIsNotYetAvailable: true);

            if (isPveServer)
            {
                sb.AppendLine(h1s + HeaderDescriptionPvE + h1c)
                .AppendLine(br)
                .AppendLine(DescriptionPvE)
                .AppendLine(brbr);
            }
            else // PvP server
            {
                sb.AppendLine(h1s + HeaderDescriptionPvP + h1c)
                .AppendLine(br)
                .AppendLine(DescriptionPvP)
                .AppendLine(brbr);
            }

            // Header 3 - Modded server (if the server is modded)
            if (Client.CurrentGame.ServerInfo.ModsOnServer.Count > 0)
            {
                sb.AppendLine(h1s + HeaderModded + h1c)
                .AppendLine(br)
                .AppendLine(DescriptionModded)
                .AppendLine(brbr);
            }

            // Header 4 - Server wipe information
            sb.AppendLine(h1s + HeaderWipeInformation + h1c)
            .AppendLine(br);

            if (data.ScheduledWipeDateUtc.HasValue)
            {
                sb.AppendLine(string.Format(CoreStrings.ServerWipeInfoStartedDate_Format,
                                            FormatDate(Client.CurrentGame.ServerInfo.CreationDateUtc.ToLocalTime())))
                .AppendLine(br)
                .AppendLine(string.Format(CoreStrings.ServerWipeInfoNextWipeDate_Format,
                                          FormatDate(data.ScheduledWipeDateUtc.Value.ToLocalTime())))
                .AppendLine(br)
                .AppendLine(ClientLocalTimeZoneHelper.GetTextTimeAlreadyConvertedToLocalTimeZone());
            }
            else if (Client.CurrentGame.IsConnectedToOfficialServer &&
                     isPveServer)
            {
                sb.AppendLine(CoreStrings.ServerWipeInfoOnMajorUpdatesOnly);
            }
            else
            {
                sb.AppendLine(CoreStrings.ServerWipeInfoNotSpecified
                              + " "
                              + CoreStrings.ConsultServerAdministrator);
            }

            return(new WelcomeMessageRemoteData(sb.ToString(), data.ScheduledWipeDateUtc));
        }
        private async static void InitPVE()
        {
            await PveSystem.ClientAwaitPvEModeFromServer();

            IsPVE = PveSystem.ClientIsPve(false);
        }
Exemple #21
0
        private static void SharedRebuildAllNodes()
        {
            if (Api.IsClient &&
                !PveSystem.ClientIsPveFlagReceived)
            {
                AvailableTechGroups = new TechGroup[0];
                return;
            }

            var isPvE = PveSystem.SharedIsPve(false);

            var allTechGroups = Api.FindProtoEntities <TechGroup>();

            foreach (var techGroup in allTechGroups)
            {
                SetupTimeGate(techGroup);

                techGroup.Nodes = techGroup.IsAvailable
                                      ? (IReadOnlyList <TechNode>)LazyAllNodesWithoutFiltering
                                  .Value
                                  .Where(n => n.Group == techGroup &&
                                         n.IsAvailable)
                                  .OrderBy(n => n.HierarchyLevel)
                                  .ThenBy(n => n.Order)
                                  .ThenBy(n => n.ShortId)
                                  .ToList()
                                      : new TechNode[0];

                var rootNodes = new List <TechNode>();
                foreach (var node in techGroup.Nodes)
                {
                    node.SharedResetCachedLearningPointsPrice();

                    if (node.IsRootNode)
                    {
                        rootNodes.Add(node);
                    }
                }

                techGroup.RootNodes = rootNodes;

                var requirements = new Requirements();
                techGroup.PrepareTechGroup(requirements);
                if (techGroup.LearningPointsPrice > 0)
                {
                    requirements.Insert(0, new TechGroupRequirementLearningPoints(techGroup.LearningPointsPrice));
                }

                if (!PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false) &&
                    techGroup.TimeGatePvP > 0)
                {
                    requirements.Add(new TechGroupRequirementTimeGate(techGroup.TimeGatePvP));
                }

                techGroup.GroupRequirements = requirements;

                Api.SafeInvoke(techGroup.NodesChanged);
            }

            AvailableTechGroups = allTechGroups.Where(t => t.IsAvailable).ToArray();
            Api.SafeInvoke(AvailableTechGroupsChanged);

            void SetupTimeGate(TechGroup techGroup)
            {
                if (isPvE)
                {
                    techGroup.TimeGatePvP = 0;
                    return;
                }

                if (techGroup.IsPrimary)
                {
                    techGroup.TimeGatePvP = techGroup.Tier switch
                    {
                        TechTier.Tier3 => TechConstants.PvpTechTimeGameTier3Basic,
                        TechTier.Tier4 => TechConstants.PvpTechTimeGameTier4Basic,
                        TechTier.Tier5 => TechConstants.PvpTechTimeGameTier5Basic,
                        _ => 0
                    };
                }
                else
                {
                    techGroup.TimeGatePvP = techGroup.Tier switch
                    {
                        TechTier.Tier3 => TechConstants.PvpTechTimeGameTier3Specialized,
                        TechTier.Tier4 => TechConstants.PvpTechTimeGameTier4Specialized,
                        TechTier.Tier5 => TechConstants.PvpTechTimeGameTier5Specialized,
                        _ => 0
                    };
                }
            }
        }
Exemple #22
0
        public virtual bool SharedCanInteract(ICharacter character, TWorldObject worldObject, bool writeToLog)
        {
            if (!this.IsInteractableObject)
            {
                return(false);
            }

            try
            {
                this.VerifyGameObject(worldObject);
            }
            catch (Exception ex)
            {
                Logger.Warning($"Interaction check failed: {ex.GetType().FullName}: {ex.Message}");
                return(false);
            }

            if (character.GetPublicState <ICharacterPublicState>().IsDead ||
                IsServer && !character.ServerIsOnline ||
                ((IsServer || character.IsCurrentClientCharacter) &&
                 PlayerCharacter.GetPrivateState(character).IsDespawned))
            {
                if (writeToLog)
                {
                    Logger.Warning(
                        $"Character cannot interact with {worldObject} - character is offline/despawned/dead.",
                        character);
                }

                return(false);
            }

            if (worldObject is IStaticWorldObject staticWorldObject)
            {
                if (PveSystem.SharedIsPve(clientLogErrorIfDataIsNotYetAvailable: false))
                {
                    if (!PveSystem.SharedValidateInteractionIsNotForbidden(character,
                                                                           staticWorldObject,
                                                                           writeToLog))
                    {
                        // action forbidden by PvE system
                        return(false);
                    }
                }
                else // PvP servers have newbie protection system
                {
                    if (!NewbieProtectionSystem.SharedValidateInteractionIsNotForbidden(
                            character,
                            staticWorldObject,
                            writeToLog))
                    {
                        // action forbidden by newbie protection system
                        return(false);
                    }
                }
            }

            return(this.SharedIsInsideCharacterInteractionArea(character,
                                                               worldObject,
                                                               writeToLog));
        }
Exemple #23
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);
        }
Exemple #24
0
 public override bool SharedCanInteract(ICharacter character, IStaticWorldObject worldObject, bool writeToLog)
 {
     return(PveSystem.SharedValidateInteractionIsNotForbidden(character, worldObject, writeToLog) &&
            NewbieProtectionSystem.SharedValidateInteractionIsNotForbidden(character, worldObject, writeToLog) &&
            this.SharedIsInsideCharacterInteractionArea(character, worldObject, writeToLog));
 }
Exemple #25
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) ||
                 !PveSystem.SharedIsAllowStructureDamage(weaponCache.Character,
                                                         staticWorldObject,
                                                         showClientNotification: false)))
            {
                return(0);
            }

            if (weaponCache.ProtoObjectExplosive != null &&
                targetObject.ProtoWorldObject is IProtoStaticWorldObject targetStaticWorldObjectProto)
            {
                // special case - apply the explosive damage
                return(ServerCalculateTotalDamageByExplosive(weaponCache.ProtoObjectExplosive,
                                                             targetStaticWorldObjectProto,
                                                             damagePreMultiplier));
            }

            // these two cases apply only if damage dealt not by a bomb
            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 != null &&
                     !damagingCharacter.IsNpc)
            {
                // apply PvE damage multiplier
                totalDamage *= WeaponConstants.DamagePveMultiplier;
            }
            else if (damagingCharacter != null &&
                     damagingCharacter.IsNpc)
            {
                // apply creature damage multiplier
                totalDamage *= WeaponConstants.DamageCreaturesMultiplier;

                if (targetObject is ICharacter victim &&
                    !victim.ServerIsOnline &&
                    !victim.IsNpc)
                {
                    // don't deal creature damage to offline players
                    totalDamage = 0;
                }
            }

            if (isFriendlyFireCase)
            {
                totalDamage *= WeaponConstants.DamageFriendlyFireMultiplier;
            }

            return(totalDamage);
        }
Exemple #26
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));
                }
            }
        }
        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);
        public static void SetupSkeletonEquipmentForCharacter(
            ICharacter character,
            IItemsContainer containerEquipment,
            IComponentSkeleton skeletonRenderer,
            ProtoCharacterSkeleton skeleton,
            List <IClientComponent> skeletonComponents,
            bool isPreview = false)
        {
            if (!(skeleton is SkeletonHumanMale) &&
                !(skeleton is SkeletonHumanFemale))
            {
                // not a human
                // setup only implants
                using var equipmentImplants = Api.Shared.WrapInTempList(
                          containerEquipment.GetItemsOfProto <IProtoItemEquipmentImplant>());
                foreach (var item in equipmentImplants.AsList())
                {
                    var proto = (IProtoItemEquipmentImplant)item.ProtoGameObject;
                    proto.ClientSetupSkeleton(item,
                                              character,
                                              skeletonRenderer,
                                              skeletonComponents,
                                              isPreview);
                }

                return;
            }

            bool isMale, isHeadEquipmentHiddenForSelfAndPartyMembers;
            CharacterHumanFaceStyle faceStyle;

            if (character.ProtoCharacter is PlayerCharacter)
            {
                var publicState = PlayerCharacter.GetPublicState(character);
                faceStyle = publicState.FaceStyle;
                isMale    = publicState.IsMale;
                isHeadEquipmentHiddenForSelfAndPartyMembers = publicState.IsHeadEquipmentHiddenForSelfAndPartyMembers;

                if (isMale && !(skeleton is SkeletonHumanMale) ||
                    !isMale && !(skeleton is SkeletonHumanFemale))
                {
                    throw new Exception(
                              $"Skeleton don\'t match the gender of the player\'s character: isMale={isMale}, {skeleton}");
                }
            }
            else
            {
                // for NPC it will generate a random face
                isMale    = true;
                faceStyle = SharedCharacterFaceStylesProvider.GetForGender(isMale).GenerateRandomFace();
                isHeadEquipmentHiddenForSelfAndPartyMembers = false;
            }

            skeletonRenderer.ResetAttachments();
            skeleton.ClientResetItemInHand(skeletonRenderer);

            var skinToneId = faceStyle.SkinToneId;

            if (string.IsNullOrEmpty(skinToneId))
            {
                skeletonRenderer.DefaultTextureRemapper = null;
            }
            else
            {
                // use colorizer for the original sprites (to apply the skin tone)
                skeletonRenderer.DefaultTextureRemapper
                    = textureResource =>
                    {
                    var filePath = textureResource.LocalPath;
                    if (filePath.IndexOf("/Weapon", StringComparison.Ordinal) >= 0 ||
                        filePath.IndexOf("/Head", StringComparison.Ordinal) >= 0)
                    {
                        // no need to remap the original head and weapon sprites
                        // (they're never used as is)
                        return(textureResource);
                    }

                    return(ClientCharacterSkinTexturesCache.Get(textureResource,
                                                                skinToneId));
                    };
            }

            // setup equipment items
            using var equipmentItems = Api.Shared.WrapInTempList(
                      containerEquipment.GetItemsOfProto <IProtoItemEquipment>());
            if (!IsAllowNakedHumans)
            {
                if (!equipmentItems.AsList().Any(i => i.ProtoGameObject is IProtoItemEquipmentArmor))
                {
                    // no armor equipped - apply generic one
                    var pants = GenericPantsAttachments.Value;
                    ClientSkeletonAttachmentsLoader.SetAttachments(
                        skeletonRenderer,
                        isMale
                            ? pants.SlotAttachmentsMale
                            : pants.SlotAttachmentsFemale);

                    // select a random generic T-shirt based on character ID
                    var allShirts          = GenericShirtAttachments.Value;
                    var selectedShirtIndex = character.Id % allShirts.Length;
                    var shirt = allShirts[(int)selectedShirtIndex];
                    ClientSkeletonAttachmentsLoader.SetAttachments(
                        skeletonRenderer,
                        isMale
                            ? shirt.SlotAttachmentsMale
                            : shirt.SlotAttachmentsFemale);
                }
            }

            IItem headEquipmentForFaceSprite = null;

            foreach (var item in equipmentItems.AsList())
            {
                var proto = (IProtoItemEquipment)item.ProtoGameObject;
                proto.ClientSetupSkeleton(item,
                                          character,
                                          skeletonRenderer,
                                          skeletonComponents,
                                          isPreview);

                if (item.ProtoItem is IProtoItemEquipmentHead &&
                    headEquipmentForFaceSprite is null)
                {
                    headEquipmentForFaceSprite = item;
                }
            }

            if (isHeadEquipmentHiddenForSelfAndPartyMembers &&
                (character.IsCurrentClientCharacter ||
                 PartySystem.ClientIsPartyMember(character.Name) ||
                 PveSystem.ClientIsPve(false)))
            {
                headEquipmentForFaceSprite = null;
            }

            // generate head sprites for human players
            const string slotName       = "Head",
                         attachmentName = "Head";

            headGenerationId++;

            var spriteQualityOffset = skeletonRenderer.SpriteQualityOffset;

            skeletonRenderer.SetAttachmentSprite(
                skeleton.SkeletonResourceFront,
                slotName,
                attachmentName,
                new ProceduralTexture(
                    $"Head Front CharacterID={character.Id} gen={headGenerationId}",
                    proceduralTextureRequest =>
                    ClientCharacterHeadSpriteComposer.GenerateHeadSprite(
                        new CharacterHeadSpriteData(faceStyle,
                                                    headEquipmentForFaceSprite,
                                                    skeleton.SkeletonResourceFront),
                        proceduralTextureRequest,
                        isMale,
                        headSpriteType: ClientCharacterHeadSpriteComposer.HeadSpriteType.Front,
                        spriteQualityOffset: spriteQualityOffset),
                    isTransparent: true,
                    isUseCache: false));

            skeletonRenderer.SetAttachmentSprite(
                skeleton.SkeletonResourceBack,
                slotName,
                attachmentName,
                new ProceduralTexture(
                    $"Head Back CharacterID={character.Id} gen={headGenerationId}",
                    proceduralTextureRequest =>
                    ClientCharacterHeadSpriteComposer.GenerateHeadSprite(
                        new CharacterHeadSpriteData(faceStyle,
                                                    headEquipmentForFaceSprite,
                                                    skeleton.SkeletonResourceBack),
                        proceduralTextureRequest,
                        isMale,
                        headSpriteType: ClientCharacterHeadSpriteComposer.HeadSpriteType.Back,
                        spriteQualityOffset: spriteQualityOffset),
                    isTransparent: true,
                    isUseCache: false));

            skeletonRenderer.SetAttachmentSprite(
                skeleton.SkeletonResourceBack,
                slotName + "Back",
                attachmentName,
                new ProceduralTexture(
                    $"Head Back2 CharacterID={character.Id} gen={headGenerationId}",
                    proceduralTextureRequest =>
                    ClientCharacterHeadSpriteComposer.GenerateHeadSprite(
                        new CharacterHeadSpriteData(faceStyle,
                                                    headEquipmentForFaceSprite,
                                                    skeleton.SkeletonResourceBack),
                        proceduralTextureRequest,
                        isMale,
                        headSpriteType: ClientCharacterHeadSpriteComposer.HeadSpriteType.BackOverlay,
                        spriteQualityOffset: spriteQualityOffset),
                    isTransparent: true,
                    isUseCache: false));
        }
        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;
            }
Exemple #30
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);
            }
        }