fish_lib/data/
location_data.rs

1use crate::data::season_data::SeasonData;
2use crate::enums::season::Season;
3use chrono::{DateTime, Utc};
4use chrono_tz::Tz;
5use serde::{Deserialize, Serialize};
6
7const SECONDS_PER_YEAR: f64 = 31_556_925.190_8;
8
9#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
10pub struct LocationData {
11    #[serde(skip, default)]
12    pub id: i32,
13    pub name: String,
14    pub timezone: Tz,
15    pub weather_seed: u32,
16    pub spring: SeasonData,
17    pub summer: SeasonData,
18    pub autumn: SeasonData,
19    pub winter: SeasonData,
20    #[serde(default)]
21    /// The IDs of the locations that need to be unlocked before this can
22    pub required_locations_unlocked: Vec<i32>,
23    #[serde(default)]
24    /// The IDs of the species that need to be caught before this location can be unlocked
25    pub required_species_caught: Vec<i32>,
26}
27
28impl LocationData {
29    fn season_index_and_progress(&self, time: DateTime<Tz>, time_multiplier: f32) -> (usize, f64) {
30        let year_progress = (time.timestamp() as f64 * time_multiplier as f64) % SECONDS_PER_YEAR
31            / SECONDS_PER_YEAR;
32
33        let current_season = year_progress * 4.0;
34        let season_index = current_season.floor() as usize;
35        let season_progress = current_season % 1.0;
36
37        (season_index, season_progress)
38    }
39
40    pub fn current_season_data(&self, time: DateTime<Tz>, time_multiplier: f32) -> SeasonData {
41        let (index, progress) = self.season_index_and_progress(time, time_multiplier);
42
43        let (prev_data, current_data, next_data) = match index {
44            0 => (&self.winter, &self.spring, &self.summer),
45            1 => (&self.spring, &self.summer, &self.autumn),
46            2 => (&self.summer, &self.autumn, &self.winter),
47            3 => (&self.autumn, &self.winter, &self.spring),
48            _ => unreachable!(),
49        };
50
51        if progress < 0.5 {
52            let adjusted_progress = progress * 2.0;
53            let start = prev_data.interpolate(current_data, 0.5);
54            start.interpolate(current_data, adjusted_progress as f32)
55        } else {
56            let adjusted_progress = (progress - 0.5) * 2.0;
57            let start = current_data.interpolate(next_data, 0.5);
58            current_data.interpolate(&start, adjusted_progress as f32)
59        }
60    }
61
62    pub fn current_season(&self, time: DateTime<Tz>, time_multiplier: f32) -> (Season, f64) {
63        let (index, progress) = self.season_index_and_progress(time, time_multiplier);
64        let season = Season::from_index(index);
65        (season, progress)
66    }
67
68    pub fn full_season_information(
69        &self,
70        time: DateTime<Tz>,
71        time_multiplier: f32,
72    ) -> (SeasonData, Season, f64) {
73        let data = self.current_season_data(time, time_multiplier);
74        let (season, progress) = self.current_season(time, time_multiplier);
75        (data, season, progress)
76    }
77
78    pub fn get_local_time(&self) -> DateTime<Tz> {
79        Utc::now().with_timezone(&self.timezone)
80    }
81}