ck3_history_extractor/display/
timeline.rs

1use std::path::{Path, PathBuf};
2
3use serde::Serialize;
4
5use super::{
6    super::{
7        game_data::GameData,
8        jinja_env::TIMELINE_TEMPLATE_NAME,
9        parser::{GameRef, GameState},
10        structures::{Character, Culture, EntityRef, Faith, GameObjectDerived, Title},
11        types::GameString,
12    },
13    graph::{create_timeline_graph, Grapher},
14    renderer::{GetPath, Renderable},
15};
16
17/// An enum representing the difference in faith or culture between two realms, really just a wrapper around DerivedRef
18pub enum RealmDifference {
19    Faith(GameRef<Faith>),
20    Culture(GameRef<Culture>),
21}
22
23impl Serialize for RealmDifference {
24    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25    where
26        S: serde::Serializer,
27    {
28        match self {
29            RealmDifference::Faith(f) => f.serialize(serializer),
30            RealmDifference::Culture(c) => c.serialize(serializer),
31        }
32    }
33}
34
35/// A struct representing the timeline of the game
36#[derive(Serialize)]
37pub struct Timeline {
38    lifespans: Vec<(GameRef<Title>, Vec<(i16, i16)>)>,
39    latest_event: i16,
40    events: Vec<(
41        i16,
42        GameRef<Character>,
43        GameRef<Title>,
44        GameString,
45        RealmDifference,
46    )>, // (year, character, title, event_type<conquered, usurped, etc.
47}
48
49impl Timeline {
50    /// Creates a new timeline from the game state
51    pub fn new(
52        lifespans: Vec<(GameRef<Title>, Vec<(i16, i16)>)>,
53        latest_event: i16,
54        events: Vec<(
55            i16,
56            GameRef<Character>,
57            GameRef<Title>,
58            GameString,
59            RealmDifference,
60        )>,
61    ) -> Self {
62        Self {
63            lifespans,
64            latest_event,
65            events,
66        }
67    }
68}
69
70impl GameObjectDerived for Timeline {
71    fn get_name(&self) -> GameString {
72        GameString::from("Timeline")
73    }
74
75    fn get_references<E: From<EntityRef>, C: Extend<E>>(&self, collection: &mut C) {
76        for (title, _) in &self.lifespans {
77            collection.extend([E::from(title.clone().into())]);
78        }
79
80        for (_, char, _, _, difference) in &self.events {
81            collection.extend([E::from(char.clone().into())]);
82            match difference {
83                RealmDifference::Faith(f) => collection.extend([E::from(f.clone().into())]),
84                RealmDifference::Culture(c) => collection.extend([E::from(c.clone().into())]),
85            }
86        }
87    }
88}
89
90impl GetPath for Timeline {
91    fn get_path(&self, path: &Path) -> PathBuf {
92        path.join("timeline.html")
93    }
94}
95
96impl Renderable for Timeline {
97    fn get_template() -> &'static str {
98        TIMELINE_TEMPLATE_NAME
99    }
100
101    fn render(&self, path: &Path, _: &GameState, grapher: Option<&Grapher>, _: &GameData) {
102        if grapher.is_some() {
103            create_timeline_graph(
104                &self.lifespans,
105                self.latest_event,
106                path.join("timeline.svg"),
107            );
108        }
109    }
110}