proof_engine/narrative/
consequences.rs1use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
6pub struct Consequence {
7 pub action: String,
8 pub effects: Vec<Effect>,
9 pub timestamp: f64,
10 pub resolved: bool,
11}
12
13#[derive(Debug, Clone)]
14pub struct Effect {
15 pub target: String,
16 pub change_type: ChangeType,
17 pub magnitude: f32,
18 pub delayed_until: Option<f64>,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum ChangeType {
23 Reputation, Relationship, WorldState, QuestState, DialogueUnlock, AreaAccess, PriceChange,
24}
25
26#[derive(Debug, Clone)]
28pub struct ConsequenceTracker {
29 pub consequences: Vec<Consequence>,
30 pub reputation: HashMap<String, f32>,
31 pub world_flags: HashMap<String, bool>,
32}
33
34impl ConsequenceTracker {
35 pub fn new() -> Self {
36 Self { consequences: Vec::new(), reputation: HashMap::new(), world_flags: HashMap::new() }
37 }
38
39 pub fn record(&mut self, action: &str, effects: Vec<Effect>, time: f64) {
40 for effect in &effects {
41 match effect.change_type {
42 ChangeType::Reputation => {
43 *self.reputation.entry(effect.target.clone()).or_insert(0.0) += effect.magnitude;
44 }
45 ChangeType::WorldState => {
46 self.world_flags.insert(effect.target.clone(), effect.magnitude > 0.0);
47 }
48 _ => {}
49 }
50 }
51 self.consequences.push(Consequence { action: action.to_string(), effects, timestamp: time, resolved: false });
52 }
53
54 pub fn reputation_with(&self, faction: &str) -> f32 {
55 self.reputation.get(faction).copied().unwrap_or(0.0)
56 }
57
58 pub fn flag_set(&self, flag: &str) -> bool {
59 self.world_flags.get(flag).copied().unwrap_or(false)
60 }
61
62 pub fn pending_at(&self, time: f64) -> Vec<&Consequence> {
64 self.consequences.iter().filter(|c| !c.resolved && c.effects.iter().any(|e| e.delayed_until.map_or(false, |t| t <= time))).collect()
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_consequence_tracking() {
74 let mut tracker = ConsequenceTracker::new();
75 tracker.record("helped_farmer", vec![
76 Effect { target: "village".into(), change_type: ChangeType::Reputation, magnitude: 10.0, delayed_until: None },
77 ], 0.0);
78 assert_eq!(tracker.reputation_with("village"), 10.0);
79 }
80}