feat: add enchantsConflict and enchantApplies to Enchant

This commit is contained in:
dualfroz committed 2026-09-07 16:46:07 +02:00
1 parent 529853153c
commit c3794851a2
1 file changed
+142
+142
View File
@@ -156,3 +156,145 @@ int enchantMaxCost(EnchantKind kind, int level) {
} }
} }
bool enchantsConflict(EnchantKind a, EnchantKind b) {
if (a == b) return false;
if (isProtectionFamily(a) && isProtectionFamily(b)) return true;
if (isDamageFamily(a) && isDamageFamily(b)) return true;
if ((a == EnchantKind::SilkTouch && b == EnchantKind::Fortune) ||
(a == EnchantKind::Fortune && b == EnchantKind::SilkTouch))
return true;
if ((a == EnchantKind::SilkTouch && b == EnchantKind::Looting) ||
(a == EnchantKind::Looting && b == EnchantKind::SilkTouch))
return true;
if ((a == EnchantKind::Infinity && b == EnchantKind::Mending) ||
(a == EnchantKind::Mending && b == EnchantKind::Infinity))
return true;
return false;
}
bool enchantApplies(EnchantKind kind, Enchantment::Target target) {
if (target == Enchantment::Target::Book) return true;
switch (kind) {
case EnchantKind::Unbreaking:
case EnchantKind::Mending:
return true;
case EnchantKind::Protection:
case EnchantKind::FireProtection:
case EnchantKind::BlastProtection:
case EnchantKind::ProjectileProtection:
case EnchantKind::Thorns:
return isArmourTarget(target);
case EnchantKind::FeatherFalling:
return target == Enchantment::Target::Boots;
case EnchantKind::Respiration:
case EnchantKind::AquaAffinity:
return target == Enchantment::Target::Helmet;
case EnchantKind::Knockback:
case EnchantKind::FireAspect:
case EnchantKind::Looting:
return target == Enchantment::Target::Sword;
case EnchantKind::Sharpness:
case EnchantKind::Smite:
case EnchantKind::BaneOfArthropods:
return target == Enchantment::Target::Sword || target == Enchantment::Target::Axe;
case EnchantKind::Efficiency:
case EnchantKind::SilkTouch:
case EnchantKind::Fortune:
return isDiggerTarget(target);
case EnchantKind::Power:
case EnchantKind::Punch:
case EnchantKind::Flame:
case EnchantKind::Infinity:
return target == Enchantment::Target::Bow;
default:
return false;
}
}
int enchantabilityOf(ItemId item) {
if (!isTool(item)) return 0;
switch (itemInfo(item).toolTier) {
case ToolTier::Wood: return 15;
case ToolTier::Stone: return 5;
case ToolTier::Iron: return 14;
case ToolTier::Gold: return 22;
case ToolTier::Diamond: return 10;
default: return 0;
}
}
Enchantment::Target enchantTargetOf(ItemId item) {
switch (itemInfo(item).toolType) {
case ToolType::Sword: return Enchantment::Target::Sword;
case ToolType::Axe: return Enchantment::Target::Axe;
case ToolType::Pickaxe: return Enchantment::Target::Pickaxe;
case ToolType::Shovel: return Enchantment::Target::Shovel;
default: return Enchantment::Target::Book;
}
}
int EnchantSet::levelOf(EnchantKind kind) const {
for (const Enchantment& entry : entries) {
if (entry.kind == kind) return entry.level;
}
return 0;
}
bool EnchantSet::conflictsWith(EnchantKind kind) const {
for (const Enchantment& entry : entries) {
if (enchantsConflict(entry.kind, kind)) return true;
}
return false;
}
bool addEnchant(EnchantSet& set, EnchantKind kind, int level) {
if (level < 1 || level > maxEnchantLevel(kind)) return false;
if (set.conflictsWith(kind)) return false;
for (Enchantment& entry : set.entries) {
if (entry.kind != kind) continue;
if (level <= entry.level) return false;
entry.level = level;
return true;
}
set.entries.push_back({kind, level});
return true;
}
bool removeEnchant(EnchantSet& set, EnchantKind kind) {
std::size_t before = set.entries.size();
set.entries.erase(std::remove_if(set.entries.begin(), set.entries.end(),
[kind](const Enchantment& e) { return e.kind == kind; }),
set.entries.end());
return set.entries.size() != before;
}
int bookshelfCount(const World& world, const Vec3i& tablePos) {
int found = 0;
for (int dx = -2; dx <= 2; ++dx) {
for (int dz = -2; dz <= 2; ++dz) {
if (std::max(std::abs(dx), std::abs(dz)) != 2) continue;
int stepX = dx > 0 ? 1 : (dx < 0 ? -1 : 0);
int stepZ = dz > 0 ? 1 : (dz < 0 ? -1 : 0);
for (int dy = 0; dy <= 1; ++dy) {
Block shelf = world.blockAt(tablePos.x + dx, tablePos.y + dy, tablePos.z + dz);
if (shelf != Block::Bookshelf) continue;
Block blocker =
world.blockAt(tablePos.x + stepX, tablePos.y + dy, tablePos.z + stepZ);
if (isOpaque(blocker)) continue;
++found;
}
}
}
return std::min(found, maxBookshelfPower);
}
EnchantSet rollEnchantments(Enchantment::Target target, int enchantability, int enchantLevel,
uint32_t& rng) {
EnchantSet chosen;
if (enchantLevel < 1) return chosen;
int bonus = enchantability / 4 + 1;
int modified = enchantLevel + rollBelow(rng, bonus) + rollBelow(rng, bonus) + 1;
float spread = 1.0f + (unitFloat(rng) + unitFloat(rng) - 1.0f) * 0.15f;
modified = std::max(1, static_cast<int>(std::lround(static_cast<float>(modified) * spread)));