private static bool SharedTryFindItemsOfType( IItemsContainerProvider containers, IProtoItem requiredProtoItem, uint count, out List <IItem> result) { var countToFindRemains = (int)count; result = new List <IItem>(); foreach (var container in containers.ItemsContainers) { foreach (var item in container.Items) { if (item.ProtoItem != requiredProtoItem) { continue; } result.Add(item); countToFindRemains -= item.Count; if (countToFindRemains <= 0) { break; } } if (countToFindRemains <= 0) { break; } } return(countToFindRemains <= 0); }
private static void ServerDestroyInputItems( Recipe recipe, IItemsContainerProvider inputContainers, ushort countToCraft, bool isCreativeMode) { foreach (var inputItem in recipe.InputItems) { var countToDestroy = (ushort)(inputItem.Count * countToCraft); var inputItemProto = inputItem.ProtoItem; if (isCreativeMode) { CreativeModeAdjustCountToDestroy(inputItemProto, ref countToDestroy); if (countToDestroy == 0) { continue; } } ServerDestroyItemsOfType(inputContainers, inputItemProto, countToDestroy, out _); } void CreativeModeAdjustCountToDestroy(IProtoItem inputItemProto, ref ushort countToDestroy) { // destroy only available count var availableCount = 0; foreach (var c in inputContainers.Containers) { foreach (var item in c.Items) { if (ReferenceEquals(item.ProtoItem, inputItemProto)) { availableCount += item.Count; } } } if (availableCount == 0) { // nothing to destroy countToDestroy = 0; return; } if (countToDestroy > availableCount) { // limit count to destroy countToDestroy = (ushort)availableCount; } } }
private static bool SharedTryFindItemsOfType( IItemsContainerProvider containers, IProtoItem requiredProtoItem, uint count, out List <IItem> result, double minQualityFraction) { var countToFindRemains = (int)count; result = new List <IItem>(); foreach (var container in containers.ItemsContainers) { foreach (var item in container.Items) { if (item.ProtoItem != requiredProtoItem) { continue; } if (requiredProtoItem is IProtoItemWithDurability && ItemDurabilitySystem.SharedGetDurabilityFraction(item) < minQualityFraction) { // not enough durability continue; } if (requiredProtoItem is IProtoItemWithFreshness && ItemFreshnessSystem.SharedGetFreshnessFraction(item) < minQualityFraction) { // not enough durability continue; } result.Add(item); countToFindRemains -= item.Count; if (countToFindRemains <= 0) { break; } } if (countToFindRemains <= 0) { break; } } return(countToFindRemains <= 0); }
private static void ServerDestroyInputItems( Recipe recipe, IItemsContainerProvider inputContainers, ushort countToCraft, bool isAdminMode) { var itemsService = Api.Server.Items; foreach (var inputItem in recipe.InputItems) { var countToDestroy = (ushort)(inputItem.Count * countToCraft); var inputItemType = inputItem.ProtoItem; if (isAdminMode) { // destroy only available count var availableCount = inputContainers.Sum(c => c.Items.Where(i => i.ProtoItem == inputItemType).Sum(i => i.Count)); if (availableCount == 0) { // nothing to destroy continue; } if (countToDestroy > availableCount) { // limit count to destroy countToDestroy = (ushort)availableCount; } } itemsService.DestroyItemsOfType( inputContainers, inputItemType, countToDestroy, out _); } }
private static void ServerDestroyInputItems( Recipe recipe, IItemsContainerProvider inputContainers, ushort countToCraft, bool isCreativeMode) { foreach (var inputItem in recipe.InputItems) { var countToDestroy = (ushort)(inputItem.Count * countToCraft); var inputItemProto = inputItem.ProtoItem; if (isCreativeMode) { // destroy only available count var availableCount = inputContainers.Sum( c => c.Items.Where(i => ReferenceEquals(i.ProtoItem, inputItemProto)) .Sum(i => i.Count)); if (availableCount == 0) { // nothing to destroy continue; } if (countToDestroy > availableCount) { // limit count to destroy countToDestroy = (ushort)availableCount; } } ServerDestroyItemsOfType( inputContainers, inputItemProto, countToDestroy, out _); } }
private static void ServerDestroyItemsOfType( IItemsContainerProvider containers, IProtoItem protoItem, uint countToDestroy, out uint destroyedCount) { var serverItemsService = Api.Server.Items; if (protoItem is not IProtoItemWithFreshness) { // for items without freshness use the default approach serverItemsService.DestroyItemsOfType(containers, protoItem, countToDestroy, out destroyedCount); return; } // for items with freshness, gather all the available items and then sort them by freshness // prefer items with lower freshness first destroyedCount = 0; using var tempAllItemsOfType = Api.Shared.GetTempList <IItem>(); var allItemsOfType = tempAllItemsOfType.AsList(); foreach (var container in containers.Containers) { foreach (var item in container.Items) { if (ReferenceEquals(item.ProtoItem, protoItem)) { allItemsOfType.Add(item); } } } SortItems(protoItem, allItemsOfType); // loop from the slot with lowest freshness to the slow with the higher freshness // (if the freshness it the same, it should go right-to-left unless we got a sorting issue) for (var index = allItemsOfType.Count - 1; index >= 0; index--) { var item = allItemsOfType[index]; if (item.Count >= countToDestroy) { // remove full remained count destroyedCount += countToDestroy; serverItemsService.SetCount(item, (ushort)(item.Count - countToDestroy)); countToDestroy = 0; return; } // remove as much as we can destroyedCount += item.Count; countToDestroy -= item.Count; serverItemsService.DestroyItem(item); } if (destroyedCount != countToDestroy) { Api.Logger.Error( $"Cannot remove all required to remove count. Containers {containers.Containers.GetJoinedString()}, item type {protoItem}, count destroyed {destroyedCount}, count to destroy remains {countToDestroy - destroyedCount}"); }
private static TradingResult ServerExecuteTrade( TradingStationLot lot, IItemsContainerProvider sellerContainers, IItemsContainerProvider buyerContainers, bool isPlayerBuying) { // find items to buy by other party if (!SharedTryFindItemsOfType(sellerContainers, lot.ProtoItem, lot.LotQuantity, out var itemsToSell)) { return(isPlayerBuying ? TradingResult.ErrorNotEnoughItemsOnStation : TradingResult.ErrorNotEnoughItemsOnPlayer); } // try to find money to pay to other party var countCoinPenny = (uint)lot.PriceCoinPenny; var countCoinShiny = (uint)lot.PriceCoinShiny; if (!SharedTryFindItemsOfType(buyerContainers, ProtoItemCoinPenny.Value, countCoinPenny, out _) || !SharedTryFindItemsOfType(buyerContainers, ProtoItemCoinShiny.Value, countCoinShiny, out _)) { return(isPlayerBuying ? TradingResult.ErrorNotEnoughMoneyOnStation : TradingResult.ErrorNotEnoughMoneyOnPlayer); } // ensure there is enough space to store the sold items if (!ServerItems.CanCreateItem(buyerContainers, lot.ProtoItem, lot.LotQuantity)) { return(isPlayerBuying ? TradingResult.ErrorNotEnoughSpaceOnPlayerForPurchasedItem : TradingResult.ErrorNotEnoughSpaceOnStationForSoldItem); } // try create money in the source containers var sourceContainerResult = new CreateItemResult() { IsEverythingCreated = true }; if (lot.PriceCoinPenny > 0) { sourceContainerResult.MergeWith( ServerItems.CreateItem(ProtoItemCoinPenny.Value, sellerContainers, countCoinPenny)); } if (lot.PriceCoinShiny > 0) { sourceContainerResult.MergeWith( ServerItems.CreateItem(ProtoItemCoinShiny.Value, sellerContainers, countCoinShiny)); } if (!sourceContainerResult.IsEverythingCreated) { sourceContainerResult.Rollback(); // TODO: check this return(isPlayerBuying ? TradingResult.ErrorNotEnoughSpaceOnStationForSoldItem : TradingResult.ErrorNotEnoughSpaceOnPlayerForPurchasedItem); } // try moving (bought) items var itemsCountToDestroyRemains = (int)lot.LotQuantity; foreach (var item in itemsToSell) { if (itemsCountToDestroyRemains <= 0) { break; } ServerItems.MoveOrSwapItem(item, buyerContainers, out var movedCount, countToMove: (ushort)itemsCountToDestroyRemains); itemsCountToDestroyRemains -= movedCount; } if (itemsCountToDestroyRemains > 0) { // should be impossible Logger.Error( "Cannot move all sold items! But we've verified that the sellerContainers have them all..."); } if (countCoinPenny > 0) { ServerItems.DestroyItemsOfType(buyerContainers, ProtoItemCoinPenny.Value, countCoinPenny, out _); } if (countCoinShiny > 0) { ServerItems.DestroyItemsOfType(buyerContainers, ProtoItemCoinShiny.Value, countCoinShiny, out _); } Logger.Important($"Successfully completed trading transaction: {lot}"); return(TradingResult.Success); }