use bevy::prelude::Resource;
use bloodstain::BloodSettings;
#[derive(Resource, Clone, Debug, PartialEq)]
pub struct WetSettings {
pub drip_rate: f32,
pub spread_rate: f32,
pub dry_ticks: u32,
pub absorbency: f32,
pub max_canvas_updates_per_tick: u32,
pub humidity: f32,
}
impl Default for WetSettings {
fn default() -> Self {
Self {
drip_rate: 0.35,
spread_rate: 0.08,
dry_ticks: 1800,
absorbency: 0.15,
max_canvas_updates_per_tick: 4,
humidity: 0.4,
}
}
}
impl WetSettings {
pub(crate) fn dry_span(&self) -> u32 {
self.dry_ticks.clamp(1, u16::MAX as u32)
}
pub(crate) fn drip_threshold(&self) -> u8 {
let t = (self.drip_rate.clamp(0.0, 1.0) * 255.0).round();
(t as u32).clamp(1, 255) as u8
}
pub(crate) fn absorbed_by(&self, age: u32) -> u32 {
let span = self.dry_span();
let total = (self.absorbency.clamp(0.0, 1.0) * 255.0).round() as u32;
let a = age.min(span);
((a as u64 * total as u64) / span as u64) as u32
}
pub fn blood(&self) -> BloodSettings {
BloodSettings { humidity: self.humidity, ..BloodSettings::default() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_shipped_dials_are_the_contract() {
let s = WetSettings::default();
assert_eq!(s.drip_rate, 0.35);
assert_eq!(s.spread_rate, 0.08);
assert_eq!(s.dry_ticks, 1800);
assert_eq!(s.absorbency, 0.15);
assert_eq!(s.max_canvas_updates_per_tick, 4);
assert_eq!(s.humidity, 0.4);
}
#[test]
fn absorption_is_cumulative_and_lands_on_its_stated_total() {
let s = WetSettings::default();
assert_eq!(s.absorbed_by(0), 0);
assert_eq!(s.absorbed_by(s.dry_ticks), 38);
let mut sum = 0;
for age in 0..s.dry_ticks {
let d = s.absorbed_by(age + 1) - s.absorbed_by(age);
sum += d;
}
assert_eq!(sum, s.absorbed_by(s.dry_ticks));
}
#[test]
fn the_drip_threshold_is_never_zero() {
let mut s = WetSettings::default();
assert_eq!(s.drip_threshold(), 89);
s.drip_rate = 0.0;
assert_eq!(s.drip_threshold(), 1);
s.drip_rate = 5.0;
assert_eq!(s.drip_threshold(), 255);
}
#[test]
fn humidity_reaches_the_blood_model_and_nothing_else_is_invented() {
let s = WetSettings { humidity: 0.8, ..Default::default() };
let b = s.blood();
assert_eq!(b.humidity, 0.8);
assert_eq!(b.wet_roughness, BloodSettings::default().wet_roughness);
assert_eq!(b.dry_roughness, BloodSettings::default().dry_roughness);
}
}