Simplify and optimize count_ordinal
[xonotic/xonotic-data.pk3dir.git] / qcsrc / lib / counting.qh
1 #pragma once
2
3 #include "i18n.qh"
4
5 // ===============================================
6 //  Time processing and counting functions/macros
7 // ===============================================
8
9 #define count_years_decs(time, decs) sprintf(CTX(_("CI_DEC^%s years")), ftos_decimals(time, decs))
10 #define count_years(time) \
11         count_fill(time, \
12         _("CI_ZER^%d years"), /* zeroth */ \
13         _("CI_FIR^%d year"),  /* first */ \
14         _("CI_SEC^%d years"), /* year */ \
15         _("CI_THI^%d years"), /* third */ \
16         _("CI_MUL^%d years")) /* multi */
17
18 #define count_weeks_decs(time, decs) sprintf(CTX(_("CI_DEC^%s weeks")), ftos_decimals(time, decs))
19 #define count_weeks(time) \
20         count_fill(time, \
21         _("CI_ZER^%d weeks"), /* zeroth */ \
22         _("CI_FIR^%d week"),  /* first */ \
23         _("CI_SEC^%d weeks"), /* week */ \
24         _("CI_THI^%d weeks"), /* third */ \
25         _("CI_MUL^%d weeks")) /* multi */
26
27 #define count_days_decs(time, decs) sprintf(CTX(_("CI_DEC^%s days")), ftos_decimals(time, decs))
28 #define count_days(time) \
29         count_fill(time, \
30         _("CI_ZER^%d days"), /* zeroth */ \
31         _("CI_FIR^%d day"),  /* first */ \
32         _("CI_SEC^%d days"), /* day */ \
33         _("CI_THI^%d days"), /* third */ \
34         _("CI_MUL^%d days")) /* multi */
35
36 #define count_hours_decs(time, decs) sprintf(CTX(_("CI_DEC^%s hours")), ftos_decimals(time, decs))
37 #define count_hours(time) \
38         count_fill(time, \
39         _("CI_ZER^%d hours"), /* zeroth */ \
40         _("CI_FIR^%d hour"),  /* first */ \
41         _("CI_SEC^%d hours"), /* hour */ \
42         _("CI_THI^%d hours"), /* third */ \
43         _("CI_MUL^%d hours")) /* multi */
44
45
46 #define count_minutes_decs(time, decs) sprintf(CTX(_("CI_DEC^%s minutes")), ftos_decimals(time, decs))
47 #define count_minutes(time) \
48         count_fill(time, \
49         _("CI_ZER^%d minutes"), /* zeroth */ \
50         _("CI_FIR^%d minute"),  /* first */ \
51         _("CI_SEC^%d minutes"), /* minute */ \
52         _("CI_THI^%d minutes"), /* third */ \
53         _("CI_MUL^%d minutes")) /* multi */
54
55 #define count_seconds_decs(time, decs) sprintf(CTX(_("CI_DEC^%s seconds")), ftos_decimals(time, decs))
56 #define count_seconds(time) \
57         count_fill(time, \
58         _("CI_ZER^%d seconds"), /* zeroth */ \
59         _("CI_FIR^%d second"),  /* first */ \
60         _("CI_SEC^%d seconds"), /* second */ \
61         _("CI_THI^%d seconds"), /* third */ \
62         _("CI_MUL^%d seconds")) /* multi */
63
64 // returns 1st, 2nd, 3rd, nth ordinal number from a cardinal number (integer)
65 ERASEABLE
66 string count_ordinal(int interval)
67 {
68         // This function is designed primarily for the English language, it's impossible
69         // to accomodate all languages unless we do a specific function for each one...
70         // and since that's not technically feasible/practical, this is all we've got folks.
71
72         int last2digits = interval % 100;
73
74         // numbers ending with 11, 12 and 13 don't follow the standard pattern
75         if (last2digits < 4 || last2digits > 20)
76         {
77                 switch (last2digits % 10)
78                 {
79                         case 1: return sprintf(_("%dst"), interval);
80                         case 2: return sprintf(_("%dnd"), interval);
81                         case 3: return sprintf(_("%drd"), interval);
82                 }
83         }
84
85         return sprintf(_("%dth"), interval);
86 }
87
88 ERASEABLE
89 string count_fill(float interval, string zeroth, string first, string second, string third, string multi)
90 {
91         // This function is designed primarily for the English language, it's impossible
92         // to accomodate all languages unless we do a specific function for each one...
93         // and since that's not technically feasible/practical, this is all we've got folks.
94
95         // Here you can insert specific strings based on the interval number, so you could do
96         // i.e. count_seconds which outputs like this:
97         //   0 seconds
98         //   1 second
99         //   2 seconds
100         //   3 seconds
101         //   etc... minutes, hours, days, etc.
102
103         switch (floor(interval))
104         {
105                 case 0: return sprintf(CTX(zeroth), interval);
106                 case 1:
107                 {
108                         if (interval == 1)  // EXACTLY value of 1
109                                 return sprintf(CTX(first), interval);
110                         else return sprintf(CTX(multi), interval);
111                 }
112                 case 2: return sprintf(CTX(second), interval);
113                 case 3: return sprintf(CTX(third), interval);
114                 default: return sprintf(CTX(multi), interval);
115         }
116         return "";
117 }
118
119 ERASEABLE
120 string process_time(float outputtype, float seconds)
121 {
122         float tmp_hours = 0, tmp_minutes = 0, tmp_seconds = 0;
123         float tmp_years = 0, tmp_weeks = 0, tmp_days = 0;
124
125         tmp_seconds = floor(seconds);
126
127         if (tmp_seconds)
128         {
129                 tmp_minutes = floor(tmp_seconds / 60);
130
131                 if (tmp_minutes)
132                 {
133                         tmp_seconds -= (tmp_minutes * 60);
134                         tmp_hours = floor(tmp_minutes / 60);
135
136                         if (tmp_hours)
137                         {
138                                 tmp_minutes -= (tmp_hours * 60);
139                                 tmp_days = floor(tmp_hours / 24);
140
141                                 if (tmp_days)
142                                 {
143                                         tmp_hours -= (tmp_days * 24);
144                                         tmp_weeks = floor(tmp_days / 7);
145
146                                         if (tmp_weeks)
147                                         {
148                                                 tmp_days -= (tmp_weeks * 7);
149                                                 tmp_years = floor(tmp_weeks / 52);
150                                         }
151                                 }
152                         }
153                 }
154         }
155
156         switch (outputtype)
157         {
158                 case 1: return sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds);
159                 case 2:
160                 {
161                         string output = "";
162
163                         output = count_seconds(tmp_seconds);
164
165                         if (tmp_minutes)
166                         {
167                                 output = strcat(
168                                         count_minutes(tmp_minutes),
169                                         ((output != "") ? strcat(", ", output) : ""));
170                         }
171
172                         if (tmp_hours)
173                         {
174                                 output = strcat(
175                                         count_hours(tmp_hours),
176                                         ((output != "") ? strcat(", ", output) : ""));
177                         }
178
179                         if (tmp_days)
180                         {
181                                 output = strcat(
182                                         count_days(tmp_days),
183                                         ((output != "") ? strcat(", ", output) : ""));
184                         }
185
186                         if (tmp_weeks)
187                         {
188                                 output = strcat(
189                                         count_weeks(tmp_weeks),
190                                         ((output != "") ? strcat(", ", output) : ""));
191                         }
192
193                         if (tmp_years)
194                         {
195                                 output = strcat(
196                                         count_years(tmp_years),
197                                         ((output != "") ? strcat(", ", output) : ""));
198                         }
199
200                         return output;
201                 }
202                 case 3:
203                 {
204                         string output = "";
205
206                         output = count_hours(tmp_hours);
207
208                         if (tmp_weeks) tmp_days += (tmp_weeks * 7);
209                         if (tmp_years) tmp_days += (tmp_years * 365);
210                         if (tmp_days)
211                         {
212                                 output = sprintf(
213                                         count_days(tmp_days),
214                                         ((output != "") ? strcat(", ", output) : ""));
215                         }
216
217                         return output;
218                 }
219         }
220         return "";
221 }