Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
getreplies.qc
Go to the documentation of this file.
1#include "getreplies.qh"
2
4#include <common/constants.qh>
10#include <common/stats.qh>
11#include <common/util.qh>
13#include <common/wepent.qh>
16#include <server/main.qh>
17#include <server/mapvoting.qh>
19#include <server/race.qh>
21#include <server/world.qh>
22
23// =========================================================
24// Reply messages for common commands, re-worked by Samual
25// Last updated: December 30th, 2011
26// =========================================================
27
28// These strings are set usually during init in world.qc,
29// or also by some gametypes or other functions manually,
30// and their purpose is to output information to clients
31// without using any extra processing time.
32
33// See common.qc for their proper commands
34
35string getrecords(int page)
36{
37 string s = "";
38
39 MUTATOR_CALLHOOK(GetRecords, page, s);
40 s = M_ARGV(1, string);
41
43 return s;
44}
45
47{
48 float t, i;
49 string n, s, p, map;
50
51 map = GetMapname();
52
53 s = "";
54 for (i = 1; i <= RANKINGS_CNT; ++i)
55 {
56 t = race_readTime(map, i);
57
58 if (t == 0) continue;
59
60 n = race_readName(map, i);
61 p = count_ordinal(i);
62 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t, false)), " ", n, "\n");
63 }
64
66
67 if (s == "") return strcat("No records are available for the map: ", map, "\n");
68 else return strcat("Records for ", map, ":\n", s);
69}
70
71string getladder()
72{
73 int i, j, k, uidcnt = 0, thiscnt;
74 string s, temp_s, rr, myuid, thisuid;
75
76 rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
77
78 for (k = 0; k < MapInfo_count; ++k)
79 {
80 if (MapInfo_Get_ByID(k))
81 {
82 for (i = 0; i <= LADDER_CNT; ++i) // i = 0 because it is the speed award
83 {
84 if (i == 0) // speed award
85 {
86 if (stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0) continue;
87
88 myuid = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/crypto_idfp"));
89 }
90 else // normal record, if it exists (else break)
91 {
92 if (race_readTime(MapInfo_Map_bspname, i) == 0) continue;
93
95 }
96
97 // string s contains:
98 // arg 0 = # of speed recs
99 // arg 1 = # of 1st place recs
100 // arg 2 = # of 2nd place recs
101 // ... etc
102 // LADDER_CNT+1 = total points
103
104 temp_s = db_get(TemporaryDB, strcat("ladder", myuid));
105
106 if (temp_s == "")
107 {
108 db_put(TemporaryDB, strcat("uid", ftos(uidcnt)), myuid);
109 ++uidcnt;
110
111 for (j = 0; j <= LADDER_CNT + 1; ++j)
112 {
113 if (j != LADDER_CNT + 1) temp_s = strcat(temp_s, "0 ");
114 else temp_s = strcat(temp_s, "0");
115 }
116 }
117
118 tokenize_console(temp_s);
119 s = "";
120
121 if (i == 0) // speed award
122 {
123 for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
124 {
125 if (j == 0) // speed award
126 s = strcat(s, ftos(stof(argv(j)) + 1)); // add 1 to speed rec count and write
127 else s = strcat(s, " ", argv(j)); // just copy over everything else
128 }
129 }
130 else // record
131 {
132 for (j = 0; j <= LADDER_CNT; ++j) // loop over each arg in the string
133 {
134 if (j == 0) s = strcat(s, argv(j)); // speed award, dont prefix with " "
135 else if (j == i) // wanted rec!
136 s = strcat(s, " ", ftos(stof(argv(j)) + 1)); // update argv(j)
137 else s = strcat(s, " ", argv(j)); // just copy over everything else
138 }
139 }
140
141 // total points are (by default) calculated like this:
142 // speedrec = floor(100 / 10) = 10 points
143 // 1st place = floor(100 / 1) = 100 points
144 // 2nd place = floor(100 / 2) = 50 points
145 // 3rd place = floor(100 / 3) = 33 points
146 // 4th place = floor(100 / 4) = 25 points
147 // 5th place = floor(100 / 5) = 20 points
148 // ... etc
149
150 if (i == 0) s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
151 else s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + floor(LADDER_FIRSTPOINT / i))); // record, add LADDER_FIRSTPOINT / i points
152
153 db_put(TemporaryDB, strcat("ladder", myuid), s);
154 }
155 }
156 }
157
158 for (i = 0; i <= uidcnt; ++i) // for each known uid
159 {
160 thisuid = db_get(TemporaryDB, strcat("uid", ftos(i)));
161 temp_s = db_get(TemporaryDB, strcat("ladder", thisuid));
162 tokenize_console(temp_s);
163 thiscnt = stof(argv(LADDER_CNT + 1));
164
165 if (thiscnt > top_scores[LADDER_SIZE - 1])
166 {
167 for (j = 0; j < LADDER_SIZE; ++j) // for each place in ladder
168 {
169 if (thiscnt > top_scores[j])
170 {
171 for (k = LADDER_SIZE - 1; k >= j; --k)
172 {
173 top_uids[k] = top_uids[k - 1];
174 top_scores[k] = top_scores[k - 1];
175 }
176
177 top_uids[j] = thisuid;
178 top_scores[j] = thiscnt;
179 break;
180 }
181 }
182 }
183 }
184
185 s = "^3-----------------------\n\n";
186
187 s = strcat(s, "Pos ^3|");
188 s = strcat(s, " ^7Total ^3|");
189
190 for (i = 1; i <= LADDER_CNT; ++i)
191 s = strcat(s, " ^7", count_ordinal(i), " ^3|");
192 s = strcat(s, " ^7Speed awards ^3| ^7Name");
193 s = strcat(s, "\n^3----+--------");
194
195 for (i = 1; i <= min(9, LADDER_CNT); ++i)
196 s = strcat(s, "+-----");
197#if LADDER_CNT > 9
198 for (i = 1; i <= LADDER_CNT - 9; ++i)
199 s = strcat(s, "+------");
200#endif
201
202 s = strcat(s, "+--------------+--------------------\n");
203
204 for (i = 0; i < LADDER_SIZE; ++i)
205 {
206 temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i]));
207 tokenize_console(temp_s);
208
209 if (argv(LADDER_CNT + 1) == "") // total is 0, skip
210 continue;
211
212 s = strcat(s, strpad(4, count_ordinal(i + 1)), "^3| ^7"); // pos
213 s = strcat(s, strpad(7, argv(LADDER_CNT + 1)), "^3| ^7"); // total
214
215 for (j = 1; j <= min(9, LADDER_CNT); ++j)
216 s = strcat(s, strpad(4, argv(j)), "^3| ^7"); // 1st, 2nd, 3rd etc cnt
217
218#if LADDER_CNT > 9
219 for (j = 10; j <= LADDER_CNT; ++j)
220 s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); // 1st, 2nd, 3rd etc cnt
221#endif
222
223 s = strcat(s, strpad(13, argv(0)), "^3| ^7"); // speed award cnt
224 s = strcat(s, uid2name(top_uids[i]), "\n"); // name
225 }
226
228
229 if (s == "") return "No ladder on this server!\n";
230 else return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
231}
232
234{
235 if(autocvar_g_maplist == "")
236 return "^7Map list is empty";
237
238 string maplist = "";
239 int mapcount = 0;
241 {
242 string col = (i % 2) ? "^2" : "^3";
243 maplist = cons(maplist, strcat(col, it));
244 mapcount += 1;
245 });
246
248 return sprintf("^7Maps in list (%d): %s\n", mapcount, maplist);
249}
250
251const int LSMAPS_MAX = 250;
252string getlsmaps()
253{
254 string lsmaps = "", col;
255 bool newmaps = false;
256 int added = 0;
257
258 for (int i = 0; i < MapInfo_count; ++i)
259 {
261 {
262 ++added;
263
264 if(added > LSMAPS_MAX)
265 continue; // we still get the added count, but skip the actual processing
266
267 // todo: Check by play count of maps for other gametypes?
269 {
270 newmaps = true;
271 if (i % 2) col = "^4*"; else col = "^5*";
272 }
273 else
274 {
275 if (i % 2) col = "^2"; else col = "^3";
276 }
277
278 lsmaps = cons(lsmaps, strcat(col, MapInfo_Map_bspname));
279 }
280 }
281
282 if(added > LSMAPS_MAX)
283 lsmaps = sprintf("%s ^7(%d not listed)", lsmaps, added - LSMAPS_MAX);
284
286 return sprintf("^7Maps available (%d)%s: %s\n", added, (newmaps ? " (New maps have asterisks marked in blue)" : ""), lsmaps);
287}
288
290{
291 string monsterlist = "";
292
293 FOREACH(Monsters, it != MON_Null && !(it.spawnflags & MON_FLAG_HIDDEN),
294 {
295 string col = ((i % 2) ? "^2" : "^3");
296 monsterlist = sprintf("%s%s%s ", monsterlist, col, it.netname);
297 });
298
299 return sprintf("^7Monsters available: %s\n", monsterlist);
300}
301
302/*
303=============
304GetCvars
305=============
306Superseded by REPLICATE
307Called with:
308 0: sends the request
309 >0: receives a cvar from name=argv(f) value=argv(f+1)
310*/
311void GetCvars_handleString(entity this, entity store, string thisname, float f, .string field, string name)
312{
313 if (f < 0)
314 {
315 strfree(store.(field));
316 }
317 else if (f > 0)
318 {
319 if (thisname == name)
320 {
321 strcpy(store.(field), argv(f + 1));
322 }
323 }
324 else
325 stuffcmd(this, strcat("cl_cmd sendcvar ", name, "\n"));
326}
327void GetCvars_handleString_Fixup(entity this, entity store, string thisname, float f, .string field, string name, string(entity, string) func)
328{
329 GetCvars_handleString(this, store, thisname, f, field, name);
330 if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
331 if (thisname == name)
332 {
333 string s = func(this, strcat(store.(field)));
334 if (s != store.(field))
335 {
336 strcpy(store.(field), s);
337 }
338 }
339}
340void GetCvars_handleFloat(entity this, entity store, string thisname, float f, .float field, string name)
341{
342 if (f < 0)
343 {
344 }
345 else if (f > 0)
346 {
347 if (thisname == name)
348 store.(field) = stof(argv(f + 1));
349 }
350 else
351 stuffcmd(this, strcat("cl_cmd sendcvar ", name, "\n"));
352}
353void GetCvars_handleFloatOnce(entity this, entity store, string thisname, float f, .float field, string name)
354{
355 if (f < 0)
356 {
357 }
358 else if (f > 0)
359 {
360 if (thisname == name)
361 {
362 if (!store.(field))
363 {
364 store.(field) = stof(argv(f + 1));
365 if (!store.(field))
366 store.(field) = -1;
367 }
368 }
369 }
370 else
371 {
372 if (!store.(field))
373 stuffcmd(this, strcat("cl_cmd sendcvar ", name, "\n"));
374 }
375}
376
380void GetCvars(entity this, entity store, int f)
381{
382 string s = string_null;
383
384 if (f == 0)
385 LOG_INFO("Warning: requesting cvar values is deprecated. Client should send them automatically using REPLICATE.\n");
386
387 if (f > 0)
388 s = strcat(argv(f));
389
390 get_cvars_f = f;
391 get_cvars_s = s;
393
394 Notification_GetCvars(this, store);
395
396 ReplicateVars(this, store, s, f);
397 if (f > 0)
398 ReplicateVars_ApplyChange(this, store, s, f);
399}
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define g_race
Definition race.qh:48
#define M_ARGV(x, type)
Definition events.qh:17
#define CTS_RECORD
Definition util.qh:98
#define TIME_ENCODED_TOSTRING(n, compact)
Definition util.qh:96
#define RACE_RECORD
Definition util.qh:97
const int RANKINGS_CNT
Definition constants.qh:31
ERASEABLE string count_ordinal(int interval)
Definition counting.qh:66
#define g_cts
Definition cts.qh:36
#define tokenize_console
void GetCvars_handleFloatOnce(entity this, entity store, string thisname, float f,.float field, string name)
string getmonsterlist()
string getrecords(int page)
Definition getreplies.qc:35
void GetCvars_handleString(entity this, entity store, string thisname, float f,.string field, string name)
string getladder()
Definition getreplies.qc:71
void GetCvars_handleFloat(entity this, entity store, string thisname, float f,.float field, string name)
void GetCvars(entity this, entity store, int f)
string getlsmaps()
void GetCvars_handleString_Fixup(entity this, entity store, string thisname, float f,.string field, string name, string(entity, string) func)
string getrankings()
Definition getreplies.qc:46
string getmaplist()
const int LSMAPS_MAX
const int LADDER_FIRSTPOINT
Definition getreplies.qh:9
float top_scores[LADDER_SIZE]
Definition getreplies.qh:14
const int LADDER_SIZE
Definition getreplies.qh:11
#define LADDER_CNT
Definition getreplies.qh:10
string top_uids[LADDER_SIZE]
Definition getreplies.qh:13
string GetMapname()
#define FOREACH_WORD(words, cond, body)
Definition iter.qh:33
#define FOREACH(list, cond, body)
Definition iter.qh:19
ACCUMULATE void ReplicateVars_ApplyChange(entity this, entity store, string thisname, int i)
Definition replicate.qh:28
#define LOG_INFO(...)
Definition log.qh:65
ERASEABLE string db_get(int db, string key)
Definition map.qh:91
ERASEABLE void db_put(int db, string key, string value)
Definition map.qh:101
float MapInfo_CheckMap(string s)
Definition mapinfo.qc:1510
bool MapInfo_Get_ByID(int i)
Definition mapinfo.qc:275
int MapInfo_ForbiddenFlags()
Definition mapinfo.qc:1664
void MapInfo_ClearTemps()
Definition mapinfo.qc:1639
float MapInfo_count
Definition mapinfo.qh:166
string MapInfo_Map_bspname
Definition mapinfo.qh:6
int MapInfo_Map_flags
Definition mapinfo.qh:15
string name
Definition menu.qh:30
float stof(string val,...)
float min(float f,...)
string ftos(float f)
float floor(float f)
string argv(float n)
const int MON_FLAG_HIDDEN
Definition monster.qh:20
string string_null
Definition nil.qh:9
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
void Notification_GetCvars(entity this, entity store)
Definition all.qc:767
void ReplicateVars(bool would_destroy)
Definition all.qh:895
#define stuffcmd(cl,...)
Definition progsdefs.qh:23
#define autocvar_g_maplist
Definition mapvoting.qh:3
float get_cvars_f
Definition events.qh:346
string get_cvars_s
Definition events.qh:347
float race_readTime(string map, float pos)
Definition race.qc:69
string race_readName(string map, float pos)
Definition race.qc:129
string uid2name(string myuid)
Definition race.qc:36
string race_readUID(string map, float pos)
Definition race.qc:74
#define strfree(this)
Definition string.qh:59
#define strcpy(this, s)
Definition string.qh:52
ERASEABLE string cons(string a, string b)
Definition string.qh:276
float TemporaryDB
Definition world.qh:129
float ServerProgsDB
Definition world.qh:128