public static CreateItemResult TryDropToCharacter(
            IReadOnlyDropItemsList dropItemsList,
            ICharacter character,
            bool sendNoFreeSpaceNotification,
            double probabilityMultiplier,
            DropItemContext context)
        {
            if (character == null)
            {
                return(new CreateItemResult()
                {
                    IsEverythingCreated = false
                });
            }

            var itemsService = Api.Server.Items;

            var result = dropItemsList.Execute(
                (protoItem, count) => itemsService.CreateItem(character, protoItem, count),
                context,
                probabilityMultiplier);

            if (sendNoFreeSpaceNotification &&
                !result.IsEverythingCreated)
            {
                NotificationSystem.ServerSendNotificationNoSpaceInInventory(character);
            }

            return(result);
        }
示例#2
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);
        }
示例#3
0
        protected override void SharedOnActionCompletedInternal(BottleRefillAction state, ICharacter character)
        {
            var itemBottle = state.ItemEmptyBottle;

            var requiredWaterProtoTile = state.WaterProtoTileToRefill;

            if (requiredWaterProtoTile == null)
            {
                throw new Exception("Impossible");
            }

            if (IsClient)
            {
                return;
            }

            var isNeedToReduceItemCount = true;

            if (itemBottle.Count == 1)
            {
                // destroy last item
                isNeedToReduceItemCount = false;
                Server.Items.SetCount(itemBottle,
                                      count: 0,
                                      byCharacter: character);
            }

            // spawn filled bottle item
            var result = requiredWaterProtoTile is TileWaterSea
                             ? Server.Items.CreateItem <ItemBottleWaterSalty>(character)
                             : Server.Items.CreateItem <ItemBottleWaterStale>(character);

            if (!result.IsEverythingCreated)
            {
                result.Rollback();
                NotificationSystem.ServerSendNotificationNoSpaceInInventory(character);
                return;
            }

            if (isNeedToReduceItemCount)
            {
                // reduce item count
                Server.Items.SetCount(itemBottle,
                                      itemBottle.Count - 1,
                                      byCharacter: character);
            }

            var itemsChangedCount = NotificationSystem.SharedGetItemsChangedCount(result);

            this.CallClient(character,
                            _ => _.ClientRemote_ActionCompleted(itemsChangedCount));
        }
示例#4
0
        /// <summary>
        /// Executed when a weapon must reload (after the reloading duration is completed).
        /// </summary>
        private static void SharedProcessWeaponReload(
            ICharacter character,
            WeaponState weaponState,
            out bool isAmmoTypeChanged)
        {
            var weaponReloadingState = weaponState.WeaponReloadingState;

            // remove weapon reloading state
            weaponState.WeaponReloadingState = null;

            var itemWeapon             = weaponReloadingState.Item;
            var itemWeaponProto        = (IProtoItemWeapon)itemWeapon.ProtoGameObject;
            var itemWeaponPrivateState = itemWeapon.GetPrivateState <WeaponPrivateState>();
            var weaponAmmoCount        = (int)itemWeaponPrivateState.AmmoCount;
            var weaponAmmoCapacity     = itemWeaponProto.AmmoCapacity;

            isAmmoTypeChanged = false;

            var selectedProtoItemAmmo = weaponReloadingState.ProtoItemAmmo;
            var currentProtoItemAmmo  = itemWeaponPrivateState.CurrentProtoItemAmmo;

            if (weaponAmmoCount > 0)
            {
                if (selectedProtoItemAmmo != currentProtoItemAmmo &&
                    weaponAmmoCount > 0)
                {
                    // unload current ammo
                    if (IsServer)
                    {
                        var targetContainers =
                            SharedGetTargetContainersForCharacterAmmo(character, isForAmmoUnloading: true);
                        var result = Server.Items.CreateItem(
                            protoItem: currentProtoItemAmmo,
                            new AggregatedItemsContainers(targetContainers),
                            count: (ushort)weaponAmmoCount);

                        if (!result.IsEverythingCreated)
                        {
                            // cannot unload current ammo - no space, try to unload to the ground
                            result.Rollback();

                            var tile            = Api.Server.World.GetTile(character.TilePosition);
                            var groundContainer = ObjectGroundItemsContainer
                                                  .ServerTryGetOrCreateGroundContainerAtTileOrNeighbors(character, tile);

                            if (groundContainer is null)
                            {
                                // cannot unload current ammo to the ground - no free space around character
                                NotificationSystem.ServerSendNotificationNoSpaceInInventory(character);
                                return;
                            }

                            result = Server.Items.CreateItem(
                                container: groundContainer,
                                protoItem: currentProtoItemAmmo,
                                count: (ushort)weaponAmmoCount);

                            if (!result.IsEverythingCreated)
                            {
                                // cannot unload current ammo to the ground - no space in ground containers near the character
                                result.Rollback();
                                NotificationSystem.ServerSendNotificationNoSpaceInInventory(character);
                                return;
                            }

                            // notify player that there were not enough space in inventory so the items were dropped to the ground
                            NotificationSystem.ServerSendNotificationNoSpaceInInventoryItemsDroppedToGround(
                                character,
                                result.ItemAmounts.First().Key?.ProtoItem);
                        }
                    }

                    Logger.Info(
                        $"Weapon ammo unloaded: {itemWeapon} -> {weaponAmmoCount} {currentProtoItemAmmo})",
                        character);

                    weaponAmmoCount = 0;
                    itemWeaponPrivateState.SetAmmoCount(0);
                }
                else // if the same ammo type is loaded
                if (weaponAmmoCount == weaponAmmoCapacity)
                {
                    // already completely loaded
                    Logger.Info(
                        $"Weapon reloading cancelled: {itemWeapon} - no reloading is required ({weaponAmmoCount}/{weaponAmmoCapacity} {selectedProtoItemAmmo})",
                        character);
                    return;
                }
            }
            else // if ammoCount == 0
            if (selectedProtoItemAmmo is null &&
                currentProtoItemAmmo is null)
            {
                Logger.Info(
                    $"Weapon reloading cancelled: {itemWeapon} - already unloaded ({weaponAmmoCount}/{weaponAmmoCapacity})",
                    character);
                return;
            }

            if (selectedProtoItemAmmo != null)
            {
                var selectedAmmoGroup = SharedGetCompatibleAmmoGroups(character, itemWeaponProto)
                                        .FirstOrDefault(g => g.Key == selectedProtoItemAmmo);

                if (selectedAmmoGroup is null)
                {
                    Logger.Warning(
                        $"Weapon reloading impossible: {itemWeapon} - no ammo of the required type ({selectedProtoItemAmmo})",
                        character);
                    return;
                }

                var ammoItems = SharedSelectAmmoItemsFromGroup(selectedAmmoGroup,
                                                               ammoCountNeed: weaponAmmoCapacity - weaponAmmoCount);
                foreach (var request in ammoItems)
                {
                    var itemAmmo = request.Item;
                    Api.Assert(itemAmmo.ProtoItem == selectedProtoItemAmmo, "Sanity check");

                    int ammoToSubstract;

                    var itemAmmoCount = itemAmmo.Count;
                    if (itemAmmoCount == 0)
                    {
                        continue;
                    }

                    if (request.Count != itemAmmoCount)
                    {
                        if (request.Count < itemAmmoCount)
                        {
                            itemAmmoCount = request.Count;
                        }
                        else if (IsServer)
                        {
                            Logger.Warning(
                                $"Trying to take more ammo to reload than player have: {itemAmmo} requested {request.Count}. Will reload as much as possible only.",
                                character);
                        }
                    }

                    if (weaponAmmoCount + itemAmmoCount >= weaponAmmoCapacity)
                    {
                        // there are more than enough ammo in that item stack to fully refill the weapon
                        ammoToSubstract = weaponAmmoCapacity - weaponAmmoCount;
                        weaponAmmoCount = weaponAmmoCapacity;
                    }
                    else
                    {
                        // consume full item stack
                        ammoToSubstract  = itemAmmoCount;
                        weaponAmmoCount += itemAmmoCount;
                    }

                    // reduce ammo item count
                    if (IsServer)
                    {
                        Server.Items.SetCount(
                            itemAmmo,
                            itemAmmo.Count - ammoToSubstract,
                            byCharacter: character);
                    }

                    if (weaponAmmoCount == weaponAmmoCapacity)
                    {
                        // the weapon is fully reloaded, no need to subtract ammo from the next ammo items
                        break;
                    }
                }
            }

            if (currentProtoItemAmmo != selectedProtoItemAmmo)
            {
                // another ammo type selected
                itemWeaponPrivateState.CurrentProtoItemAmmo = selectedProtoItemAmmo;
                // reset weapon cache (it will be re-calculated on next fire processing)
                weaponState.WeaponCache = null;
                isAmmoTypeChanged       = true;
            }

            if (weaponAmmoCount < 0 ||
                weaponAmmoCount > weaponAmmoCapacity)
            {
                Logger.Error(
                    "Something is completely wrong during reloading! Result ammo count is: " + weaponAmmoCount);
                weaponAmmoCount = 0;
            }

            itemWeaponPrivateState.SetAmmoCount((ushort)weaponAmmoCount);

            if (weaponAmmoCount == 0)
            {
                // weapon unloaded - and the log entry about this is already written (see above)
                return;
            }

            Logger.Info(
                $"Weapon reloaded: {itemWeapon} - ammo {weaponAmmoCount}/{weaponAmmoCapacity} {selectedProtoItemAmmo?.ToString() ?? "<no ammo>"}",
                character);

            if (IsServer)
            {
                ServerNotifyAboutReloading(character, weaponState, isFinished: true);
            }
            else
            {
                weaponState.ProtoWeapon.SoundPresetWeapon
                .PlaySound(WeaponSound.ReloadFinished,
                           character,
                           SoundConstants.VolumeWeapon);
            }
        }
示例#5
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);
        }