001 (ns the-great-game.time
002 (:require [clojure.string :as s]))
003
004 (def game-start-time
005 "The start time of this run."
006 (System/currentTimeMillis))
007
008 (def ^:const game-day-length
009 "The Java clock advances in milliseconds, which is fine.
010 But we need game-days to be shorter than real world days.
011 A Witcher 3 game day is 1 hour 36 minutes, or 96 minutes, which is
012 presumably researched. Round it up to 100 minutes for easier
013 calculation."
014 (* 100 ;; minutes per game day
015 60 ;; seconds per minute
016 1000)) ;; milliseconds per second
017
018 (defn now
019 "For now, we'll use Java timestamp for time; ultimately, we need a
020 concept of game-time which allows us to drive day/night cycle, seasons,
021 et cetera, but what matters about time is that it is a value which
022 increases."
023 []
024 (System/currentTimeMillis))
025
026 (def ^:const canonical-ordering-of-houses
027 "The canonical ordering of religious houses."
028 [:eye
029 :foot
030 :nose
031 :hand
032 :ear
033 :mouth
034 :stomach
035 :furrow
036 :plough])
037
038 (def ^:const days-of-week
039 "The eight-day week of the game world. This differs from the canonical
040 ordering of houses in that it omits the eye."
041 (rest canonical-ordering-of-houses))
042
043 (def ^:const days-in-week
044 "This world has an eight day week."
045 (count days-of-week))
046
047 (def ^:const seasons-of-year
048 "The ordering of seasons in the year is different from the canonical
049 ordering of the houses, for reasons of the agricultural cycle."
050 [:foot
051 :nose
052 :hand
053 :ear
054 :mouth
055 :stomach
056 :plough
057 :furrow
058 :eye])
059
060 (def ^:const seasons-in-year
061 "Nine seasons in a year, one for each house (although the order is
062 different."
063 (count seasons-of-year))
064
065 (def ^:const weeks-of-season
066 "To fit nine seasons of eight day weeks into 365 days, each must be of
067 five weeks."
068 [:first :second :third :fourth :fifth])
069
070 (def ^:const weeks-in-season
071 "To fit nine seasons of eight day weeks into 365 days, each must be of
072 five weeks."
073 (count weeks-of-season))
074
075 (def ^:const days-in-season
076 (* weeks-in-season days-in-week))
077
078 (defn game-time
079 "With no arguments, the current game time. If a Java `timestamp` value is
080 passed (as a `long`), the game time represented by that value."
081 ([] (game-time (now)))
082 ([timestamp]
083 (- timestamp game-start-time)))
084
085 (defmacro day-of-year
086 "The day of the year represented by this `game-time`, ignoring leap years."
087 [game-time]
088 `(mod (long (/ ~game-time game-day-length)) 365))
089
090 (def waiting-day?
091 "Does this `game-time` represent a waiting day?"
092 (memoize
093 ;; we're likely to call this several times in quick succession on the
094 ;; same timestamp
095 (fn [game-time]
096 (>=
097 (day-of-year game-time)
098 (* seasons-in-year weeks-in-season days-in-week)))))
099
100 (defn day
101 "Day of the eight-day week represented by this `game-time`."
102 [game-time]
103 (let [day-of-week (mod (day-of-year game-time) days-in-week)]
104 (if (waiting-day? game-time)
105 (nth weeks-of-season day-of-week)
106 (nth days-of-week day-of-week))))
107
108 (defn week
109 "Week of season represented by this `game-time`."
110 [game-time]
111 (let [day-of-season (mod (day-of-year game-time) days-in-season)
112 week (/ day-of-season days-in-week)]
113 (if (waiting-day? game-time)
114 :waiting
115 (nth weeks-of-season week))))
116
117 (defn season
118 [game-time]
119 (let [season (int (/ (day-of-year game-time) days-in-season))]
120 (if (waiting-day? game-time)
121 :waiting
122 (nth seasons-of-year season))))
123
124 (defn date-string
125 "Return a correctly formatted date for this `game-time` in the calendar of
126 the Great Place."
127 [game-time]
128 (s/join
129 " "
130 (if
131 (waiting-day? game-time)
132 [(s/capitalize
133 (name
134 (nth
135 weeks-of-season
136 (mod (day-of-year game-time) days-in-week))))
137 "waiting day"]
138 [(s/capitalize (name (week game-time)))
139 (s/capitalize (name (day game-time)))
140 "of the"
141 (s/capitalize (name (season game-time)))])))
142
143
144