feat: add xorshift and unitFloat

This commit is contained in:
dualfroz committed 2026-09-06 22:50:59 +02:00
1 parent 2e76ff9143
commit 0cc5b9527b
1 file changed
+177
+177
View File
@@ -0,0 +1,177 @@
#include "vf/Damage.h"
#include <algorithm>
#include <cmath>
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<float>(xorshift(rng)) / 4294967295.0f; }
int rollBelow(uint32_t& rng, int bound) {
if (bound <= 1) return 0;
return static_cast<int>(xorshift(rng) % static_cast<uint32_t>(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<float>(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;
}
}