1 /*
2  * See Licensing and Copyright notice in naev.h
3  */
4 
5 /**
6  * @file ntime.c
7  *
8  * @brief Handles the Naev time.
9  *
10  * 1 SCU =  5e3 STP = 50e6 STU
11  * 1 STP = 10e3 STU
12  * 1 STU = 1 second
13  *
14  * Generally displayed as:
15  *  <SCU>:<STP>.<STU> UST
16  * The number of STU digits can be variable, for example:
17  *
18  *  630:3726.1 UST
19  *  630:3726.12 UST
20  *  630:3726.124 UST
21  *  630:3726.1248 UST
22  *  630:3726.12489 UST
23  *
24  * Are all valid.
25  *
26  * Acronyms:
27  *    - UST : Universal Synchronized Time
28  *    - STU : Smallest named time unit. Equal to the Earth second.
29  *    - STP : Most commonly used time unit. STPs are the new hours. 1 STP = 10,000 STU (about 2.8 Earth hours).
30  *    - SCU : Used for long-term time periods. 1 SCU = 5000 STP (about 579 Earth days).
31  */
32 
33 
34 #include "ntime.h"
35 
36 #include "naev.h"
37 
38 #include <stdio.h>
39 #include "nstring.h"
40 #include <stdlib.h>
41 
42 #include "hook.h"
43 #include "economy.h"
44 
45 
46 #define NT_STU_DIV   (1000)      /* Divider for extracting STU. */
47 #define NT_STU_DT    (30)        /* Update rate, how many STU are in a real second. */
48 #define NT_SCU_STU   ((ntime_t)NT_SCU_STP*(ntime_t)NT_STP_STU) /* STU in an SCU */
49 #define NT_STP_DIV   ((ntime_t)NT_STP_STU*(ntime_t)NT_STU_DIV) /* Divider for extracting STP. */
50 #define NT_SCU_DIV   ((ntime_t)NT_SCU_STU*(ntime_t)NT_STU_DIV) /* Divider for extracting STP. */
51 
52 
53 /**
54  * @brief Used for storing time increments to not trigger hooks during Lua
55  *        calls and such.
56  */
57 typedef struct NTimeUpdate_s {
58    struct NTimeUpdate_s *next; /**< Next in the linked list. */
59    ntime_t inc; /**< Time increment associated. */
60 } NTimeUpdate_t;
61 static NTimeUpdate_t *ntime_inclist = NULL; /**< Time increment list. */
62 
63 
64 static ntime_t naev_time = 0; /**< Contains the current time in mSTU. */
65 static double naev_remainder = 0.; /**< Remainder when updating, to try to keep in perfect sync. */
66 static int ntime_enable = 1; /** Allow updates? */
67 
68 
69 /**
70  * @brief Updatse the time based on realtime.
71  */
ntime_update(double dt)72 void ntime_update( double dt )
73 {
74    double dtt, tu;
75    ntime_t inc;
76 
77    /* Only if we need to update. */
78    if (!ntime_enable)
79       return;
80 
81    /* Calculate the effective time. */
82    dtt = naev_remainder + dt*NT_STU_DT*NT_STU_DIV;
83 
84    /* Time to update. */
85    tu             = floor( dtt );
86    inc            = (ntime_t) tu;
87    naev_remainder = dtt - tu; /* Leave remainder. */
88 
89    /* Increment. */
90    naev_time     += inc;
91    hooks_updateDate( inc );
92 }
93 
94 
95 /**
96  * @brief Creates a time structure.
97  */
ntime_create(int scu,int stp,int stu)98 ntime_t ntime_create( int scu, int stp, int stu )
99 {
100    ntime_t tscu, tstp, tstu;
101    tscu = scu;
102    tstp = stp;
103    tstu = stu;
104    return tscu*NT_SCU_DIV + tstp*NT_STP_DIV + tstu*NT_STU_DIV;
105 }
106 
107 
108 /**
109  * @brief Gets the current time.
110  *
111  *    @return The current time in mSTU.
112  */
ntime_get(void)113 ntime_t ntime_get (void)
114 {
115    return naev_time;
116 }
117 
118 
119 /**
120  * @brief Gets the current time broken into individual components.
121  */
ntime_getR(int * scu,int * stp,int * stu,double * rem)122 void ntime_getR( int *scu, int *stp, int *stu, double *rem )
123 {
124    *scu = ntime_getSCU( naev_time );
125    *stp = ntime_getSTP( naev_time );
126    *stu = ntime_getSTU( naev_time );
127    *rem = ntime_getRemainder( naev_time ) + naev_remainder;
128 }
129 
130 
131 /**
132  * @brief Gets the SCU of a time.
133  */
ntime_getSCU(ntime_t t)134 int ntime_getSCU( ntime_t t )
135 {
136    return (t / NT_SCU_DIV);
137 }
138 
139 
140 /**
141  * @brief Gets the STP of a time.
142  */
ntime_getSTP(ntime_t t)143 int ntime_getSTP( ntime_t t )
144 {
145    return (t / NT_STP_DIV) % NT_SCU_STP;
146 }
147 
148 
149 /**
150  * @brief Gets the STU of a time.
151  */
ntime_getSTU(ntime_t t)152 int ntime_getSTU( ntime_t t )
153 {
154    return (t / NT_STU_DIV) % NT_STP_STU;
155 }
156 
157 
158 /**
159  * @brief Converts the time to STU.
160  *    @param t Time to convert.
161  *    @return Time in STU.
162  */
ntime_convertSTU(ntime_t t)163 double ntime_convertSTU( ntime_t t )
164 {
165    return ((double)t / (double)NT_STU_DIV);
166 }
167 
168 
169 /**
170  * @brief Gets the remainder.
171  */
ntime_getRemainder(ntime_t t)172 double ntime_getRemainder( ntime_t t )
173 {
174    return (double)(t % NT_STU_DIV);
175 }
176 
177 
178 /**
179  * @brief Gets the time in a pretty human readable format.
180  *
181  *    @param t Time to print (in STU), if 0 it'll use the current time.
182  *    @param d Number of digits to use.
183  *    @return The time in a human readable format (must free).
184  */
ntime_pretty(ntime_t t,int d)185 char* ntime_pretty( ntime_t t, int d )
186 {
187    char str[64];
188    ntime_prettyBuf( str, sizeof(str), t, d );
189    return strdup(str);
190 }
191 
192 
193 /**
194  * @brief Gets the time in a pretty human readable format filling a preset buffer.
195  *
196  *    @param[out] str Buffer to use.
197  *    @param max Maximum length of the buffer (recommended 64).
198  *    @param t Time to print (in STU), if 0 it'll use the current time.
199  *    @param d Number of digits to use.
200  *    @return The time in a human readable format (must free).
201  */
ntime_prettyBuf(char * str,int max,ntime_t t,int d)202 void ntime_prettyBuf( char *str, int max, ntime_t t, int d )
203 {
204    ntime_t nt;
205    int scu, stp, stu;
206 
207    if (t==0)
208       nt = naev_time;
209    else
210       nt = t;
211 
212    /* UST (Universal Synchronized Time) - unit is STU (Synchronized Time Unit) */
213    scu = ntime_getSCU( nt );
214    stp = ntime_getSTP( nt );
215    stu = ntime_getSTU( nt );
216    if ((scu==0) && (stp==0)) /* only STU */
217       nsnprintf( str, max, "%04d STU", stu );
218    else if ((scu==0) || (d==0))
219       nsnprintf( str, max, "%.*f STP", d, stp + 0.0001 * stu );
220    else /* UST format */
221       nsnprintf( str, max, "UST %d:%.*f", scu, d, stp + 0.0001 * stu );
222 }
223 
224 
225 /**
226  * @brief Sets the time absolutely, does NOT generate an event, used at init.
227  *
228  *    @param t Absolute time to set to in STU.
229  */
ntime_set(ntime_t t)230 void ntime_set( ntime_t t )
231 {
232    naev_time      = t;
233    naev_remainder = 0.;
234 }
235 
236 
237 /**
238  * @brief Loads time including remainder.
239  */
ntime_setR(int scu,int stp,int stu,double rem)240 void ntime_setR( int scu, int stp, int stu, double rem )
241 {
242    naev_time   = ntime_create( scu, stp, stu );
243    naev_time  += floor(rem);
244    naev_remainder = fmod( rem, 1. );
245 }
246 
247 
248 /**
249  * @brief Sets the time relatively.
250  *
251  *    @param t Time modifier in STU.
252  */
ntime_inc(ntime_t t)253 void ntime_inc( ntime_t t )
254 {
255    naev_time += t;
256    economy_update( t );
257 
258    /* Run hooks. */
259    if (t > 0)
260       hooks_updateDate( t );
261 }
262 
263 
264 /**
265  * @brief Allows the time to update when the game is updating.
266  *
267  *    @param enable Whether or not to enable time updating.
268  */
ntime_allowUpdate(int enable)269 void ntime_allowUpdate( int enable )
270 {
271    ntime_enable = enable;
272 }
273 
274 
275 /**
276  * @brief Sets the time relatively.
277  *
278  * This does NOT call hooks and such, they must be run with ntime_refresh
279  *  manually later.
280  *
281  *    @param t Time modifier in STU.
282  */
ntime_incLagged(ntime_t t)283 void ntime_incLagged( ntime_t t )
284 {
285    NTimeUpdate_t *ntu, *iter;
286 
287    /* Create the time increment. */
288    ntu = malloc(sizeof(NTimeUpdate_t));
289    ntu->next = NULL;
290    ntu->inc = t;
291 
292    /* Only member. */
293    if (ntime_inclist == NULL)
294       ntime_inclist = ntu;
295 
296    else {
297       /* Find end of list. */
298       for (iter = ntime_inclist; iter->next != NULL; iter = iter->next);
299       /* Append to end. */
300       iter->next = ntu;
301    }
302 }
303 
304 
305 /**
306  * @brief Checks to see if ntime has any hooks pending to run.
307  */
ntime_refresh(void)308 void ntime_refresh (void)
309 {
310    NTimeUpdate_t *ntu;
311 
312    /* We have to run all the increments one by one to ensure all hooks get
313     * run and that no collisions occur. */
314    while (ntime_inclist != NULL) {
315       ntu = ntime_inclist;
316 
317       /* Run hook stuff and actually update time. */
318       naev_time += ntu->inc;
319       economy_update( ntu->inc );
320 
321       /* Remove the increment. */
322       ntime_inclist = ntu->next;
323 
324       /* Free the increment. */
325       free(ntu);
326    }
327 }
328 
329