feat: add enchantsConflict and enchantApplies to Enchant
This commit is contained in:
1 parent
529853153c
commit
c3794851a2
1 file changed
+142
@@ -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)));
|
||||
|
||||
Reference in new issue
Block a user