示例#1
0
        public bool ServerOnHackingStage(IStaticWorldObject worldObject, ICharacter character)
        {
            var publicState = GetPublicState(worldObject);

            publicState.HackingProgressPercent += 100 / this.HackingStagesNumber;
            if (publicState.HackingProgressPercent < 100)
            {
                return(true);
            }

            Server.World.DestroyObject(worldObject);

            var lootDroplist    = this.LootDroplist;
            var dropItemContext = new DropItemContext(character, worldObject);

            var dropItemResult = lootDroplist.TryDropToCharacterOrGround(
                character,
                character.TilePosition,
                dropItemContext,
                out _,
                probabilityMultiplier: this.ServerGetDropListProbabilityMultiplier(worldObject));

            if (dropItemResult.TotalCreatedCount > 0)
            {
                NotificationSystem.ServerSendItemsNotification(character, dropItemResult);
                var skillExperienceToAdd = SkillSearching.ExperienceAddWhenSearching
                                           * SearchSkillExperienceMultiplier;
                character.ServerAddSkillExperience <SkillSearching>(skillExperienceToAdd);
            }

            ServerObjectUseObserver.NotifyObjectUsed(character, worldObject);
            this.ServerOnHacked(character, worldObject);
            return(true);
        }
示例#2
0
        private bool ServerRemote_UseItem(IItem item)
        {
            var character = ServerRemoteContext.Character;

            this.ServerValidateItemForRemoteCall(item, character);

            var teleportObjects = Server.World
                                  .GetStaticWorldObjectsOfProto <TObjectTeleport>()
                                  .ToList();

            var knownTeleportPositions = TeleportsSystem.ServerGetDiscoveredTeleports(character);

            teleportObjects.RemoveAll(t => knownTeleportPositions.Contains(t.TilePosition));
            if (teleportObjects.Count == 0)
            {
                // no teleports to reveal
                return(false);
            }

            // reveal a single random teleport
            TeleportsSystem.ServerAddTeleportToDiscoveredList(character,
                                                              teleportObjects.TakeByRandom());

            Server.Items.SetCount(item, item.Count - 1);
            NotificationSystem.ServerSendItemsNotification(character, protoItem: this, deltaCount: -1);
            Logger.Important("Discovered a teleport with " + this.ShortId, character);
            return(true);
        }
示例#3
0
        public bool ServerGather(IStaticWorldObject worldObject, ICharacter character)
        {
            var lootDroplist = GetPublicState(worldObject).ProtoCharacterMob
                               .LootDroplist;

            var dropItemContext = new DropItemContext(character, worldObject);
            CreateItemResult dropItemResult;
            var attemptRemains = 200;

            do
            {
                dropItemResult = lootDroplist.TryDropToCharacterOrGround(character,
                                                                         character.TilePosition,
                                                                         dropItemContext,
                                                                         out _);
            }
            // ensure that at least something is spawned...
            // perhaps that's not a good idea, but we have an attempts limit
            while (dropItemResult.TotalCreatedCount == 0 &&
                   --attemptRemains > 0);

            // probably the attempts limit exceeded and nothing is spawned
            // we don't consider this as an issue as the probability of this is too rare

            Logger.Info(this + " was gathered", character);
            NotificationSystem.ServerSendItemsNotification(character, dropItemResult);
            character.ServerAddSkillExperience <SkillHunting>(SkillHunting.ExperienceForGather);
            Server.World.DestroyObject(worldObject);
            return(true);
        }
示例#4
0
        protected override bool ServerTryGatherByCharacter(ICharacter who, IStaticWorldObject vegetationObject)
        {
            var publicState = GetPublicState(vegetationObject);

            if (!publicState.IsSpoiled)
            {
                if (!base.ServerTryGatherByCharacter(who, vegetationObject))
                {
                    return(false);
                }
            }
            else // spoiled plant
            {
                var result = this.SpoiledGatherDroplist.TryDropToCharacterOrGround(
                    who,
                    who.TilePosition,
                    new DropItemContext(who, vegetationObject),
                    out var groundItemsContainer);
                if (result.TotalCreatedCount == 0)
                {
                    result.Rollback();
                    return(false);
                }

                Logger.Info(vegetationObject + " was gathered when spoiled", who);
                NotificationSystem.ServerSendItemsNotification(
                    who,
                    result,
                    exceptItemsContainer: groundItemsContainer);
            }

            // reset grown harvest state
            this.ServerClearHarvestState(vegetationObject, who);
            return(true);
        }
        public static void ServerSpawnEmptyBottle(ICharacter character, ushort count = 1)
        {
            var createItemResult = Server.Items.CreateItem <ItemBottleEmpty>(character, count);

            // notify the owner about the spawned empty bottle
            NotificationSystem.ServerSendItemsNotification(character, createItemResult);
        }
示例#6
0
        private void ServerRemote_Cut(IItem item)
        {
            var character = ServerRemoteContext.Character;

            this.ServerValidateItemForRemoteCall(item, character);

            var createItemResult = this.DropItemsList.TryDropToCharacter(
                character,
                new DropItemContext(character),
                probabilityMultiplier: RateResourcesGatherBasic.SharedValue);

            if (!createItemResult.IsEverythingCreated)
            {
                createItemResult.Rollback();
                return;
            }

            Logger.Important(character + " cut " + item);

            this.ServerNotifyItemUsed(character, item);
            // decrease item count
            Server.Items.SetCount(item, (ushort)(item.Count - 1));

            NotificationSystem.ServerSendItemsNotification(character, createItemResult);
        }
示例#7
0
        public static void ServerSpawnEmptyBottle(ICharacter character, ushort count = 1)
        {
            var createItemResult = Server.Items.CreateItem <ItemBottleEmpty>(character, count);

            if (createItemResult.IsEverythingCreated)
            {
                // notify the owner about the spawned empty bottle
                NotificationSystem.ServerSendItemsNotification(character, createItemResult);
                return;
            }

            createItemResult.Rollback();

            var groundContainer =
                ObjectGroundItemsContainer.ServerTryGetOrCreateGroundContainerAtTileOrNeighbors(character, character.Tile);

            if (groundContainer is null)
            {
                return;
            }

            createItemResult = Server.Items.CreateItem <ItemBottleEmpty>(groundContainer, count);
            if (createItemResult.IsEverythingCreated)
            {
                // notify the owner about the spawned empty bottle
                NotificationSystem.ServerSendNotificationNoSpaceInInventoryItemsDroppedToGround(
                    character,
                    createItemResult.ItemAmounts.FirstOrDefault().Key?.ProtoItem);
                return;
            }

            // BUG: cannot spawn an empty bottle either to player or to the ground. It's a rare case, but still possible.
            // It's better to return a false result and cancel the action such as drinking of the water.
            NotificationSystem.ServerSendNotificationNoSpaceInInventory(character);
        }
示例#8
0
        protected virtual bool ServerTryGatherByCharacter(ICharacter who, IStaticWorldObject vegetationObject)
        {
            var result = this.GatherDroplist.TryDropToCharacterOrGround(
                who,
                who.TilePosition,
                new DropItemContext(who, vegetationObject),
                out var groundItemsContainer,
                probabilityMultiplier: RateResourcesGatherBasic.SharedValue);

            if (result.TotalCreatedCount == 0)
            {
                return(false);
            }

            // even if at least one item is gathered it should pass
            // otherwise we will have an issue with berries and other stuff which cannot be rollback easily
            Logger.Info(vegetationObject + " was gathered", who);

            result.RemoveEntriesNotOwnedByCharacter(who);
            NotificationSystem.ServerSendItemsNotification(
                who,
                result,
                exceptItemsContainer: groundItemsContainer);
            return(true);
        }
        private void ServerOnMineralStageMined(
            WeaponFinalCache weaponCache,
            IStaticWorldObject mineralObject,
            int damageStage)
        {
            var byCharacter   = weaponCache.Character;
            var byWeaponProto = weaponCache.ProtoWeapon;

            Logger.Info(
                $"{mineralObject} current damage stage changed to {damageStage}. Dropping items for that stage",
                byCharacter);

            try
            {
                var dropItemsList   = this.DropItemsConfig.GetForStage(damageStage);
                var dropItemContext = new DropItemContext(byCharacter,
                                                          mineralObject,
                                                          byWeaponProto,
                                                          weaponCache.ProtoExplosive);

                var objectDrone = weaponCache.Drone;
                if (objectDrone != null)
                {
                    // drop resources into the internal storage of the drone
                    var storageItemsContainer = ((IProtoDrone)objectDrone.ProtoGameObject)
                                                .ServerGetStorageItemsContainer(objectDrone);
                    dropItemsList.TryDropToContainer(storageItemsContainer, dropItemContext);
                }
                else if (byWeaponProto is IProtoItemWeaponMelee)
                {
                    var result = dropItemsList.TryDropToCharacterOrGround(byCharacter,
                                                                          mineralObject.TilePosition,
                                                                          dropItemContext,
                                                                          groundContainer: out _);
                    if (result.TotalCreatedCount > 0)
                    {
                        NotificationSystem.ServerSendItemsNotification(byCharacter, result);
                    }
                }
                else
                {
                    // not a melee weapon or cannot drop to the character inventory - drop on the ground only
                    dropItemsList.TryDropToGround(mineralObject.TilePosition,
                                                  dropItemContext,
                                                  out _);
                }
            }
            finally
            {
                if (byWeaponProto is IProtoItemToolMining ||
                    weaponCache.ProtoExplosive is ObjectBombMining)
                {
                    // add experience proportional to the mineral structure points (effectively - for the time spent on mining)
                    var exp = SkillProspecting.ExperienceAddPerStructurePoint;
                    exp *= this.StructurePointsMax / this.DamageStagesCount;
                    byCharacter?.ServerAddSkillExperience <SkillProspecting>(exp);
                }
            }
        }
示例#10
0
        protected override void ServerOnStaticObjectDestroyedByCharacter(
            ICharacter byCharacter,
            IProtoItemWeapon byWeaponProto,
            IStaticWorldObject targetObject)
        {
            base.ServerOnStaticObjectDestroyedByCharacter(byCharacter, byWeaponProto, targetObject);

            // drop chance and gained experience depends on the vegetation growth stage
            var growthProgressFraction = this.GrowthStagesCount > 0
                                             ? GetPublicState(targetObject).GrowthStage / (double)this.GrowthStagesCount
                                             : 1;

            growthProgressFraction = MathHelper.Clamp(growthProgressFraction, 0.1, 1);

            try
            {
                var dropItemContext = new DropItemContext(byCharacter, targetObject);
                if (byWeaponProto is IProtoItemWeaponMelee)
                {
                    // a melee weapon - try drop items to character
                    var result = this.DroplistOnDestroy.TryDropToCharacter(
                        byCharacter,
                        dropItemContext,
                        probabilityMultiplier: growthProgressFraction);
                    if (result.IsEverythingCreated)
                    {
                        NotificationSystem.ServerSendItemsNotification(byCharacter, result);
                        return;
                    }

                    result.Rollback();
                }

                // not a melee weapon or cannot drop to character - drop on the ground only
                this.DroplistOnDestroy.TryDropToGround(
                    targetObject.TilePosition,
                    dropItemContext,
                    probabilityMultiplier: growthProgressFraction,
                    groundContainer: out _);
            }
            finally
            {
                if (byWeaponProto is IProtoItemToolWoodcutting)
                {
                    // add experience proportional to the tree structure points (effectively - for the time spent on woodcutting)
                    var exp = SkillWoodcutting.ExperienceAddPerStructurePoint;
                    exp *= this.StructurePointsMax * growthProgressFraction;
                    byCharacter?.ServerAddSkillExperience <SkillWoodcutting>(exp);
                }
            }
        }
        protected virtual bool ServerTryGatherByCharacter(ICharacter who, IStaticWorldObject vegetationObject)
        {
            var result = this.GatherDroplist.TryDropToCharacter(who, new DropItemContext(who, vegetationObject));

            if (result.IsEverythingCreated)
            {
                Logger.Info(vegetationObject + " was gathered", who);
                NotificationSystem.ServerSendItemsNotification(who, result);
                return(true);
            }

            result.Rollback();
            return(false);
        }
示例#12
0
        public bool ServerGather(IStaticWorldObject worldObject, ICharacter character)
        {
            //MOD
            PublicState publicState = GetPublicState(worldObject);

            var lootDroplist = publicState.ProtoCharacterMob.LootDroplist;

            var dropItemContext = new DropItemContext(character, worldObject);

            CreateItemResult dropItemResultFinal = new CreateItemResult();

            var level = publicState.Level;

            for (int i = 0; i < level; i++)
            {
                CreateItemResult dropItemResult;

                var attemptRemains = 200;
                do
                {
                    dropItemResult = lootDroplist.TryDropToCharacterOrGround(character,
                                                                             character.TilePosition,
                                                                             dropItemContext,
                                                                             out _);

                    dropItemResultFinal.MergeWith(dropItemResult);
                }
                // ensure that at least something is spawned...
                // perhaps that's not a good idea, but we have an attempts limit
                while (dropItemResult.TotalCreatedCount == 0 && --attemptRemains > 0);
            }

            if (!dropItemResultFinal.IsEverythingCreated)
            {
                Logger.Warning("Not all loot items were provided by "
                               + worldObject
                               + " - there is not enough space in inventory and around the character");
            }

            // probably the attempts limit exceeded and nothing is spawned
            // we don't consider this as an issue as the probability of this is too rare

            Logger.Info(worldObject + " was gathered", character);
            Server.World.DestroyObject(worldObject);

            NotificationSystem.ServerSendItemsNotification(character, dropItemResultFinal);
            character.ServerAddSkillExperience <SkillHunting>(SkillHunting.ExperienceForGather * level);
            return(true);
        }
示例#13
0
        protected override void ServerOnUse(ICharacter character, PlayerCharacterCurrentStats currentStats)
        {
            var createItemResult = this.droplist.TryDropToCharacterOrGround(character,
                                                                            character.TilePosition,
                                                                            new DropItemContext(character),
                                                                            out _);

            if (!createItemResult.IsEverythingCreated)
            {
                createItemResult.Rollback();
                throw new Exception("Not enough space");
            }

            NotificationSystem.ServerSendItemsNotification(character, createItemResult);
        }
示例#14
0
        private void ServerOnDamageStageIncreased(
            [CanBeNull] ICharacter byCharacter,
            IProtoItemWeapon byWeaponProto,
            IStaticWorldObject mineralObject,
            int damageStage)
        {
            Logger.Info(
                $"{mineralObject} current damage stage changed to {damageStage}. Dropping items for that stage",
                byCharacter);

            try
            {
                var dropItemsList   = this.DropItemsConfig.GetForStage(damageStage);
                var dropItemContext = new DropItemContext(byCharacter, mineralObject, byWeaponProto);

                if (byWeaponProto is IProtoItemWeaponMelee)
                {
                    var result = dropItemsList.TryDropToCharacter(byCharacter, dropItemContext);
                    if (result.IsEverythingCreated)
                    {
                        NotificationSystem.ServerSendItemsNotification(
                            byCharacter,
                            result);
                        return;
                    }

                    result.Rollback();
                }

                // not a melee weapon or cannot drop to the character inventory - drop on the ground only
                dropItemsList.TryDropToGround(mineralObject.TilePosition,
                                              dropItemContext,
                                              out _);
            }
            finally
            {
                if (byWeaponProto is IProtoItemToolMining)
                {
                    // add experience proportional to the mineral structure points (effectively - for the time spent on mining)
                    var exp = SkillMining.ExperienceAddPerStructurePoint;
                    exp *= this.StructurePointsMax / DamageStagesCount;
                    byCharacter?.ServerAddSkillExperience <SkillMining>(exp);
                }
            }
        }
示例#15
0
        public static bool ServerTryDeductBait(ICharacter character, IProtoItemFishingBait protoItemBait)
        {
            var itemBait = SharedFindBaitItem(character, protoItemBait);

            if (itemBait is null)
            {
                return(false);
            }

            // found a bait item of the required type, deduct the amount
            Server.Items.SetCount(itemBait,
                                  itemBait.Count - 1,
                                  byCharacter: character);

            NotificationSystem.ServerSendItemsNotification(character,
                                                           protoItemBait,
                                                           deltaCount: -1);

            return(true);
        }
示例#16
0
        private static bool ServerTryCreateOutputItems(CraftingQueue craftingQueue, CraftingQueueItem queueItem)
        {
            if (craftingQueue.IsContainerOutputFull &&
                craftingQueue.ContainerOutputLastStateHash == craftingQueue.ContainerOutput.StateHash)
            {
                return(false);
            }

            var recipe = queueItem.Recipe;
            var result = recipe.OutputItems.TrySpawnToContainer(craftingQueue.ContainerOutput);

            if (!result.IsEverythingCreated)
            {
                // cannot create items at specified container
                result.Rollback();
                craftingQueue.IsContainerOutputFull        = true;
                craftingQueue.ContainerOutputLastStateHash = craftingQueue.ContainerOutput.StateHash;
                return(false);
            }

            // something is created, assume crafting success
            craftingQueue.IsContainerOutputFull        = false;
            craftingQueue.ContainerOutputLastStateHash = craftingQueue.ContainerOutput.StateHash;

            if (recipe is Recipe.RecipeForManufacturing recipeManufacturing)
            {
                recipeManufacturing.ServerOnManufacturingCompleted(
                    ((ManufacturingCraftingQueue)craftingQueue).WorldObject,
                    craftingQueue);
            }

            if (craftingQueue is CharacterCraftingQueue characterCraftingQueue)
            {
                NotificationSystem.ServerSendItemsNotification(
                    characterCraftingQueue.Character,
                    result);
            }

            return(true);
        }
示例#17
0
        /// <summary>
        /// Please note - no validations are done!
        /// If the item is missing it will be not destroyed and passed.
        /// </summary>
        public static void ServerDestroyItems(
            ICharacter character,
            IReadOnlyList <ProtoItemWithCount> requiredItems)
        {
            var serverItemsService = Api.Server.Items;
            var itemsChangedCount  = new Dictionary <IProtoItem, int>();

            foreach (var requiredItem in requiredItems)
            {
                serverItemsService.DestroyItemsOfType(
                    character,
                    requiredItem.ProtoItem,
                    requiredItem.Count,
                    out var destroyedCount);

                if (destroyedCount > 0)
                {
                    itemsChangedCount[requiredItem.ProtoItem] = -(int)destroyedCount;
                }
            }

            NotificationSystem.ServerSendItemsNotification(character, itemsChangedCount);
        }
        public void ServerDestroyRequiredItems(ICharacter character)
        {
            if (CreativeModeSystem.SharedIsInCreativeMode(character))
            {
                Api.Logger.Important(character + " is in the admin mode - free construction is allowed.");
                return;
            }

            // assume all the validation has been done before this action
            var serverItemsService = Api.Server.Items;
            var itemsChangedCount  = new Dictionary <IProtoItem, int>();

            foreach (var requiredItem in this.RequiredItems)
            {
                serverItemsService.DestroyItemsOfType(
                    character,
                    requiredItem.ProtoItem,
                    requiredItem.Count,
                    out _);
                itemsChangedCount[requiredItem.ProtoItem] = -requiredItem.Count;
            }

            NotificationSystem.ServerSendItemsNotification(character, itemsChangedCount);
        }
示例#19
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);
        }
示例#20
0
        private static void ServerOnDroneReturnedToPlayer(IDynamicWorldObject worldObject)
        {
            var privateState = GetPrivateState(worldObject);
            var character    = privateState.CharacterOwner;

            CharacterDroneControlSystem.ServerDespawnDrone(worldObject, isReturnedToPlayer: true);

            var storageContainer = privateState.StorageItemsContainer;

            if (storageContainer.OccupiedSlotsCount == 0)
            {
                return;
            }

            // drop storage container contents to player
            // but first, move the drone item to its original slot (if possible)
            var characterContainerInventory = character.SharedGetPlayerContainerInventory();
            var characterContainerHotbar    = character.SharedGetPlayerContainerHotbar();

            var itemInFirstSlot = storageContainer.GetItemAtSlot(0);

            if (itemInFirstSlot is not null)
            {
                // item in the first slot is the drone's associated item
                // it could be destroyed in case the drone's HP dropped <= 1
                Server.Items.MoveOrSwapItem(itemInFirstSlot,
                                            privateState.IsStartedFromHotbarContainer
                                                ? characterContainerHotbar
                                                : characterContainerInventory,
                                            slotId: privateState.StartedFromSlotIndex,
                                            movedCount: out _);
            }

            var result = Server.Items.TryMoveAllItems(storageContainer, characterContainerInventory);

            try
            {
                if (storageContainer.OccupiedSlotsCount == 0)
                {
                    // all items moved from drone to player
                    return;
                }

                // try move remaining items to hotbar
                var resultToHotbar = Server.Items.TryMoveAllItems(storageContainer, characterContainerHotbar);
                result.MergeWith(resultToHotbar,
                                 areAllItemsMoved: resultToHotbar.AreAllItemMoved);

                if (storageContainer.OccupiedSlotsCount == 0)
                {
                    // all items moved from drone to player
                    return;
                }
            }
            finally
            {
                if (result.MovedItems.Count > 0)
                {
                    // notify player about the received items
                    NotificationSystem.ServerSendItemsNotification(
                        character,
                        result.MovedItems
                        .GroupBy(p => p.Key.ProtoItem)
                        .Where(p => !(p.Key is TItemDrone))
                        .ToDictionary(p => p.Key, p => p.Sum(v => v.Value)));
                }
            }

            // try to drop the remaining items on the ground
            var groundContainer = ObjectGroundItemsContainer
                                  .ServerTryGetOrCreateGroundContainerAtTileOrNeighbors(character, character.Tile);

            if (groundContainer is not null)
            {
                var result2 = Server.Items.TryMoveAllItems(storageContainer, groundContainer);
                if (result2.MovedItems.Count > 0)
                {
                    var protoItemForIcon = result2.MovedItems.First().Key.ProtoItem;

                    NotificationSystem.ServerSendNotificationNoSpaceInInventoryItemsDroppedToGround(
                        character,
                        protoItemForIcon);

                    // ensure that these items could be lifted only by their owner in PvE
                    WorldObjectClaimSystem.ServerTryClaim(groundContainer.OwnerAsStaticObject,
                                                          character,
                                                          WorldObjectClaimDuration.DroppedGoods);
                }
            }

            if (storageContainer.OccupiedSlotsCount == 0)
            {
                return;
            }

            Logger.Error("Not all items dropped on the ground from the drone storage: "
                         + worldObject
                         + " slots occupied: "
                         + storageContainer.OccupiedSlotsCount);
        }
示例#21
0
        private void ServerRemote_Uninstall(byte slotId)
        {
            var character   = ServerRemoteContext.Character;
            var worldObject = InteractionCheckerSystem.GetCurrentInteraction(character);

            this.VerifyGameObject((IStaticWorldObject)worldObject);

            var itemToUninstall = character.SharedGetPlayerContainerEquipment()
                                  .GetItemAtSlot(slotId);

            if (itemToUninstall == null)
            {
                throw new Exception("No implant installed");
            }

            var itemToUninstallProto      = (IProtoItemEquipmentImplant)itemToUninstall.ProtoItem;
            var biomaterialRequiredAmount = CreativeModeSystem.SharedIsInCreativeMode(character)
                                                ? (ushort)0
                                                : itemToUninstallProto.BiomaterialAmountRequiredToUninstall;

            if (!character.ContainsItemsOfType(ProtoItemBiomaterialVial.Value,
                                               requiredCount: biomaterialRequiredAmount) &&
                !CreativeModeSystem.SharedIsInCreativeMode(character))
            {
                throw new Exception("Not enough biomaterial vials");
            }

            // move to inventory
            if (!Server.Items.MoveOrSwapItem(itemToUninstall,
                                             character.SharedGetPlayerContainerInventory(),
                                             out _))
            {
                NotificationSystem.ServerSendNotificationNoSpaceInInventory(character);
                return;
            }

            if (biomaterialRequiredAmount > 0)
            {
                // destroy vials
                Server.Items.DestroyItemsOfType(character,
                                                ProtoItemBiomaterialVial.Value,
                                                countToDestroy: biomaterialRequiredAmount,
                                                out _);

                NotificationSystem.ServerSendItemsNotification(
                    character,
                    ProtoItemBiomaterialVial.Value,
                    -biomaterialRequiredAmount);
            }

            if (itemToUninstallProto is ItemImplantBroken)
            {
                // broken implant destroys on uninstall
                Server.Items.DestroyItem(itemToUninstall);
                NotificationSystem.ServerSendItemsNotification(
                    character,
                    itemToUninstallProto,
                    -1);
            }

            Logger.Info("Implant uninstalled: " + itemToUninstall);
        }
示例#22
0
        private void ServerRemote_Install(IItem itemToInstall, byte slotId)
        {
            var character   = ServerRemoteContext.Character;
            var worldObject = InteractionCheckerSystem.GetCurrentInteraction(character);

            this.VerifyGameObject((IStaticWorldObject)worldObject);

            var containerEquipment   = character.SharedGetPlayerContainerEquipment();
            var currentInstalledItem = containerEquipment.GetItemAtSlot(slotId);

            if (currentInstalledItem != null)
            {
                if (currentInstalledItem == itemToInstall)
                {
                    Logger.Info("The implant is already installed");
                    return;
                }

                throw new Exception("Please uninstall installed implant");
            }

            if (itemToInstall.Container.OwnerAsCharacter != character ||
                itemToInstall.Container == containerEquipment)
            {
                throw new Exception("The item to install must be in character containers (except equipment)");
            }

            if (!containerEquipment.ProtoItemsContainer.CanAddItem(
                    new CanAddItemContext(containerEquipment,
                                          itemToInstall,
                                          slotId,
                                          byCharacter: null,
                                          isExploratoryCheck: false)))
            {
                throw new Exception("Cannot install implant item there");
            }

            var itemToInstallProto = (IProtoItemEquipmentImplant)itemToInstall.ProtoItem;

            if (itemToInstallProto is ItemImplantBroken)
            {
                throw new Exception("Cannot install broken implant");
            }

            foreach (var equippedItem in containerEquipment.Items)
            {
                if (equippedItem.ProtoItem == itemToInstallProto)
                {
                    throw new Exception("Another implant of this type is already installed: " + itemToInstallProto);
                }
            }

            var biomaterialRequiredAmount = CreativeModeSystem.SharedIsInCreativeMode(character)
                                                ? (ushort)0
                                                : itemToInstallProto.BiomaterialAmountRequiredToInstall;

            if (!character.ContainsItemsOfType(ProtoItemBiomaterialVial.Value,
                                               requiredCount: biomaterialRequiredAmount))
            {
                throw new Exception("Not enough biomaterial vials");
            }

            if (!Server.Items.MoveOrSwapItem(itemToInstall,
                                             containerEquipment,
                                             out _,
                                             slotId: slotId))
            {
                throw new Exception("Unknown error - cannot move implant item to the player equipment");
            }

            if (biomaterialRequiredAmount > 0)
            {
                // destroy vials
                Server.Items.DestroyItemsOfType(character,
                                                ProtoItemBiomaterialVial.Value,
                                                countToDestroy: biomaterialRequiredAmount,
                                                out _);

                NotificationSystem.ServerSendItemsNotification(
                    character,
                    ProtoItemBiomaterialVial.Value,
                    -biomaterialRequiredAmount);
            }

            Logger.Info("Implant installed: " + itemToInstall);
        }
示例#23
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);
        }
示例#24
0
        private static int ServerTryConsumeWaterBottles(
            ICharacter character,
            int waterAmount,
            int waterCapacity,
            List <IItem> bottlesToConsume)
        {
            var serverItemsService    = Server.Items;
            var totalUsedBottlesCount = 0;
            var maxBottlesToConsume   = MaxBottlesToConsumePerRefill;

            foreach (var itemBottle in bottlesToConsume)
            {
                // check if character owns this item
                if (!character.ProtoCharacter
                    .SharedEnumerateAllContainers(character, includeEquipmentContainer: false)
                    .Any(c => c.Items.Contains(itemBottle)))
                {
                    throw new Exception("The character doesn't own " + itemBottle + " - cannot use it to reload");
                }

                int itemBottleCountToSubstract;

                var itemBottleCount = itemBottle.Count;
                if (itemBottleCount == 0)
                {
                    continue;
                }

                if (itemBottleCount > maxBottlesToConsume)
                {
                    itemBottleCount = (ushort)maxBottlesToConsume;
                }

                if (waterAmount + itemBottleCount * BottleWaterAmount
                    >= waterCapacity)
                {
                    // there are more than enough item count in that item stack to fully refill the watering can
                    itemBottleCountToSubstract =
                        (int)Math.Ceiling((waterCapacity - waterAmount) / (double)BottleWaterAmount);
                    waterAmount = waterCapacity;
                }
                else
                {
                    // consume full item stack
                    itemBottleCountToSubstract = itemBottleCount;
                    waterAmount += itemBottleCount * BottleWaterAmount;
                }

                if (itemBottleCountToSubstract > 0)
                {
                    maxBottlesToConsume   -= itemBottleCountToSubstract;
                    totalUsedBottlesCount += itemBottleCountToSubstract;

                    // reduce item count
                    var itemBottleNewCount = itemBottle.Count - itemBottleCountToSubstract;
                    serverItemsService.SetCount(
                        itemBottle,
                        itemBottleNewCount,
                        byCharacter: character,
                        isSendingUpdatesToPlayer: true);

                    // spawn empty bottles
                    ItemBottleEmpty.ServerSpawnEmptyBottle(character, (ushort)itemBottleCountToSubstract);
                }

                if (waterAmount >= waterCapacity)
                {
                    // fully refilled
                    break;
                }

                if (maxBottlesToConsume <= 0)
                {
                    // amount of bottles to consume exceeded
                    break;
                }
            }

            NotificationSystem.ServerSendItemsNotification(
                character,
                new Dictionary <IProtoItem, int>()
            {
                { GetProtoEntity <ItemBottleWater>(), -totalUsedBottlesCount }
            });

            return(waterAmount);
        }
示例#25
0
        private static double ServerTryConsumeFuelItems(
            ItemFuelRefillActionState state,
            ICharacter character,
            double fuelAmount,
            double fuelCapacity)
        {
            var maxItemsToConsumePerRefill = MaxItemsToConsumePerRefill;
            var consumedItems = new Dictionary <IProtoItem, int>();

            foreach (var itemToConsume in state.ItemsToConsumeForRefill)
            {
                // check if character owns this item
                if (!character.ProtoCharacter
                    .SharedEnumerateAllContainers(character, includeEquipmentContainer: false)
                    .Any(c => c.Items.Contains(itemToConsume)))
                {
                    throw new Exception("The character doesn't own " + itemToConsume + " - cannot use it to reload");
                }

                int itemToConsumeCountToSubstract;

                var itemToConsumeCount = itemToConsume.Count;
                if (itemToConsumeCount == 0)
                {
                    continue;
                }

                if (itemToConsumeCount > maxItemsToConsumePerRefill)
                {
                    itemToConsumeCount = (ushort)maxItemsToConsumePerRefill;
                }

                var fuelAmountPerItem = ((IProtoItemFuel)itemToConsume.ProtoItem).FuelAmount;
                if (fuelAmount + itemToConsumeCount * fuelAmountPerItem
                    >= fuelCapacity)
                {
                    // there are more than enough item count in that item stack to fully refill
                    itemToConsumeCountToSubstract = (int)Math.Ceiling((fuelCapacity - fuelAmount)
                                                                      / fuelAmountPerItem);
                    fuelAmount = fuelCapacity;
                }
                else
                {
                    // consume full item stack
                    itemToConsumeCountToSubstract = itemToConsumeCount;
                    fuelAmount += itemToConsumeCount * fuelAmountPerItem;
                }

                if (itemToConsumeCountToSubstract > 0)
                {
                    maxItemsToConsumePerRefill -= itemToConsumeCountToSubstract;

                    // reduce item count
                    var itemToConsumeNewCount = itemToConsume.Count - itemToConsumeCountToSubstract;
                    Server.Items.SetCount(
                        itemToConsume,
                        itemToConsumeNewCount,
                        byCharacter: character);

                    // ReSharper disable once PossibleNullReferenceException
                    consumedItems.Add(itemToConsume.ProtoItem, -itemToConsumeCountToSubstract);
                }

                if (fuelAmount >= fuelCapacity)
                {
                    // fully refilled
                    break;
                }

                if (maxItemsToConsumePerRefill <= 0)
                {
                    // amount of bottles to consume exceeded
                    break;
                }
            }

            NotificationSystem.ServerSendItemsNotification(character, consumedItems);
            return(fuelAmount);
        }
        public bool ServerGather(IStaticWorldObject worldObject, ICharacter character)
        {
            var privateState = GetPrivateState(worldObject);

            if (privateState.IsDropListSpawned)
            {
                // this loot container was already search - drop list was already spawned
                return(true);
            }

            // spawn items accordingly to the droplist
            privateState.IsDropListSpawned = true;
            var skillExperienceToAdd = SkillSearching.ExperienceAddWhenSearching
                                       * this.SearchingSkillExperienceMultiplier;

            var lootDroplist    = this.ServerGetLootDroplist(worldObject);
            var dropItemContext = new DropItemContext(character, worldObject);

            CreateItemResult dropItemResult;

            if (this.IsAutoTakeAll)
            {
                // try to simply pickup the content
                dropItemResult = lootDroplist.TryDropToCharacter(character,
                                                                 dropItemContext,
                                                                 sendNoFreeSpaceNotification: false);
                if (dropItemResult.IsEverythingCreated &&
                    dropItemResult.TotalCreatedCount > 0)
                {
                    NotificationSystem.ServerSendItemsNotification(character, dropItemResult);
                    Server.World.DestroyObject(worldObject); // destroy object after success pickup
                    character.ServerAddSkillExperience <SkillSearching>(skillExperienceToAdd);
                    ServerLootEventHelper.OnLootReceived(character, worldObject);
                    return(true);
                }

                dropItemResult.Rollback();
            }

            // create a container and drop items there
            var attemptRemains = 100;
            var itemsContainer = privateState.ItemsContainer;

            do
            {
                dropItemResult = lootDroplist.TryDropToContainer(itemsContainer, dropItemContext);
            }
            // ensure that at least something is spawned...
            // perhaps that's not a good idea, but we have an attempts limit
            while (dropItemResult.TotalCreatedCount == 0 &&
                   --attemptRemains > 0);

            Server.Items.SetSlotsCount(itemsContainer, itemsContainer.OccupiedSlotsCount);

            character.ServerAddSkillExperience <SkillSearching>(skillExperienceToAdd);
            ServerLootEventHelper.OnLootReceived(character, worldObject);

            Server.World.EnterPrivateScope(character, worldObject);

            // register private scope exit on interaction cancel
            InteractionCheckerSystem.SharedRegister(
                character,
                worldObject,
                finishAction: isAbort =>
            {
                if (worldObject.IsDestroyed)
                {
                    return;
                }

                Server.World.ExitPrivateScope(character, worldObject);

                if (isAbort)
                {
                    // notify client
                    this.CallClient(character, _ => _.ClientRemote_FinishInteraction(worldObject));
                }

                if (this.IsAutoDestroyWhenLooted)
                {
                    // container was closed - destroy it
                    Server.World.DestroyObject(worldObject);
                }
            });

            Logger.Important($"Started object interaction with {worldObject} for {character}");
            this.CallClient(character, _ => _.ClientRemote_OnContainerOpened(worldObject));
            return(true);
        }
示例#27
0
        protected override void ServerOnStaticObjectDestroyedByCharacter(
            ICharacter byCharacter,
            WeaponFinalCache weaponCache,
            IStaticWorldObject targetObject)
        {
            base.ServerOnStaticObjectDestroyedByCharacter(byCharacter, weaponCache, targetObject);

            // drop chance and gained experience depends on the vegetation growth stage
            var growthProgressFraction = this.SharedGetGrowthProgress(targetObject);

            growthProgressFraction = MathHelper.Clamp(growthProgressFraction, 0.1, 1);

            try
            {
                var dropItemsList   = this.DroplistOnDestroy;
                var dropItemContext = new DropItemContext(byCharacter,
                                                          targetObject,
                                                          weaponCache.ProtoWeapon,
                                                          weaponCache.ProtoExplosive);

                var objectDrone = weaponCache.Drone;
                if (objectDrone is not null)
                {
                    // drop resources into the internal storage of the drone
                    var storageItemsContainer = ((IProtoDrone)objectDrone.ProtoGameObject)
                                                .ServerGetStorageItemsContainer(objectDrone);
                    dropItemsList.TryDropToContainer(storageItemsContainer,
                                                     dropItemContext,
                                                     probabilityMultiplier: growthProgressFraction);
                }
                else if (weaponCache.ProtoWeapon is IProtoItemWeaponMelee)
                {
                    // a melee weapon - try drop items to character
                    var result = dropItemsList.TryDropToCharacterOrGround(
                        byCharacter,
                        targetObject.TilePosition,
                        dropItemContext,
                        groundContainer: out _,
                        probabilityMultiplier: growthProgressFraction);
                    if (result.TotalCreatedCount > 0)
                    {
                        NotificationSystem.ServerSendItemsNotification(byCharacter, result);
                    }
                }
                else
                {
                    // not a melee weapon or cannot drop to character - drop on the ground only
                    dropItemsList.TryDropToGround(
                        targetObject.TilePosition,
                        dropItemContext,
                        probabilityMultiplier: growthProgressFraction,
                        groundContainer: out _);
                }
            }
            finally
            {
                if (weaponCache.ProtoWeapon is IProtoItemToolWoodcutting)
                {
                    // add experience proportional to the vegetation structure points
                    // (effectively - for the time spent on woodcutting)
                    var exp = SkillLumbering.ExperienceAddPerStructurePoint;
                    exp *= this.StructurePointsMax * growthProgressFraction;
                    byCharacter?.ServerAddSkillExperience <SkillLumbering>(exp);
                }
            }
        }