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