1 #pragma once
2 #ifndef CATA_SRC_CALENDAR_H
3 #define CATA_SRC_CALENDAR_H
4 
5 #include <iosfwd>
6 #include <utility>
7 #include <vector>
8 
9 class JsonIn;
10 class JsonOut;
11 class time_duration;
12 class time_point;
13 template<typename T> struct enum_traits;
14 
15 /** Real world seasons */
16 enum season_type {
17     SPRING = 0,
18     SUMMER = 1,
19     AUTUMN = 2,
20     WINTER = 3,
21     NUM_SEASONS
22 };
23 
24 template<>
25 struct enum_traits<season_type> {
26     static constexpr season_type last = season_type::NUM_SEASONS;
27 };
28 
29 /** Phases of the moon */
30 enum moon_phase {
31     /** New (completely dark) moon */
32     MOON_NEW = 0,
33     /** One quarter of moon lit, amount lit is increasing every day */
34     MOON_WAXING_CRESCENT,
35     /** One half of moon lit, amount lit is increasing every day */
36     MOON_HALF_MOON_WAXING,
37     /** Three quarters of moon lit, amount lit is increasing every day */
38     MOON_WAXING_GIBBOUS,
39     /** Full moon */
40     MOON_FULL,
41     /** Three quarters of moon lit, amount lit decreases every day */
42     MOON_WANING_GIBBOUS,
43     /** Half of moon is lit, amount lit decreases every day */
44     MOON_HALF_MOON_WANING,
45     /** One quarter of moon lit, amount lit decreases every day */
46     MOON_WANING_CRESCENT,
47     /** Not a valid moon phase, but can be used for iterating through enum */
48     MOON_PHASE_MAX
49 };
50 
51 /**
52  * Time keeping class
53  *
54  * Encapsulates the current time of day, date, and year.  Also tracks seasonal variation in day
55  * length, the passing of the seasons themselves, and the phases of the moon.
56  */
57 namespace calendar
58 {
59 /**
60  * Predicate to handle rate-limiting. Returns `true` after every @p event_frequency duration.
61  */
62 bool once_every( const time_duration &event_frequency );
63 
64 /**
65  * A number that represents the longest possible action.
66  *
67  * This number should be regarded as a number of turns, and can safely be converted to a
68  * number of seconds or moves (movement points) without integer overflow.  If used to
69  * represent a larger unit (hours/days/years), then this will result in integer overflow.
70  */
71 extern const int INDEFINITELY_LONG;
72 
73 /**
74  * The expected duration of the cataclysm
75  *
76  * Large duration that can be used to approximate infinite amounts of time.
77  *
78  * This number can't be safely converted to a number of moves without causing
79  * an integer overflow.
80  */
81 extern const time_duration INDEFINITELY_LONG_DURATION;
82 
83 /// @returns Whether the eternal season is enabled.
84 bool eternal_season();
85 void set_eternal_season( bool is_eternal_season );
86 
87 /** @returns Time in a year, (configured in current world settings) */
88 time_duration year_length();
89 
90 /** @returns Time of a season (configured in current world settings) */
91 time_duration season_length();
92 void set_season_length( int dur );
93 
94 /// @returns relative length of game season to real life season.
95 float season_ratio();
96 
97 /**
98  * @returns ratio of actual season length (a world option) to default season length. This
99  * should be used to convert JSON values (that assume the default for the season length
100  * option) to actual in-game length.
101  */
102 float season_from_default_ratio();
103 
104 /** Returns the translated name of the season (with first letter being uppercase). */
105 std::string name_season( season_type s );
106 
107 extern time_point start_of_cataclysm;
108 extern time_point start_of_game;
109 extern time_point turn;
110 extern season_type initial_season;
111 
112 /**
113  * A time point that is always before the current turn, even when the game has
114  * just started. This implies `before_time_starts < calendar::turn` is always
115  * true. It can be used to initialize `time_point` values that denote that last
116  * time a cache was update.
117  */
118 extern const time_point before_time_starts;
119 /**
120  * Represents time point 0.
121  * TODO: flesh out the documentation
122  */
123 extern const time_point turn_zero;
124 } // namespace calendar
125 
126 template<typename T>
127 constexpr T to_turns( const time_duration &duration );
128 template<typename T>
129 constexpr T to_seconds( const time_duration &duration );
130 template<typename T>
131 constexpr T to_minutes( const time_duration &duration );
132 template<typename T>
133 constexpr T to_hours( const time_duration &duration );
134 template<typename T>
135 constexpr T to_days( const time_duration &duration );
136 template<typename T>
137 constexpr T to_weeks( const time_duration &duration );
138 template<typename T>
139 constexpr T to_moves( const time_duration &duration );
140 
141 template<typename T>
142 constexpr T to_turn( const time_point &point );
143 
144 template<typename T>
145 constexpr time_duration operator/( const time_duration &lhs, T rhs );
146 template<typename T>
147 inline time_duration &operator/=( time_duration &lhs, T rhs );
148 template<typename T>
149 constexpr time_duration operator*( const time_duration &lhs, T rhs );
150 template<typename T>
151 constexpr time_duration operator*( T lhs, const time_duration &rhs );
152 template<typename T>
153 inline time_duration &operator*=( time_duration &lhs, T rhs );
154 
155 /**
156  * A duration defined as a number of specific time units.
157  * Currently it stores the number (as integer) of turns.
158  * Note: currently variable season length is ignored by this class (N turns are
159  * always N turns) and there is no way to create an instance from units larger
160  * than days (e.g. seasons or years) and no way to convert a duration into those
161  * units directly. (You can still use @ref calendar to do this.)
162  *
163  * Operators for time points and time duration are defined as one may expect them:
164  * -duration ==> duration (inverse)
165  * point - point ==> duration (duration between to points in time)
166  * point + duration ==> point (the revers of above)
167  * point - duration ==> point (same as: point + -duration)
168  * duration + duration ==> duration
169  * duration - duration ==> duration (same as: duration + -duration)
170  * duration * scalar ==> duration (simple scaling yields a double with precise value)
171  * scalar * duration ==> duration (same as above)
172  * duration / duration ==> scalar (revers of above)
173  * duration / scalar ==> duration (same as: duration * 1/scalar)
174  * duration % duration ==> duration ("remainder" of duration / some integer)
175  * Also shortcuts: += and -= and *= and /=
176  */
177 class time_duration
178 {
179     private:
180         friend class time_point;
181         int turns_;
182 
183         explicit constexpr time_duration( const int t ) : turns_( t ) { }
184 
185     public:
186         time_duration() : turns_( 0 ) {}
187 
188         void serialize( JsonOut &jsout ) const;
189         void deserialize( JsonIn &jsin );
190 
191         /**
192          * Named constructors to get a duration representing a multiple of the named time
193          * units. Note that a duration is stored as integer number of turns, so
194          * `from_minutes( 0.0001 )` will be stored as "0 turns".
195          * The template type is used for the conversion from given time unit to turns, so
196          * `from_hours( 0.5 )` will yield "1800 turns".
197          * Conversion of units greater than days (seasons) is not supported because they
198          * depend on option settings ("season length").
199          */
200         /**@{*/
201         template<typename T>
202         static constexpr time_duration from_turns( const T t ) {
203             return time_duration( t );
204         }
205         template<typename T>
206         static constexpr time_duration from_moves( const T t ) {
207             return time_duration( t / 100 );
208         }
209         template<typename T>
210         static constexpr time_duration from_seconds( const T t ) {
211             return time_duration( t );
212         }
213         template<typename T>
214         static constexpr time_duration from_minutes( const T m ) {
215             return from_turns( m * 60 );
216         }
217         template<typename T>
218         static constexpr time_duration from_hours( const T h ) {
219             return from_minutes( h * 60 );
220         }
221         template<typename T>
222         static constexpr time_duration from_days( const T d ) {
223             return from_hours( d * 24 );
224         }
225         template<typename T>
226         static constexpr time_duration from_weeks( const T d ) {
227             return from_days( d * 7 );
228         }
229         /**@}*/
230 
231         /**
232          * Converts the duration to an amount of the given units. The conversions is
233          * done with values of the given template type. That means using an integer
234          * type (e.g. `int`) will return a truncated value (amount of *full* minutes
235          * that make up the duration, discarding the remainder).
236          * Calling `to_minutes<double>` will return a precise number.
237          * Example:
238          * `to_hours<int>( from_minutes( 90 ) ) == 1`
239          * `to_hours<double>( from_minutes( 90 ) ) == 1.5`
240          */
241         /**@{*/
242         template<typename T>
243         friend constexpr T to_turns( const time_duration &duration ) {
244             return duration.turns_;
245         }
246         template<typename T>
247         friend constexpr T to_seconds( const time_duration &duration ) {
248             return duration.turns_;
249         }
250         template<typename T>
251         friend constexpr T to_minutes( const time_duration &duration ) {
252             return static_cast<T>( duration.turns_ ) / static_cast<T>( 60 );
253         }
254         template<typename T>
255         friend constexpr T to_hours( const time_duration &duration ) {
256             return static_cast<T>( duration.turns_ ) / static_cast<T>( 60 * 60 );
257         }
258         template<typename T>
259         friend constexpr T to_days( const time_duration &duration ) {
260             return static_cast<T>( duration.turns_ ) / static_cast<T>( 60 * 60 * 24 );
261         }
262         template<typename T>
263         friend constexpr T to_weeks( const time_duration &duration ) {
264             return static_cast<T>( duration.turns_ ) / static_cast<T>( 60 * 60 * 24 * 7 );
265         }
266         template<typename T>
267         friend constexpr T to_moves( const time_duration &duration ) {
268             return to_turns<int>( duration ) * 100;
269         }
270         /**@{*/
271 
272         constexpr bool operator<( const time_duration &rhs ) const {
273             return turns_ < rhs.turns_;
274         }
275         constexpr bool operator<=( const time_duration &rhs ) const {
276             return turns_ <= rhs.turns_;
277         }
278         constexpr bool operator>( const time_duration &rhs ) const {
279             return turns_ > rhs.turns_;
280         }
281         constexpr bool operator>=( const time_duration &rhs ) const {
282             return turns_ >= rhs.turns_;
283         }
284         constexpr bool operator==( const time_duration &rhs ) const {
285             return turns_ == rhs.turns_;
286         }
287         constexpr bool operator!=( const time_duration &rhs ) const {
288             return turns_ != rhs.turns_;
289         }
290 
291         friend constexpr time_duration operator-( const time_duration &duration ) {
292             return time_duration( -duration.turns_ );
293         }
294         friend constexpr time_duration operator+( const time_duration &lhs, const time_duration &rhs ) {
295             return time_duration( lhs.turns_ + rhs.turns_ );
296         }
297         friend time_duration &operator+=( time_duration &lhs, const time_duration &rhs ) {
298             return lhs = time_duration( lhs.turns_ + rhs.turns_ );
299         }
300         friend constexpr time_duration operator-( const time_duration &lhs, const time_duration &rhs ) {
301             return time_duration( lhs.turns_ - rhs.turns_ );
302         }
303         friend time_duration &operator-=( time_duration &lhs, const time_duration &rhs ) {
304             return lhs = time_duration( lhs.turns_ - rhs.turns_ );
305         }
306         // Using double here because it has the highest precision. Callers can cast it to whatever they want.
307         friend double operator/( const time_duration &lhs, const time_duration &rhs ) {
308             return static_cast<double>( lhs.turns_ ) / static_cast<double>( rhs.turns_ );
309         }
310         template<typename T>
311         friend constexpr time_duration operator/( const time_duration &lhs, const T rhs ) {
312             return time_duration( lhs.turns_ / rhs );
313         }
314         template<typename T>
315         friend time_duration &operator/=( time_duration &lhs, const T rhs ) {
316             return lhs = time_duration( lhs.turns_ / rhs );
317         }
318         template<typename T>
319         friend constexpr time_duration operator*( const time_duration &lhs, const T rhs ) {
320             return time_duration( lhs.turns_ * rhs );
321         }
322         template<typename T>
323         friend constexpr time_duration operator*( const T lhs, const time_duration &rhs ) {
324             return time_duration( lhs * rhs.turns_ );
325         }
326         template<typename T>
327         friend time_duration &operator*=( time_duration &lhs, const T rhs ) {
328             return lhs = time_duration( lhs.turns_ * rhs );
329         }
330         friend time_duration operator%( const time_duration &lhs, const time_duration &rhs ) {
331             return time_duration( lhs.turns_ % rhs.turns_ );
332         }
333 
334         /// Returns a random duration in the range [low, hi].
335         friend time_duration rng( time_duration lo, time_duration hi );
336 
337         static const std::vector<std::pair<std::string, time_duration>> units;
338 };
339 
340 /// @see x_in_y(int,int)
341 bool x_in_y( const time_duration &a, const time_duration &b );
342 
343 /**
344  * Convert the given number into an duration by calling the matching
345  * `time_duration::from_*` function.
346  */
347 /**@{*/
348 constexpr time_duration operator"" _turns( const unsigned long long int v )
349 {
350     return time_duration::from_turns( v );
351 }
352 constexpr time_duration operator"" _seconds( const unsigned long long int v )
353 {
354     return time_duration::from_seconds( v );
355 }
356 constexpr time_duration operator"" _minutes( const unsigned long long int v )
357 {
358     return time_duration::from_minutes( v );
359 }
360 constexpr time_duration operator"" _hours( const unsigned long long int v )
361 {
362     return time_duration::from_hours( v );
363 }
364 constexpr time_duration operator"" _days( const unsigned long long int v )
365 {
366     return time_duration::from_days( v );
367 }
368 constexpr time_duration operator"" _weeks( const unsigned long long int v )
369 {
370     return time_duration::from_weeks( v );
371 }
372 /**@}*/
373 
374 /**
375  * Returns a string showing a duration. The string contains at most two numbers
376  * along with their units. E.g. 3661 seconds will return "1 hour and 1 minute"
377  * (the 1 additional second is clipped). An input of 3601 will return "1 hour"
378  * (the second is clipped again and the number of additional minutes would be
379  * 0 so it's skipped).
380  * @param compact True for compact display of time. Example: 1 min 15 secs
381  */
382 std::string to_string( const time_duration &d, bool compact = false );
383 
384 enum class clipped_align : int {
385     none,
386     right,
387     compact
388 };
389 
390 enum class clipped_unit : int {
391     forever,
392     second,
393     minute,
394     hour,
395     day,
396     week,
397     season,
398     year,
399 };
400 
401 /**
402  * Returns a value representing the passed in duration truncated to an appropriate unit
403  * along with the unit in question.
404  * "10 days" or "1 minute".
405  * The chosen unit will be the smallest unit, that is at least as much as the
406  * given duration. E.g. an input of 60 minutes will return "1 hour", an input of
407  * 59 minutes will return "59 minutes".
408  */
409 std::pair<int, clipped_unit> clipped_time( const time_duration &d );
410 
411 /**
412  * Returns a string showing a duration as whole number of appropriate units, e.g.
413  * "10 days" or "1 minute".
414  * The chosen unit will be the smallest unit, that is at least as much as the
415  * given duration. E.g. an input of 60 minutes will return "1 hour", an input of
416  * 59 minutes will return "59 minutes".
417  * @param align none, right, or compact.
418  */
419 std::string to_string_clipped( const time_duration &d, clipped_align align = clipped_align::none );
420 /**
421  * Returns approximate duration.
422  * @param verbose If true, 'less than' and 'more than' will be printed instead of '<' and '>' respectively.
423  */
424 std::string to_string_approx( const time_duration &dur, bool verbose = true );
425 /**
426  * Returns a string that is writable to JSON that is also readable from JSON
427  */
428 std::string to_string_writable( const time_duration &dur );
429 
430 /**
431  * A point in the game time. Use `calendar::turn` to get the current point.
432  * Modify it by adding/subtracting @ref time_duration.
433  * This can be compared with the usual comparison operators.
434  * It can be (de)serialized via JSON.
435  *
436  * Note that is does not handle variable sized season length. Changing the
437  * season length has no effect on it.
438  */
439 class time_point
440 {
441     private:
442         friend class time_duration;
443         int turn_;
444 
445     public:
446         time_point();
447         // TODO: make private
448         explicit constexpr time_point( const int t ) : turn_( t ) { }
449 
450     public:
451         // TODO: remove this, nobody should need it, one should use a constant `time_point`
452         // (representing turn 0) and a `time_duration` instead.
453         static constexpr time_point from_turn( const int t ) {
454             return time_point( t );
455         }
456 
457         void serialize( JsonOut &jsout ) const;
458         void deserialize( JsonIn &jsin );
459 
460         // TODO: try to get rid of this
461         template<typename T>
462         friend constexpr T to_turn( const time_point &point ) {
463             return point.turn_;
464         }
465 
466         friend constexpr inline bool operator<( const time_point &lhs, const time_point &rhs ) {
467             return to_turn<int>( lhs ) < to_turn<int>( rhs );
468         }
469         friend constexpr inline bool operator<=( const time_point &lhs, const time_point &rhs ) {
470             return to_turn<int>( lhs ) <= to_turn<int>( rhs );
471         }
472         friend constexpr inline bool operator>( const time_point &lhs, const time_point &rhs ) {
473             return to_turn<int>( lhs ) > to_turn<int>( rhs );
474         }
475         friend constexpr inline bool operator>=( const time_point &lhs, const time_point &rhs ) {
476             return to_turn<int>( lhs ) >= to_turn<int>( rhs );
477         }
478         friend constexpr inline bool operator==( const time_point &lhs, const time_point &rhs ) {
479             return to_turn<int>( lhs ) == to_turn<int>( rhs );
480         }
481         friend constexpr inline bool operator!=( const time_point &lhs, const time_point &rhs ) {
482             return to_turn<int>( lhs ) != to_turn<int>( rhs );
483         }
484 
485         friend constexpr inline time_duration operator-(
486             const time_point &lhs, const time_point &rhs ) {
487             return time_duration::from_turns( to_turn<int>( lhs ) - to_turn<int>( rhs ) );
488         }
489         friend constexpr inline time_point operator+(
490             const time_point &lhs, const time_duration &rhs ) {
491             return time_point::from_turn( to_turn<int>( lhs ) + to_turns<int>( rhs ) );
492         }
493         friend time_point inline &operator+=( time_point &lhs, const time_duration &rhs ) {
494             return lhs = time_point::from_turn( to_turn<int>( lhs ) + to_turns<int>( rhs ) );
495         }
496         friend constexpr inline time_point operator-(
497             const time_point &lhs, const time_duration &rhs ) {
498             return time_point::from_turn( to_turn<int>( lhs ) - to_turns<int>( rhs ) );
499         }
500         friend time_point inline &operator-=( time_point &lhs, const time_duration &rhs ) {
501             return lhs = time_point::from_turn( to_turn<int>( lhs ) - to_turns<int>( rhs ) );
502         }
503 
504         // TODO: implement minutes_of_hour and so on and use it.
505 };
506 
507 inline time_duration time_past_midnight( const time_point &p )
508 {
509     return ( p - calendar::turn_zero ) % 1_days;
510 }
511 
512 inline time_duration time_past_new_year( const time_point &p )
513 {
514     return ( p - calendar::turn_zero ) % calendar::year_length();
515 }
516 
517 template<typename T>
518 inline T minute_of_hour( const time_point &p )
519 {
520     return to_minutes<T>( ( p - calendar::turn_zero ) % 1_hours );
521 }
522 
523 template<typename T>
524 inline T hour_of_day( const time_point &p )
525 {
526     return to_hours<T>( ( p - calendar::turn_zero ) % 1_days );
527 }
528 
529 /// This uses the current season length.
530 template<typename T>
531 inline T day_of_season( const time_point &p )
532 {
533     return to_days<T>( ( p - calendar::turn_zero ) % calendar::season_length() );
534 }
535 
536 /// @returns The season of the of the given time point. Returns the same season for
537 /// any input if the calendar::eternal_season yields true.
538 season_type season_of_year( const time_point &p );
539 /// @returns The time point formatted to be shown to the player. Contains year, season, day and time of day.
540 std::string to_string( const time_point &p );
541 /// @returns The time point formatted to be shown to the player. Contains only the time of day, not the year, day or season.
542 std::string to_string_time_of_day( const time_point &p );
543 /** Returns the default duration of a lunar month (duration between syzygies) */
544 time_duration lunar_month();
545 /** Returns the current phase of the moon. */
546 moon_phase get_moon_phase( const time_point &p );
547 /** Returns the current sunrise time based on the time of year. */
548 time_point sunrise( const time_point &p );
549 /** Returns the current sunset time based on the time of year. */
550 time_point sunset( const time_point &p );
551 /** Returns the time it gets light based on sunrise */
552 time_point daylight_time( const time_point &p );
553 /** Returns the time it gets dark based on sunset */
554 time_point night_time( const time_point &p );
555 /** Returns true if it's currently night time - after dusk and before dawn. */
556 bool is_night( const time_point &p );
557 /** Returns true if it's currently day time - after dawn and before dusk. */
558 bool is_day( const time_point &p );
559 /** Returns true if it's currently dusk - between sunset and and twilight_duration after sunset. */
560 bool is_dusk( const time_point &p );
561 /** Returns true if it's currently dawn - between sunrise and twilight_duration after sunrise. */
562 bool is_dawn( const time_point &p );
563 /** Returns the current seasonally-adjusted maximum daylight level */
564 double current_daylight_level( const time_point &p );
565 /** How much light is provided in full daylight */
566 double default_daylight_level();
567 /** Returns the current sunlight or moonlight level through the preceding functions.
568  *  By default, returns sunlight level for vision, with moonlight providing a measurable amount
569  *  of light.  with vision == false, returns sunlight for solar panel purposes, and moonlight
570  *  provides 0 light */
571 float sunlight( const time_point &p, bool vision = true );
572 
573 enum class weekdays : int {
574     SUNDAY = 0,
575     MONDAY,
576     TUESDAY,
577     WEDNESDAY,
578     THURSDAY,
579     FRIDAY,
580     SATURDAY,
581 };
582 
583 weekdays day_of_week( const time_point &p );
584 
585 #endif // CATA_SRC_CALENDAR_H
586