feat: add transferAll and splitOff to ItemStack
This commit is contained in:
1 parent
0bb301ea22
commit
c29b9dba4a
1 file changed
+160
@@ -158,3 +158,163 @@ StackTransfer transferStack(MetaStack& from, MetaStack& into, int amount) {
|
||||
return transfer;
|
||||
}
|
||||
|
||||
StackTransfer transferAll(MetaStack& from, MetaStack& into) {
|
||||
return transferStack(from, into, from.count);
|
||||
}
|
||||
|
||||
MetaStack splitOff(MetaStack& stack, int amount) {
|
||||
MetaStack taken;
|
||||
if (stack.empty() || amount <= 0) return taken;
|
||||
int moved = std::min(amount, stack.count);
|
||||
taken.item = stack.item;
|
||||
taken.meta = stack.meta;
|
||||
taken.count = moved;
|
||||
stack.count -= moved;
|
||||
if (stack.count <= 0) stack.clear();
|
||||
return taken;
|
||||
}
|
||||
|
||||
MetaStack splitHalf(MetaStack& stack) {
|
||||
if (stack.empty()) return MetaStack{};
|
||||
return splitOff(stack, (stack.count + 1) / 2);
|
||||
}
|
||||
|
||||
int defragmentStacks(std::vector<MetaStack>& stacks) {
|
||||
int freedBefore = 0;
|
||||
for (const MetaStack& stack : stacks) {
|
||||
if (stack.empty()) ++freedBefore;
|
||||
}
|
||||
|
||||
for (std::size_t target = 0; target < stacks.size(); ++target) {
|
||||
if (stacks[target].empty() || stacks[target].full()) continue;
|
||||
for (std::size_t source = target + 1; source < stacks.size(); ++source) {
|
||||
if (stacks[source].empty()) continue;
|
||||
if (!stacksMergeable(stacks[target], stacks[source])) continue;
|
||||
transferAll(stacks[source], stacks[target]);
|
||||
if (stacks[target].full()) break;
|
||||
}
|
||||
}
|
||||
|
||||
std::stable_partition(stacks.begin(), stacks.end(),
|
||||
[](const MetaStack& stack) { return !stack.empty(); });
|
||||
|
||||
int freedAfter = 0;
|
||||
for (const MetaStack& stack : stacks) {
|
||||
if (stack.empty()) ++freedAfter;
|
||||
}
|
||||
return freedAfter - freedBefore;
|
||||
}
|
||||
|
||||
int totalCountOf(const std::vector<MetaStack>& stacks, ItemId item) {
|
||||
int total = 0;
|
||||
for (const MetaStack& stack : stacks) {
|
||||
if (!stack.empty() && stack.item == item) total += stack.count;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
bool stackOrderLess(const MetaStack& a, const MetaStack& b) {
|
||||
if (a.empty() != b.empty()) return b.empty();
|
||||
if (a.empty()) return false;
|
||||
if (a.item != b.item) return a.item < b.item;
|
||||
bool aWorn = a.meta.durability.used > 0;
|
||||
bool bWorn = b.meta.durability.used > 0;
|
||||
if (aWorn != bWorn) return bWorn;
|
||||
if (a.count != b.count) return a.count > b.count;
|
||||
return a.meta.customName < b.meta.customName;
|
||||
}
|
||||
|
||||
void sortStacks(std::vector<MetaStack>& stacks) {
|
||||
std::stable_sort(stacks.begin(), stacks.end(), stackOrderLess);
|
||||
}
|
||||
|
||||
uint32_t stackRandom(uint32_t& state) {
|
||||
if (state == 0) state = 0x9e3779b9u;
|
||||
state ^= state << 13;
|
||||
state ^= state >> 17;
|
||||
state ^= state << 5;
|
||||
return state;
|
||||
}
|
||||
|
||||
bool unbreakingSkipsWear(int unbreakingLevel, bool armorPiece, uint32_t& rng) {
|
||||
if (unbreakingLevel <= 0) return false;
|
||||
float levels = static_cast<float>(unbreakingLevel + 1);
|
||||
float ignoreChance = armorPiece ? 0.6f + 0.4f / levels
|
||||
: static_cast<float>(unbreakingLevel) / levels;
|
||||
float roll = static_cast<float>(stackRandom(rng)) / 4294967295.0f;
|
||||
return roll < ignoreChance;
|
||||
}
|
||||
|
||||
WearResult damageStack(MetaStack& stack, int amount, uint32_t& rng) {
|
||||
if (stack.empty() || !stack.meta.durability.damageable()) return WearResult::NotDamageable;
|
||||
if (stack.meta.unbreakable || amount <= 0) return WearResult::Absorbed;
|
||||
|
||||
int unbreaking = stack.meta.enchants.levelOf(EnchantKind::Unbreaking);
|
||||
int applied = 0;
|
||||
for (int i = 0; i < amount; ++i) {
|
||||
if (unbreakingSkipsWear(unbreaking, false, rng)) continue;
|
||||
++applied;
|
||||
}
|
||||
if (applied == 0) return WearResult::Absorbed;
|
||||
|
||||
stack.meta.durability.used += applied;
|
||||
if (!stack.meta.durability.broken()) return WearResult::Damaged;
|
||||
|
||||
if (stack.meta.enchants.has(EnchantKind::Mending)) {
|
||||
stack.meta.durability.used = stack.meta.durability.max - 1;
|
||||
return WearResult::Survived;
|
||||
}
|
||||
stack.clear();
|
||||
return WearResult::Broke;
|
||||
}
|
||||
|
||||
int mendingRepair(MetaStack& stack, int experience) {
|
||||
if (stack.empty() || experience <= 0) return 0;
|
||||
if (!stack.meta.durability.damageable()) return 0;
|
||||
if (!stack.meta.enchants.has(EnchantKind::Mending)) return 0;
|
||||
int repair = std::min(experience * 2, stack.meta.durability.used);
|
||||
stack.meta.durability.used -= repair;
|
||||
return repair;
|
||||
}
|
||||
|
||||
MetaStack craftingRemainder(const MetaStack& ingredient) {
|
||||
if (ingredient.empty()) return MetaStack{};
|
||||
if (!ingredient.meta.durability.damageable()) return MetaStack{};
|
||||
|
||||
MetaStack leftover = ingredient;
|
||||
leftover.count = 1;
|
||||
if (leftover.meta.unbreakable) return leftover;
|
||||
leftover.meta.durability.used += 1;
|
||||
if (leftover.meta.durability.broken()) return MetaStack{};
|
||||
return leftover;
|
||||
}
|
||||
|
||||
ItemSlot toItemSlot(const MetaStack& stack) {
|
||||
if (stack.empty()) return ItemSlot{};
|
||||
ItemSlot slot;
|
||||
slot.item = stack.item;
|
||||
slot.count = stack.count;
|
||||
slot.durability = stack.meta.durability.remaining();
|
||||
return slot;
|
||||
}
|
||||
|
||||
MetaStack fromItemSlot(const ItemSlot& slot) {
|
||||
MetaStack stack;
|
||||
if (slot.empty()) return stack;
|
||||
stack.item = slot.item;
|
||||
stack.count = slot.count;
|
||||
int max = isTool(slot.item) ? toolMaxDurability(slot.item) : 0;
|
||||
if (max > 0) {
|
||||
int left = std::min(std::max(slot.durability, 0), max);
|
||||
stack.meta.durability = {max - left, max};
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
NbtTag stackToNbt(const MetaStack& stack) {
|
||||
NbtTag tag = NbtTag::makeCompound();
|
||||
if (stack.empty()) {
|
||||
tag.put("Id", NbtTag::makeShort(0));
|
||||
return tag;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user