From 0cc5b9527b5cea733357be8e979320011a241506 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 6 Sep 2026 22:50:59 +0200 Subject: [PATCH] feat: add xorshift and unitFloat --- core/src/Damage.cpp | 177 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 core/src/Damage.cpp diff --git a/core/src/Damage.cpp b/core/src/Damage.cpp new file mode 100644 index 0000000..ccfeb80 --- /dev/null +++ b/core/src/Damage.cpp @@ -0,0 +1,177 @@ +#include "vf/Damage.h" + +#include +#include + +namespace vf { + +namespace { + +uint32_t xorshift(uint32_t& state) { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + return state; +} + +float unitFloat(uint32_t& rng) { return static_cast(xorshift(rng)) / 4294967295.0f; } + +int rollBelow(uint32_t& rng, int bound) { + if (bound <= 1) return 0; + return static_cast(xorshift(rng) % static_cast(bound)); +} + +// Vanilla per-slot durability bases, scaled by the material factor below. +int slotDurabilityBase(Armor::Slot slot) { + switch (slot) { + case Armor::Slot::Helmet: return 11; + case Armor::Slot::Chestplate: return 16; + case Armor::Slot::Leggings: return 15; + case Armor::Slot::Boots: return 13; + default: return 0; + } +} + +int materialDurabilityFactor(Armor::Material material) { + switch (material) { + case Armor::Material::Leather: return 5; + case Armor::Material::Chain: return 15; + case Armor::Material::Iron: return 15; + case Armor::Material::Gold: return 7; + case Armor::Material::Diamond: return 33; + default: return 0; + } +} + +int protectionPointsFor(const EnchantSet& enchants, DamageType type) { + int points = 0; + int general = enchants.levelOf(EnchantKind::Protection); + if (general > 0 && type != DamageType::Void && type != DamageType::Starve) points += general; + if (isFireDamage(type)) points += 2 * enchants.levelOf(EnchantKind::FireProtection); + if (type == DamageType::Explosion) points += 2 * enchants.levelOf(EnchantKind::BlastProtection); + if (isProjectileDamage(type)) { + points += 2 * enchants.levelOf(EnchantKind::ProjectileProtection); + } + if (type == DamageType::Fall) points += 3 * enchants.levelOf(EnchantKind::FeatherFalling); + return points; +} + +bool unbreakingBlocksWear(int unbreakingLevel, uint32_t& rng) { + if (unbreakingLevel <= 0) return false; + float ignoreChance = 0.6f + 0.4f / static_cast(unbreakingLevel + 1); + return unitFloat(rng) < ignoreChance; +} + +Vec3 knockbackAlong(const Vec3& heading, float strength) { + Vec3 flat = normalize(Vec3{heading.x, 0.0f, heading.z}); + if (length(flat) <= 0.0f) flat = {1.0f, 0.0f, 0.0f}; + float horizontal = 0.4f + strength * 0.5f; + return {flat.x * horizontal, 0.4f, flat.z * horizontal}; +} + +} // namespace + +bool bypassesArmor(DamageType type) { + switch (type) { + case DamageType::Void: + case DamageType::Starve: + case DamageType::Suffocation: + case DamageType::Magic: + return true; + default: + return false; + } +} + +bool bypassesInvulnerability(DamageType type) { + return type == DamageType::Void || type == DamageType::Starve; +} + +bool bypassesMitigation(DamageType type) { return type == DamageType::Void; } + +bool isFireDamage(DamageType type) { + return type == DamageType::Fire || type == DamageType::Lava; +} + +bool isProjectileDamage(DamageType type) { return type == DamageType::Projectile; } + +HurtSource meleeSource(int attackerId, const Vec3& origin, bool byPlayer) { + HurtSource source; + source.type = DamageType::Melee; + source.origin = origin; + source.attackerId = attackerId; + source.ownerId = attackerId; + source.byPlayer = byPlayer; + return source; +} + +HurtSource projectileSource(int projectileId, int ownerId, const Vec3& origin, bool byPlayer) { + HurtSource source; + source.type = DamageType::Projectile; + source.origin = origin; + source.attackerId = projectileId; + source.ownerId = ownerId; + source.byPlayer = byPlayer; + return source; +} + +HurtSource environmentSource(DamageType type, const Vec3& origin) { + HurtSource source; + source.type = type; + source.origin = origin; + source.fiery = isFireDamage(type); + return source; +} + +Armor makeArmor(Armor::Material material, Armor::Slot slot) { + Armor piece; + piece.material = material; + piece.slot = slot; + piece.maxDurability = slotDurabilityBase(slot) * materialDurabilityFactor(material); + piece.durability = piece.maxDurability; + return piece; +} + +int armorPoints(const Armor& piece) { + if (!piece.worn()) return 0; + switch (piece.material) { + case Armor::Material::Leather: + switch (piece.slot) { + case Armor::Slot::Helmet: return 1; + case Armor::Slot::Chestplate: return 3; + case Armor::Slot::Leggings: return 2; + default: return 1; + } + case Armor::Material::Chain: + switch (piece.slot) { + case Armor::Slot::Helmet: return 2; + case Armor::Slot::Chestplate: return 5; + case Armor::Slot::Leggings: return 4; + default: return 1; + } + case Armor::Material::Iron: + switch (piece.slot) { + case Armor::Slot::Helmet: return 2; + case Armor::Slot::Chestplate: return 6; + case Armor::Slot::Leggings: return 5; + default: return 2; + } + case Armor::Material::Gold: + switch (piece.slot) { + case Armor::Slot::Helmet: return 2; + case Armor::Slot::Chestplate: return 5; + case Armor::Slot::Leggings: return 3; + default: return 1; + } + case Armor::Material::Diamond: + switch (piece.slot) { + case Armor::Slot::Helmet: return 3; + case Armor::Slot::Chestplate: return 8; + case Armor::Slot::Leggings: return 6; + default: return 3; + } + default: + return 0; + } +} +