proof-engine 0.2.3

Real-time graphics from math: glyphs and particles moved by ODEs, strange attractors and force fields, drawn with HDR bloom on OpenGL.
Documentation

// ── Final Loot Utilities ──────────────────────────────────────────────────────

pub fn item_level_bracket(ilvl: u32) -> &'static str {
    if ilvl >= 90 { "Endgame" }
    else if ilvl >= 70 { "High" }
    else if ilvl >= 50 { "Mid" }
    else if ilvl >= 30 { "Low-Mid" }
    else { "Starter" }
}

pub fn recommended_zone_ilvl(player_level: u32) -> u32 { player_level.saturating_sub(5) }
pub fn max_zone_ilvl(player_level: u32) -> u32 { player_level + 5 }
pub fn base_drop_chance(enemy_level: u32, player_level: u32) -> f32 {
    let diff = enemy_level as i32 - player_level as i32;
    let base = 0.15f32;
    if diff > 5 { base * 1.5 } else if diff < -10 { base * 0.5 } else { base }
}
pub fn item_sell_value(base_value: f32, rarity: &ItemRarity, durability_pct: f32) -> f32 {
    base_value * rarity_value_multiplier(rarity) * 0.3 * (durability_pct / 100.0).max(0.1)
}
pub fn max_affix_count(ilvl: u32) -> u32 { if ilvl >= 80 { 6 } else if ilvl >= 50 { 4 } else { 2 } }
pub fn loot_seed_from_entity(entity_id: u32, zone_id: u32, timestamp: u64) -> u64 {
    (entity_id as u64).wrapping_mul(0x517CC1B727220A95).wrapping_add(zone_id as u64).wrapping_add(timestamp)
}
pub fn normalize_weights(weights: &mut Vec<f32>) {
    let total: f32 = weights.iter().sum();
    if total > 0.0 { for w in weights.iter_mut() { *w /= total; } }
}
pub fn pick_weighted_index(weights: &[f32], roll: f32) -> usize {
    let mut acc = 0.0f32;
    for (i, &w) in weights.iter().enumerate() {
        acc += w;
        if roll <= acc { return i; }
    }
    weights.len().saturating_sub(1)
}
pub fn clamp_item_level(ilvl: u32, zone_min: u32, zone_max: u32) -> u32 { ilvl.clamp(zone_min, zone_max) }