protected override void SharedOnActionCompletedInternal(WateringActionState state, ICharacter character)
        {
            var worldObject      = (IStaticWorldObject)state.TargetWorldObject;
            var protoPlant       = (IProtoObjectPlant)worldObject.ProtoWorldObject;
            var itemWateringCan  = state.ItemWateringCan;
            var protoWateringCan = (IProtoItemToolWateringCan)itemWateringCan.ProtoItem;

            if (IsServer)
            {
                protoPlant.ServerOnWatered(character,
                                           worldObject,
                                           wateringDuration: protoWateringCan.WateringDuration.TotalSeconds);
            }

            protoWateringCan.SharedOnWatered(itemWateringCan, worldObject);

            if (IsServer)
            {
                character.ServerAddSkillExperience <SkillFarming>(SkillFarming.ExperienceForWatering);

                // notify tool was used
                ServerItemUseObserver.NotifyItemUsed(character, itemWateringCan);

                // reduce watering can durability
                ItemDurabilitySystem.ServerModifyDurability(itemWateringCan, delta: -1);
            }
        }
Beispiel #2
0
        protected override void ServerOnDegradeWeapon(
            ICharacter character,
            IItem weaponItem,
            IProtoItemWeapon protoWeapon,
            List <WeaponHitData> hitObjects)
        {
            if (hitObjects.Count == 0)
            {
                // no objects were hit
                return;
            }

            var decrease = this.DurabilityDecreasePerAction;

            foreach (var hit in hitObjects)
            {
                var protoObject = hit.WorldObject.ProtoWorldObject;
                if (protoObject is IProtoObjectWall ||
                    protoObject is IProtoObjectDoor ||
                    protoObject is IProtoObjectTradingStation)
                {
                    // hit wall, door or station
                    decrease *= 5;
                    break;
                }
            }

            ItemDurabilitySystem.ServerModifyDurability(
                weaponItem,
                delta: -decrease);
        }
        protected override void ServerUpdate(ServerUpdateData data)
        {
            var item = data.GameObject;

            if (!(item.Container?.ProtoItemsContainer is ItemsContainerGeneratorSolar))
            {
                // the panel is not installed
                return;
            }

            var worldObjectGenerator = item.Container.OwnerAsStaticObject;

            if (worldObjectGenerator == null ||
                worldObjectGenerator.IsDestroyed)
            {
                return;
            }

            // The panel is installed.
            // Decrease durability proportionally to the generation rate
            // (degrade only during the daytime and only if active).
            var rate = ProtoObjectGeneratorSolar.SharedGetElectricityProductionRate(worldObjectGenerator);

            if (rate <= 0)
            {
                return;
            }

            var decrease = this.DurabilityDecreasePerMinuteWhenInstalled * (data.DeltaTime / 60.0);

            decrease *= rate;

            ItemDurabilitySystem.ServerModifyDurability(item,
                                                        delta: -(int)decrease);
        }
Beispiel #4
0
        protected override void ServerUpdate(ServerUpdateData data)
        {
            var publicState = data.PublicState;

            if (!publicState.IsActive)
            {
                return;
            }

            var item = data.GameObject;

            ItemDurabilitySystem.ServerModifyDurability(item,
                                                        -this.DurabilityDecreasePerSecond * data.DeltaTime,
                                                        roundUp: true);

            // check if item is in a hotbar selected slot, if not - make it not active
            var itemOwnerCharacter = item.Container?.OwnerAsCharacter;

            if (itemOwnerCharacter == null ||
                !itemOwnerCharacter.ServerIsOnline ||
                item != itemOwnerCharacter.SharedGetPlayerSelectedHotbarItem())
            {
                Logger.Info(item + " is not in the hotbar selected slot or player is offline - make it inactive");
                publicState.IsActive = false;
                return;
            }

            ServerItemUseObserver.NotifyItemUsed(itemOwnerCharacter, item);

            this.ItemFuelConfig.SharedTryConsumeFuel(item, data.PrivateState, data.DeltaTime, out var isFuelRanOut);
            if (isFuelRanOut)
            {
                publicState.IsActive = false;
            }
        }
Beispiel #5
0
        private void ServerRemote_OnActionCompletedInternal(IItem itemVehicleRemote, ICharacter character, Vector2D mousePosition)
        {
            if (!(itemVehicleRemote.ProtoItem is IProtoItemVehicleRemoteControl protoRemote))
            {
                return;
            }

            if (!CharacterEnergySystem.SharedHasEnergyCharge(character, protoRemote.EngeryUse))
            {
                return;
            }

            List <GarageVehicleEntry> list = VehicleGarageSystem.ServerGetCharacterVehicles(character, false);

            TakeVehicleResult result = TakeVehicleResult.Unknown;

            if (list.Count > 0)
            {
                var privateState = itemVehicleRemote.GetPrivateState <ItemVehicleRemoteControlPrivateState>();
                result = this.ServerTakeVehicle(privateState, character, mousePosition);
            }

            if (result == TakeVehicleResult.Success)
            {
                CharacterEnergySystem.ServerDeductEnergyCharge(character, protoRemote.EngeryUse);

                ItemDurabilitySystem.ServerModifyDurability(itemVehicleRemote, delta: -1);
            }
        }
        private static void ServerOnBatteryItemCharged(IItem item, double energyAdded)
        {
            if (energyAdded <= 0)
            {
                return;
            }

            var container = item.Container;

            // reduce durability proportionally to the added charge
            ItemDurabilitySystem.ServerModifyDurability(item, -(int)Math.Ceiling(energyAdded));

            if (!item.IsDestroyed)
            {
                return;
            }

            // item was destroyed during recharging
            var character = container?.OwnerAsCharacter;

            if (character == null ||
                character.SharedGetPlayerContainerEquipment() != container)
            {
                return;
            }

            // redistribute remaining energy to other energy bank devices
            var energyRemains = SharedGetPrivateState(item).EnergyCharge;

            ServerAddEnergyChargeInternal(character,
                                          energyRemains,
                                          invokeServerOnBatteryItemCharged: false);
        }
Beispiel #7
0
        private void ServerApplyItemsDecay(
            ObjectGeneratorPragmiumReactorPrivateState reactorPrivateState,
            double deltaTime)
        {
            var activationProgress = reactorPrivateState.ActivationProgressPercents / 100.0;

            if (activationProgress <= 0)
            {
                reactorPrivateState.ServerAccumulatedDecayDuration = 0;
                return;
            }

            using var tempItemsList = Api.Shared.WrapInTempList(reactorPrivateState.ItemsContainer.Items);
            if (tempItemsList.Count == 0)
            {
                return;
            }

            reactorPrivateState.ServerAccumulatedDecayDuration += deltaTime;
            if (reactorPrivateState.ServerAccumulatedDecayDuration < ItemDecayIntervalDuration)
            {
                return;
            }

            // apply accumulated decay
            reactorPrivateState.ServerAccumulatedDecayDuration -= ItemDecayIntervalDuration;
            var decayMultiplier     = activationProgress * ItemDecayIntervalDuration;
            var fuelDecayMultiplier = 100.0 / reactorPrivateState.Stats.FuelLifetimePercent;

            foreach (var item in tempItemsList.AsList())
            {
                var protoGameObject = item.ProtoGameObject;
                switch (protoGameObject)
                {
                case ItemReactorFuelRod protoFuelRod:
                {
                    var decayAmount = decayMultiplier
                                      * protoFuelRod.DurabilityMax
                                      / protoFuelRod.LifetimeDuration;

                    decayAmount *= fuelDecayMultiplier;

                    ItemDurabilitySystem.ServerModifyDurability(item, -(int)decayAmount);
                    break;
                }

                case ProtoItemReactorModule protoItemModule:
                {
                    var decayAmount = decayMultiplier
                                      * protoItemModule.DurabilityMax
                                      / protoItemModule.LifetimeDuration;

                    ItemDurabilitySystem.ServerModifyDurability(item, -(int)decayAmount);
                    break;
                }
                }
            }
        }
        public static void ServerDespawnDrone(IDynamicWorldObject objectDrone, bool isReturnedToPlayer)
        {
            var privateState = objectDrone.GetPrivateState <DronePrivateState>();
            var publicState  = objectDrone.GetPublicState <DronePublicState>();

            publicState.ResetTargetPosition();

            if (privateState.IsDespawned)
            {
                return;
            }

            var droneItem      = privateState.AssociatedItem;
            var protoItemDrone = (IProtoItemDrone)droneItem.ProtoItem;
            var characterOwner = privateState.CharacterOwner;
            var world          = Server.World;

            var protoDrone = protoItemDrone.ProtoDrone;

            protoDrone.ServerOnDroneDroppedOrReturned(objectDrone, characterOwner, isReturnedToPlayer);

            // recreate physics (as despawned drone doesn't have any physics)
            privateState.IsDespawned = true;
            world.StopPhysicsBody(objectDrone.PhysicsBody);
            objectDrone.ProtoWorldObject.SharedCreatePhysics(objectDrone);
            world.SetPosition(objectDrone,
                              ServerCharacterDeathMechanic.ServerGetGraveyardPosition().ToVector2D());

            privateState.CharacterOwner = null;
            ServerOnDroneControlRemoved(characterOwner, objectDrone);

            var currentDurability = (int)(objectDrone.GetPublicState <DronePublicState>().StructurePointsCurrent
                                          / protoItemDrone.DurabilityToStructurePointsConversionCoefficient);

            if (currentDurability <= 1)
            {
                currentDurability = 0;
            }

            var deltaDurabilility = (int)(ItemDurabilitySystem.SharedGetDurabilityValue(droneItem)
                                          - currentDurability);

            if (deltaDurabilility <= 0)
            {
                return;
            }

            ItemDurabilitySystem.ServerModifyDurability(droneItem,
                                                        -deltaDurabilility);

            if (droneItem.IsDestroyed)
            {
                // drone item degraded to 100%, notify the player
                ItemDurabilitySystem.Instance.CallClient(characterOwner,
                                                         _ => _.ClientRemote_ItemBroke(droneItem.ProtoItem));
            }
        }
        private static void ServerOnEnergyUsed(IItem item, double energyAmountUsed)
        {
            if (energyAmountUsed <= 0)
            {
                return;
            }

            // reduce durability proportionally to the removed charge
            ItemDurabilitySystem.ServerModifyDurability(item, -(int)Math.Ceiling(energyAmountUsed));
        }
Beispiel #10
0
        private void SharedOnStageCompleted()
        {
            if (Api.IsServer)
            {
                // notify tool was used
                ServerItemUseObserver.NotifyItemUsed(this.Character, this.ItemVehicleRepairKit);

                // reduce tool durability
                ItemDurabilitySystem.ServerModifyDurability(this.ItemVehicleRepairKit, delta: -1);
            }
            else // if client
            {
                Api.Client.Audio.PlayOneShot(VehicleSystem.SoundResourceVehicleRepair);
            }

            this.currentStageDurationSeconds     = this.CalculateStageDurationSeconds(this.Character, isFirstStage: false);
            this.currentStageTimeRemainsSeconds += this.currentStageDurationSeconds;

            var currentStructurePoints = this.VehiclePublicState.StructurePointsCurrent;
            var newStructurePoints     = currentStructurePoints
                                         + this.stageStructureAddValue;

            if (Api.IsServer)
            {
                ((IProtoVehicle)this.Vehicle.ProtoGameObject)
                .ServerOnRepair(this.Vehicle, this.Character);
            }

            if (currentStructurePoints < this.structurePointsMax)
            {
                // repairing is still possible - more stages are available
                this.UpdateProgress();

                if (Api.IsServer &&
                    this.ItemVehicleRepairKit.IsDestroyed)
                {
                    // tool was destroyed (durability 0)
                    this.AbortAction();
                    return;
                }

                return;
            }

            // repairing is absolutely completed
            if (Api.IsServer)
            {
                // TODO: add skill experience for repair
                // this.CharacterPrivateState.Skills.ServerAddSkillExperience<SkillVehicles>(
                //     SkillVehicles.ExperienceAddWhenRepairFinished);
            }

            this.SetCompleted(isCancelled: false);
            VehicleRepairKitSystem.SharedActionCompleted(this.Character, this);
        }
        public override void ServerOnItemDamaged(IItem item, double damageApplied)
        {
            var owner = item.Container.OwnerAsCharacter;

            if (owner != null)
            {
                damageApplied *= owner.SharedGetFinalStatMultiplier(StatName.ImplantDegradationFromDamageMultiplier);
            }

            ItemDurabilitySystem.ServerModifyDurability(item, delta: -(int)damageApplied);
        }
Beispiel #12
0
        private void ServerRemote_RelocateStructure(IStaticWorldObject objectStructure, Vector2Ushort toPosition)
        {
            if (objectStructure.TilePosition == toPosition)
            {
                // relocation not required
                return;
            }

            var character = ServerRemoteContext.Character;

            if (!SharedValidateCanCharacterRelocateStructure(character,
                                                             objectStructure,
                                                             toPosition,
                                                             errorMessage: out _,
                                                             logErrors: true))
            {
                return;
            }

            var fromPosition = objectStructure.TilePosition;

            Api.SafeInvoke(
                () => ServerStructureBeforeRelocating?.Invoke(character, fromPosition, objectStructure));

            Server.World.SetPosition(objectStructure, toPosition);

            try
            {
                // ensure the structure is reinitialized (has its physics rebuilt, etc)
                objectStructure.ServerInitialize();
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
            }

            ConstructionPlacementSystem.Instance.ServerNotifyOnStructurePlacedOrRelocated(objectStructure, character);

            Api.SafeInvoke(
                () => ServerStructureRelocated?.Invoke(character, fromPosition, objectStructure));

            // let's deduct the tool durability
            if (CreativeModeSystem.SharedIsInCreativeMode(character))
            {
                return;
            }

            // the item in hotbar is definitely a construction tool as it was validated above
            var itemConstructionTool = character.SharedGetPlayerSelectedHotbarItem();

            ItemDurabilitySystem.ServerModifyDurability(
                itemConstructionTool,
                delta: -((IProtoObjectStructure)objectStructure.ProtoGameObject).RelocationToolDurabilityCost);
        }
        private static void ServerOnEnergyUsed(IItem item, double energyAmountUsed)
        {
            if (energyAmountUsed <= 0)
            {
                return;
            }

            // reduce durability proportionally to the removed charge, durability as int is dropping to fast
            if (RandomHelper.Next(20) == 1)
            {
                ItemDurabilitySystem.ServerModifyDurability(item, -energyAmountUsed, true);
            }
        }
Beispiel #14
0
        public override void ServerOnCharacterDeath(IItem item, bool isEquipped, out bool shouldDrop)
        {
            // implants never drop on death
            shouldDrop = false;
            if (!isEquipped)
            {
                return;
            }

            // durability reduced on death
            var fraction        = MathHelper.Clamp(this.DurabilityFractionReduceOnDeath, 0, 1);
            var durabilityDelta = (ushort)(this.DurabilityMax * fraction);

            ItemDurabilitySystem.ServerModifyDurability(item, delta: -durabilityDelta);
        }
Beispiel #15
0
        public virtual void ServerOnCharacterDeath(IItem item, bool isEquipped, out bool shouldDrop)
        {
            shouldDrop = true;
            if (!isEquipped)
            {
                return;
            }

            if (item.ProtoItem is IProtoItemWithDurablity protoItemWithDurablity)
            {
                // -10% of durability reduced on death
                const double durabilityFractionReduceOnDeath = 0.1;
                var          durabilityDelta = (ushort)(protoItemWithDurablity.DurabilityMax * durabilityFractionReduceOnDeath);
                ItemDurabilitySystem.ServerModifyDurability(item, delta: -durabilityDelta);
            }
        }
Beispiel #16
0
        public virtual void ServerOnCharacterDeath(IItem item, bool isEquipped, out bool shouldDrop)
        {
            shouldDrop = true;
            if (!isEquipped)
            {
                return;
            }

            if (item.ProtoItem is IProtoItemWithDurablity protoItemWithDurablity)
            {
                // -10% of durability reduced on death
                var durabilityDelta = protoItemWithDurablity.DurabilityMax * DurabilityFractionReduceOnDeath;
                ItemDurabilitySystem.ServerModifyDurability(item,
                                                            delta: -durabilityDelta,
                                                            roundUp: false);
            }
        }
        protected sealed override void ServerUpdate(ServerUpdateData data)
        {
            base.ServerUpdate(data);

            if (this.durabilityDecreasePerServerUpdate <= 0)
            {
                // non-degradeable
                return;
            }

            if (data.DeltaTime <= 0)
            {
                // not processed
                return;
            }

            // try to degrade durability over time and give experience for cybernetic affinity skill
            var item  = data.GameObject;
            var owner = item.Container?.OwnerAsCharacter;

            if (owner is null ||
                !owner.ServerIsOnline ||
                owner.SharedGetPlayerContainerEquipment() != item.Container)
            {
                // player offline or not an equipped item
                return;
            }

            if (CharacterIdleSystem.ServerIsIdlePlayer(owner))
            {
                return;
            }

            var durabilityDecrease = this.durabilityDecreasePerServerUpdate;

            durabilityDecrease *= owner.SharedGetFinalStatMultiplier(StatName.ImplantDegradationSpeedMultiplier);
            ItemDurabilitySystem.ServerModifyDurability(item, -durabilityDecrease, roundUp: false);

            owner.ServerAddSkillExperience <SkillCyberneticAffinity>(
                data.DeltaTime * SkillCyberneticAffinity.ExperienceAddedPerImplantPerSecond);

            if (!item.IsDestroyed)
            {
                this.ServerUpdateInstalledImplant(data);
            }
        }
Beispiel #18
0
        private void ServerGatheringSystemGatherHandler(ICharacter character, IStaticWorldObject worldObject)
        {
            if (!(worldObject.ProtoStaticWorldObject is ObjectCorpse))
            {
                return;
            }

            // corpse looted
            var itemDevice = character.SharedGetPlayerContainerEquipment()
                             .GetItemsOfProto(this)
                             .FirstOrDefault();

            if (itemDevice == null)
            {
                // don't have an equipped device
                return;
            }

            ItemDurabilitySystem.ServerModifyDurability(itemDevice, -DurabilityDecreasePerUse);
        }
        public override void ServerOnCharacterDeath(IItem item, bool isEquipped, out bool shouldDrop)
        {
            if (!isEquipped)
            {
                // not installed implants always drop on death
                shouldDrop = true;
                return;
            }

            // installed implants never drop on death
            shouldDrop = false;

            // reduce implant's durability on death
            var fraction        = MathHelper.Clamp(this.DurabilityFractionReduceOnDeath, 0, 1);
            var durabilityDelta = this.DurabilityMax * fraction;

            ItemDurabilitySystem.ServerModifyDurability(item,
                                                        delta: -durabilityDelta,
                                                        roundUp: false);
        }
Beispiel #20
0
        public virtual void ServerOnCharacterDeath(IItem item, bool isEquipped, out bool shouldDrop)
        {
            // only unequipped items will drop unless full loot system enabled
            shouldDrop = ItemConstants.ServerPvpIsFullLootEnabled ||
                         !isEquipped;

            if (!isEquipped)
            {
                return;
            }

            if (item.ProtoItem is IProtoItemWithDurability protoItemWithDurability)
            {
                // reduce equipped item's durability on death
                var durabilityDelta = protoItemWithDurability.DurabilityMax * DurabilityFractionReduceOnDeath;
                ItemDurabilitySystem.ServerModifyDurability(item,
                                                            delta: -durabilityDelta,
                                                            roundUp: false);
            }
        }
        // please note that requiredEnergyAmount is <= ushort.MaxValue
        private static bool ServerDeductEnergyChargeInternal(IDynamicWorldObject vehicle, uint requiredEnergyAmount)
        {
            if (requiredEnergyAmount <= 0)
            {
                return(true);
            }

            using var tempItemsList = SharedGetTempListFuelItemsForVehicle(vehicle);
            if (tempItemsList.Count == 0)
            {
                // there are no battery packs equipped
                return(false);
            }

            // deduct energy
            foreach (var item in tempItemsList.AsList())
            {
                var privateState = SharedGetPrivateState(item);
                var charge       = privateState.DurabilityCurrent;
                if (charge <= 0)
                {
                    // no charge there
                    continue;
                }

                if (charge >= requiredEnergyAmount)
                {
                    // there are more than enough charge available
                    ItemDurabilitySystem.ServerModifyDurability(item, -(int)requiredEnergyAmount);
                    return(true);
                }

                // use all the remaining charge in this item
                requiredEnergyAmount -= charge;
                ItemDurabilitySystem.ServerModifyDurability(item, -(int)charge);
            }

            // probably consumed but not enough energy (remaining requiredEnergyAmount > 0)
            return(false);
        }
        private void ServerRemote_RelocateStructure(IStaticWorldObject objectStructure, Vector2Ushort toPosition)
        {
            if (objectStructure.TilePosition == toPosition)
            {
                // relocation not required
                return;
            }

            var character = ServerRemoteContext.Character;

            if (!SharedValidateCanCharacterRelocateStructure(character,
                                                             objectStructure,
                                                             toPosition,
                                                             logErrors: true))
            {
                return;
            }

            Api.SafeInvoke(
                () => ServerStructureBeforeRelocating?.Invoke(character, objectStructure));

            Server.World.SetPosition(objectStructure, toPosition);
            ConstructionPlacementSystem.Instance.ServerNotifyOnStructurePlacedOrRelocated(objectStructure, character);

            Api.SafeInvoke(
                () => ServerStructureRelocated?.Invoke(character, objectStructure));

            // let's deduct the tool durability
            if (CreativeModeSystem.SharedIsInCreativeMode(character))
            {
                return;
            }

            // the item in hotbar is definitely a construction tool as it was validated above
            var itemConstructionTool = character.SharedGetPlayerSelectedHotbarItem();

            ItemDurabilitySystem.ServerModifyDurability(itemConstructionTool,
                                                        delta: -ToolDurabilityCostForStructureRelocation);
        }
        public static bool ConditionHasDeviceEquipped(DropItemContext context)
        {
            // Please note: checking this condition will also automatically deduct the device's durability.
            if (!context.HasCharacter)
            {
                return(false);
            }

            // find the device
            var itemDevice = context.Character.SharedGetPlayerContainerEquipment()
                             .GetItemsOfProto(protoItemKeiniteCollector)
                             .FirstOrDefault();

            if (itemDevice is null)
            {
                // don't have an equipped device
                return(false);
            }

            ItemDurabilitySystem.ServerModifyDurability(itemDevice, -DurabilityDecreasePerUse);
            return(true);
        }
Beispiel #24
0
        protected sealed override void ServerUpdate(ServerUpdateData data)
        {
            base.ServerUpdate(data);

            if (this.durabilityDecreasePerServerUpdate <= 0)
            {
                // non-degradeable
                return;
            }

            if (data.DeltaTime <= 0)
            {
                // not processed
                return;
            }

            // try to degrade durability over time
            var item  = data.GameObject;
            var owner = item.Container?.OwnerAsCharacter;

            if (owner == null ||
                !owner.IsOnline ||
                owner.SharedGetPlayerContainerEquipment() != item.Container)
            {
                // player offline or not an equipped item
                return;
            }

            var durabilityDecrease = this.durabilityDecreasePerServerUpdate;

            durabilityDecrease *= owner.SharedGetFinalStatMultiplier(StatName.ImplantDegradationSpeedMultiplier);
            ItemDurabilitySystem.ServerModifyDurability(item,
                                                        -(int)Math.Floor(durabilityDecrease));

            if (!item.IsDestroyed)
            {
                this.ServerUpdateInstalledImplant(data);
            }
        }
        protected override void ServerOnDegradeWeapon(
            ICharacter character,
            IItem weaponItem,
            IProtoItemWeapon protoWeapon,
            IReadOnlyList <IWorldObject> hitObjects)
        {
            if (hitObjects.Count == 0)
            {
                // no objects were hit
                return;
            }

            var decrease = this.DurabilityDecreasePerAction;

            foreach (var hitObject in hitObjects)
            {
                var protoObject = hitObject.ProtoWorldObject;
                if (protoObject is IProtoObjectWall ||
                    protoObject is IProtoObjectDoor ||
                    protoObject is IProtoObjectTradingStation)
                {
                    if (LandClaimSystem.SharedIsObjectInsideAnyArea((IStaticWorldObject)hitObject))
                    {
                        // hit a wall, door or station inside a land claim area - take a durability penalty
                        decrease = (ushort)Math.Min(
                            Math.Ceiling(decrease * this.DurabilityDecreaseMultiplierWhenHittingBuildings),
                            ushort.MaxValue);
                        break;
                    }
                }
            }

            ItemDurabilitySystem.ServerModifyDurability(
                weaponItem,
                delta: -decrease);
        }
 public virtual void ServerOnItemDamaged(IItem item, double damageApplied)
 {
     ItemDurabilitySystem.ServerModifyDurability(item, delta: -(int)damageApplied);
 }
Beispiel #27
0
        private void ServerGatheringSystemGatherHandler(ICharacter character, IStaticWorldObject worldObject)
        {
            if (!(worldObject.ProtoStaticWorldObject is ObjectCorpse))
            {
                return;
            }

            // corpse gathered!
            // find the device and vial
            var itemDevice = character.SharedGetPlayerContainerEquipment()
                             .GetItemsOfProto(this)
                             .FirstOrDefault();

            if (itemDevice == null)
            {
                // don't have an equipped device
                return;
            }

            var protoItemVialEmpty = GetProtoEntity <ItemVialEmpty>();

            // require at least one vial
            if (!character.ContainsItemsOfType(protoItemVialEmpty, requiredCount: 1))
            {
                // don't have an empty vial
                this.CallClient(character, _ => _.ClientRemote_NotEnoughEmptyVials());
                return;
            }

            var protoMob = (IProtoCharacterCore)worldObject.GetPublicState <ObjectCorpse.PublicState>()
                           .ProtoCharacterMob;
            var healthMax     = protoMob.StatDefaultHealthMax;
            var maxVialsToUse = (ushort)MathHelper.Clamp(Math.Floor(healthMax / 100.0),
                                                         min: 1,
                                                         max: 10);

            // destroy empty vial
            Server.Items.DestroyItemsOfType(
                character,
                protoItemVialEmpty,
                maxVialsToUse,
                out var destroyedEmptyVialsCount);

            if (destroyedEmptyVialsCount == 0)
            {
                // cannot destroy any empty vial (should be impossible)
                return;
            }

            // spawn biomaterial vials
            var createItemResult = Server.Items.CreateItem <ItemVialBiomaterial>(character,
                                                                                 count: destroyedEmptyVialsCount);

            var itemChangedCount = NotificationSystem.SharedGetItemsChangedCount(createItemResult);

            itemChangedCount.Add(protoItemVialEmpty, -(int)destroyedEmptyVialsCount);
            NotificationSystem.ServerSendItemsNotification(character, itemChangedCount);

            ItemDurabilitySystem.ServerModifyDurability(itemDevice, -DurabilityDecreasePerUse);
            Logger.Info("Biomaterial collected successfully with Biomaterial collector", character);
        }
        private void SharedOnStageCompleted()
        {
            if (Api.IsServer &&
                this.ItemCrowbarTool is not null)
            {
                // notify tool was used
                ServerItemUseObserver.NotifyItemUsed(this.Character, this.ItemCrowbarTool);

                // reduce tool durability
                ItemDurabilitySystem.ServerModifyDurability(this.ItemCrowbarTool, delta: -1);
            }

            this.currentStageDurationSeconds     = this.CalculateStageDurationSeconds(this.Character, isFirstStage: false);
            this.currentStageTimeRemainsSeconds += this.currentStageDurationSeconds;

            var oldStructurePoints = this.ObjectPublicState.StructurePointsCurrent;
            var newStructurePoints = Math.Max(
                0,
                oldStructurePoints - this.stageStructureRemoveValue);

            this.protoStructure.SharedOnDeconstructionStage(
                this.WorldObject,
                this.Character,
                oldStructurePoints,
                newStructurePoints);

            if (Api.IsClient || // client will simply always deconstruct until finished
                newStructurePoints > 0)
            {
                // deconstruction progressed
                if (Api.IsServer)
                {
                    Logger.Important(
                        $"Deconstruction progressed: {this.WorldObject} structure points: {newStructurePoints}/{this.structurePointsMax}; by {this.Character}");
                }

                this.UpdateProgress();

                if (Api.IsServer &&
                    this.ItemCrowbarTool is not null &&
                    this.ItemCrowbarTool.IsDestroyed)
                {
                    // tool was destroyed (durability 0)
                    this.AbortAction();
                    return;
                }

                return;
            }

            // deconstruction is completed
            if (Api.IsServer)
            {
                if (!(this.protoStructure is ProtoObjectConstructionSite))
                {
                    this.CharacterPrivateState.Skills.ServerAddSkillExperience <SkillBuilding>(
                        SkillBuilding.ExperienceAddWhenDeconstructionFinished);
                }

                Logger.Important(
                    $"Deconstruction completed: {this.WorldObject} structure points: {newStructurePoints}/{this.structurePointsMax}; by {this.Character}");
                this.ObjectPublicState.StructurePointsCurrent = newStructurePoints;
            }

            this.SetCompleted(isCancelled: false);
            DeconstructionSystem.SharedActionCompleted(this.Character, this);
        }
Beispiel #29
0
        private void ServerGatheringSystemGatherHandler(ICharacter character, IStaticWorldObject worldObject)
        {
            if (!(worldObject.ProtoStaticWorldObject is ObjectCorpse))
            {
                return;
            }

            // corpse looted
            // find the device and vial
            var itemDevice = character.SharedGetPlayerContainerEquipment()
                             .GetItemsOfProto(this)
                             .FirstOrDefault();

            if (itemDevice is null)
            {
                // don't have an equipped device
                return;
            }

            var protoItemVialEmpty = GetProtoEntity <ItemVialEmpty>();

            // require at least one vial
            if (!character.ContainsItemsOfType(protoItemVialEmpty, requiredCount: 1))
            {
                // don't have an empty vial
                this.CallClient(character, _ => _.ClientRemote_NotEnoughEmptyVials());
                return;
            }

            var protoMob = worldObject.GetPublicState <ObjectCorpse.PublicState>()
                           .ProtoCharacterMob;
            var healthMax     = protoMob.StatDefaultHealthMax;
            var maxVialsToUse = (ushort)MathHelper.Clamp(
                Math.Floor(protoMob.BiomaterialValueMultiplier * healthMax / 100.0),
                min: 1,
                max: 10);

            // destroy empty vial
            Server.Items.DestroyItemsOfType(
                character,
                protoItemVialEmpty,
                maxVialsToUse,
                out var destroyedEmptyVialsCount);

            if (destroyedEmptyVialsCount == 0)
            {
                // cannot destroy any empty vial (should be impossible)
                return;
            }

            // spawn biomaterial vials
            var protoItemVialBiomaterial = Api.GetProtoEntity <ItemVialBiomaterial>();
            var createItemResult         = Server.Items.CreateItem(protoItemVialBiomaterial,
                                                                   character,
                                                                   count: destroyedEmptyVialsCount);

            if (!createItemResult.IsEverythingCreated)
            {
                createItemResult.Rollback();
                var groundItemsContainer =
                    ObjectGroundItemsContainer.ServerTryGetOrCreateGroundContainerAtTileOrNeighbors(character,
                                                                                                    character.Tile);
                if (groundItemsContainer is null)
                {
                    Logger.Error("Not enough space around the player to drop a full vial");
                    // restore items
                    Server.Items.CreateItem(protoItemVialEmpty,
                                            character,
                                            destroyedEmptyVialsCount);
                    return;
                }

                createItemResult = Server.Items.CreateItem(protoItemVialBiomaterial,
                                                           groundItemsContainer,
                                                           count: destroyedEmptyVialsCount);
                if (!createItemResult.IsEverythingCreated)
                {
                    createItemResult.Rollback();
                    Logger.Error("Not enough space around the player to drop a full vial");
                    // restore items
                    Server.Items.CreateItem(protoItemVialEmpty,
                                            character,
                                            destroyedEmptyVialsCount);
                    return;
                }

                NotificationSystem.ServerSendNotificationNoSpaceInInventoryItemsDroppedToGround(character,
                                                                                                protoItemVialBiomaterial);
            }

            var itemChangedCount = NotificationSystem.SharedGetItemsChangedCount(createItemResult);

            itemChangedCount.Add(protoItemVialEmpty, -(int)destroyedEmptyVialsCount);
            NotificationSystem.ServerSendItemsNotification(character, itemChangedCount);

            ItemDurabilitySystem.ServerModifyDurability(itemDevice, -DurabilityDecreasePerUse);
            Logger.Info("Biomaterial collected successfully with Biomaterial collector", character);
        }
Beispiel #30
0
        private void SharedOnStageCompleted()
        {
            if (!this.ValidateRequiredItemsAvailable())
            {
                // don't have required items - cannot do building/repairing action
                this.AbortAction();
                return;
            }

            if (Api.IsServer)
            {
                // items are removing only on the Server-side
                this.Config.ServerDestroyRequiredItems(this.Character);

                // notify tool was used
                ServerItemUseObserver.NotifyItemUsed(this.Character, this.ItemConstructionTool);

                // reduce tool durability
                ItemDurabilitySystem.ServerModifyDurability(this.ItemConstructionTool, delta: -1);
            }

            this.currentStageDurationSeconds     = this.CalculateStageDurationSeconds(this.Character, isFirstStage: false);
            this.currentStageTimeRemainsSeconds += this.currentStageDurationSeconds;

            var currentStructurePoints = this.ObjectPublicState.StructurePointsCurrent;
            var newStructurePoints     = currentStructurePoints
                                         + this.stageStructureAddValue;

            // Please note: as we're using floating number (StructurePointsCurrent) to track the construction progress
            // it might cause some inaccuracy. In order to avoid this inaccuracy we're adding some tolerance.
            // The tolerance is also needed to handle the case when the blueprint was damaged only slightly.
            var completionTolerance = this.stageStructureAddValue / 2.0;

            // Please note: client will simply always construct until finished
            // Server will keep building stages until the completion tolerance reached.
            if ((Api.IsClient && currentStructurePoints < this.structurePointsMax) ||
                (Api.IsServer && newStructurePoints + completionTolerance < this.structurePointsMax))
            {
                // repairing/building is still possible - more stages are available
                if (Api.IsServer)
                {
                    this.ObjectPublicState.StructurePointsCurrent = (float)newStructurePoints;
                    Api.Logger.Important(
                        $"Building/repairing progressed: {this.WorldObject} structure points: {newStructurePoints}/{this.structurePointsMax}; by {this.Character}");

                    if (this.IsRepair)
                    {
                        ((IProtoObjectStructure)this.WorldObject.ProtoStaticWorldObject)
                        .ServerOnRepairStageFinished(this.WorldObject, this.Character);
                    }
                }

                this.UpdateProgress();

                if (!this.ValidateRequiredItemsAvailable())
                {
                    // don't have enough required items - cannot continue building/repairing action
                    this.AbortAction();
                    return;
                }

                if (Api.IsServer &&
                    this.ItemConstructionTool.IsDestroyed)
                {
                    // tool was destroyed (durability 0)
                    this.AbortAction();
                    return;
                }

                return;
            }

            // repairing/building is completed
            if (Api.IsServer)
            {
                newStructurePoints = this.structurePointsMax;
                Api.Logger.Important(
                    $"Building/repairing completed: {this.WorldObject} structure points: {newStructurePoints}/{this.structurePointsMax}; by {this.Character}");
                this.ObjectPublicState.StructurePointsCurrent = (float)newStructurePoints;

                if (this.IsRepair)
                {
                    ((IProtoObjectStructure)this.WorldObject.ProtoStaticWorldObject)
                    .ServerOnRepairStageFinished(this.WorldObject, this.Character);
                }

                if (this.ObjectPublicState is ConstructionSitePublicState constructionSiteState)
                {
                    constructionSiteState.LastBuildActionDoneByCharacter = this.Character;
                    var constructionProto = ProtoObjectConstructionSite.SharedGetConstructionProto(this.WorldObject);

                    // add skill experience for building
                    this.CharacterPrivateState.Skills.ServerAddSkillExperience <SkillBuilding>(
                        SkillBuilding.ExperienceAddWhenBuildingFinished
                        * constructionProto.BuildingSkillExperienceMultiplier);
                }
                else
                {
                    // add skill experience for repair
                    this.CharacterPrivateState.Skills.ServerAddSkillExperience <SkillBuilding>(
                        SkillBuilding.ExperienceAddWhenRepairFinished
                        * ((IProtoObjectStructure)this.WorldObject.ProtoGameObject).BuildingSkillExperienceMultiplier);
                }
            }

            this.SetCompleted(isCancelled: false);
            ConstructionSystem.SharedActionCompleted(this.Character, this);
        }