]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/command/getreplies.qc
Purge autocvars.qh from the codebase, cvars are defined in the headers of the feature...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / command / getreplies.qc
1 #include "getreplies.qh"
2
3 #include <common/command/_mod.qh>
4 #include <common/constants.qh>
5 #include <common/gamemodes/_mod.qh>
6 #include <common/monsters/_mod.qh>
7 #include <common/net_linked.qh>
8 #include <common/notifications/all.qh>
9 #include <common/playerstats.qh>
10 #include <common/stats.qh>
11 #include <common/util.qh>
12 #include <common/weapons/_all.qh>
13 #include <common/wepent.qh>
14 #include <server/command/getreplies.qh>
15 #include <server/intermission.qh>
16 #include <server/main.qh>
17 #include <server/mapvoting.qh>
18 #include <server/mutators/_mod.qh>
19 #include <server/race.qh>
20 #include <server/weapons/selection.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 game modes 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
35 string getrecords(int page)  // 50 records per page
36 {
37         string s = "";
38
39         MUTATOR_CALLHOOK(GetRecords, page, s);
40         s = M_ARGV(1, string);
41
42         MapInfo_ClearTemps();
43
44         if (s == "" && page == 0)
45                 return "No records are available on this server for the current game mode.\n";
46         return s;
47 }
48
49 string getrankings()
50 {
51         float t, i;
52         string n, s, p, map;
53
54         map = GetMapname();
55
56         s = "";
57         for (i = 1; i <= RANKINGS_CNT; ++i)
58         {
59                 t = race_readTime(map, i);
60
61                 if (t == 0) continue;
62
63                 n = race_readName(map, i);
64                 p = count_ordinal(i);
65                 s = strcat(s, strpad(8, p), " ", strpad(-8, TIME_ENCODED_TOSTRING(t)), " ", n, "\n");
66         }
67
68         MapInfo_ClearTemps();
69
70         if (s == "") return strcat("No records are available for the map: ", map, "\n");
71         else return strcat("Records for ", map, ":\n", s);
72 }
73
74 string getladder()
75 {
76         int i, j, k, uidcnt = 0, thiscnt;
77         string s, temp_s, rr, myuid, thisuid;
78
79         rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
80
81         for (k = 0; k < MapInfo_count; ++k)
82         {
83                 if (MapInfo_Get_ByID(k))
84                 {
85                         for (i = 0; i <= LADDER_CNT; ++i) // i = 0 because it is the speed award
86                         {
87                                 if (i == 0)                   // speed award
88                                 {
89                                         if (stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/speed"))) == 0) continue;
90
91                                         myuid = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, rr, "speed/crypto_idfp"));
92                                 }
93                                 else  // normal record, if it exists (else break)
94                                 {
95                                         if (race_readTime(MapInfo_Map_bspname, i) == 0) continue;
96
97                                         myuid = race_readUID(MapInfo_Map_bspname, i);
98                                 }
99
100                                 // string s contains:
101                                 // arg 0 = # of speed recs
102                                 // arg 1 = # of 1st place recs
103                                 // arg 2 = # of 2nd place recs
104                                 // ... etc
105                                 // LADDER_CNT+1 = total points
106
107                                 temp_s = db_get(TemporaryDB, strcat("ladder", myuid));
108
109                                 if (temp_s == "")
110                                 {
111                                         db_put(TemporaryDB, strcat("uid", ftos(uidcnt)), myuid);
112                                         ++uidcnt;
113
114                                         for (j = 0; j <= LADDER_CNT + 1; ++j)
115                                         {
116                                                 if (j != LADDER_CNT + 1) temp_s = strcat(temp_s, "0 ");
117                                                 else temp_s = strcat(temp_s, "0");
118                                         }
119                                 }
120
121                                 tokenize_console(temp_s);
122                                 s = "";
123
124                                 if (i == 0)                                         // speed award
125                                 {
126                                         for (j = 0; j <= LADDER_CNT; ++j)               // loop over each arg in the string
127                                         {
128                                                 if (j == 0)                                 // speed award
129                                                         s = strcat(s, ftos(stof(argv(j)) + 1)); // add 1 to speed rec count and write
130                                                 else s = strcat(s, " ", argv(j));           // just copy over everything else
131                                         }
132                                 }
133                                 else  // record
134                                 {
135                                         for (j = 0; j <= LADDER_CNT; ++j)                    // loop over each arg in the string
136                                         {
137                                                 if (j == 0) s = strcat(s, argv(j));              // speed award, dont prefix with " "
138                                                 else if (j == i)                                 // wanted rec!
139                                                         s = strcat(s, " ", ftos(stof(argv(j)) + 1)); // update argv(j)
140                                                 else s = strcat(s, " ", argv(j));                // just copy over everything else
141                                         }
142                                 }
143
144                                 // total points are (by default) calculated like this:
145                                 // speedrec = floor(100 / 10) = 10 points
146                                 // 1st place = floor(100 / 1) = 100 points
147                                 // 2nd place = floor(100 / 2) = 50 points
148                                 // 3rd place = floor(100 / 3) = 33 points
149                                 // 4th place = floor(100 / 4) = 25 points
150                                 // 5th place = floor(100 / 5) = 20 points
151                                 // ... etc
152
153                                 if (i == 0) s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + LADDER_FIRSTPOINT / 10)); // speed award, add LADDER_FIRSTPOINT / 10 points
154                                 else s = strcat(s, " ", ftos(stof(argv(LADDER_CNT + 1)) + floor(LADDER_FIRSTPOINT / i)));  // record, add LADDER_FIRSTPOINT / i points
155
156                                 db_put(TemporaryDB, strcat("ladder", myuid), s);
157                         }
158                 }
159         }
160
161         for (i = 0; i <= uidcnt; ++i)  // for each known uid
162         {
163                 thisuid = db_get(TemporaryDB, strcat("uid", ftos(i)));
164                 temp_s = db_get(TemporaryDB, strcat("ladder", thisuid));
165                 tokenize_console(temp_s);
166                 thiscnt = stof(argv(LADDER_CNT + 1));
167
168                 if (thiscnt > top_scores[LADDER_SIZE - 1])
169                 {
170                         for (j = 0; j < LADDER_SIZE; ++j)  // for each place in ladder
171                         {
172                                 if (thiscnt > top_scores[j])
173                                 {
174                                         for (k = LADDER_SIZE - 1; k >= j; --k)
175                                         {
176                                                 top_uids[k] = top_uids[k - 1];
177                                                 top_scores[k] = top_scores[k - 1];
178                                         }
179
180                                         top_uids[j] = thisuid;
181                                         top_scores[j] = thiscnt;
182                                         break;
183                                 }
184                         }
185                 }
186         }
187
188         s = "^3-----------------------\n\n";
189
190         s = strcat(s, "Pos ^3|");
191         s = strcat(s, " ^7Total  ^3|");
192
193         for (i = 1; i <= LADDER_CNT; ++i)
194                 s = strcat(s, " ^7", count_ordinal(i), " ^3|");
195         s = strcat(s, " ^7Speed awards ^3| ^7Name");
196         s = strcat(s, "\n^3----+--------");
197
198         for (i = 1; i <= min(9, LADDER_CNT); ++i)
199                 s = strcat(s, "+-----");
200 #if LADDER_CNT > 9
201                 for (i = 1; i <= LADDER_CNT - 9; ++i)
202                         s = strcat(s, "+------");
203 #endif
204
205         s = strcat(s, "+--------------+--------------------\n");
206
207         for (i = 0; i < LADDER_SIZE; ++i)
208         {
209                 temp_s = db_get(TemporaryDB, strcat("ladder", top_uids[i]));
210                 tokenize_console(temp_s);
211
212                 if (argv(LADDER_CNT + 1) == "")                           // total is 0, skip
213                         continue;
214
215                 s = strcat(s, strpad(4, count_ordinal(i + 1)), "^3| ^7"); // pos
216                 s = strcat(s, strpad(7, argv(LADDER_CNT + 1)), "^3| ^7"); // total
217
218                 for (j = 1; j <= min(9, LADDER_CNT); ++j)
219                         s = strcat(s, strpad(4, argv(j)), "^3| ^7");          // 1st, 2nd, 3rd etc cnt
220
221 #if LADDER_CNT > 9
222                         for (j = 10; j <= LADDER_CNT; ++j)
223                                 s = strcat(s, strpad(4, argv(j)), " ^3| ^7"); // 1st, 2nd, 3rd etc cnt
224 #endif
225
226                 s = strcat(s, strpad(13, argv(0)), "^3| ^7");         // speed award cnt
227                 s = strcat(s, uid2name(top_uids[i]), "\n");           // name
228         }
229
230         MapInfo_ClearTemps();
231
232         if (s == "") return "No ladder on this server!\n";
233         else return strcat("Top ", ftos(LADDER_SIZE), " ladder rankings:\n", s);
234 }
235
236 string getmaplist()
237 {
238         string maplist = "", col;
239         int i, argc;
240
241         argc = tokenize_console(autocvar_g_maplist);
242         for (i = 0; i < argc; ++i)
243         {
244                 if (MapInfo_CheckMap(argv(i)))
245                 {
246                         if (i % 2) col = "^2"; else col = "^3";
247                         maplist = sprintf("%s%s%s ", maplist, col, argv(i));
248                 }
249         }
250
251         MapInfo_ClearTemps();
252         return sprintf("^7Maps in list: %s\n", maplist);
253 }
254
255 const int LSMAPS_MAX = 250;
256 string getlsmaps()
257 {
258         string lsmaps = "", col;
259         bool newmaps = false;
260         int added = 0;
261
262         for (int i = 0; i < MapInfo_count; ++i)
263         {
264                 if ((MapInfo_Get_ByID(i)) && !(MapInfo_Map_flags & MapInfo_ForbiddenFlags()))
265                 {
266                         ++added;
267
268                         if(added > LSMAPS_MAX)
269                                 continue; // we still get the added count, but skip the actual processing
270
271                         // todo: Check by play count of maps for other game types?
272                         if((g_race || g_cts) && !race_readTime(MapInfo_Map_bspname, 1))
273                         {
274                                 newmaps = true;
275                                 if (i % 2) col = "^4*"; else col = "^5*";
276                         }
277                         else
278                         {
279                                 if (i % 2) col = "^2"; else col = "^3";
280                         }
281
282                         lsmaps = sprintf("%s%s%s ", lsmaps, col, MapInfo_Map_bspname);
283                 }
284         }
285
286         if(added > LSMAPS_MAX)
287                 lsmaps = sprintf("%s^7(%d not listed)", lsmaps, added - LSMAPS_MAX);
288
289         MapInfo_ClearTemps();
290         return sprintf("^7Maps available (%d)%s: %s\n", added, (newmaps ? " (New maps have asterisks marked in blue)" : ""), lsmaps);
291 }
292
293 string getmonsterlist()
294 {
295         string monsterlist = "";
296
297         FOREACH(Monsters, it != MON_Null && !(it.spawnflags & MON_FLAG_HIDDEN),
298         {
299                 string col = ((i % 2) ? "^2" : "^3");
300                 monsterlist = sprintf("%s%s%s ", monsterlist, col, it.netname);
301         });
302
303         return sprintf("^7Monsters available: %s\n", monsterlist);
304 }
305
306 /*
307 =============
308 GetCvars
309 =============
310 Called with:
311   0:  sends the request
312   >0: receives a cvar from name=argv(f) value=argv(f+1)
313 */
314 void GetCvars_handleString(entity this, entity store, string thisname, float f, .string field, string name)
315 {
316         if (f < 0)
317         {
318                 strfree(store.(field));
319         }
320         else if (f > 0)
321         {
322                 if (thisname == name)
323                 {
324                         strcpy(store.(field), argv(f + 1));
325                 }
326         }
327         else
328                 stuffcmd(this, strcat("cl_cmd sendcvar ", name, "\n"));
329 }
330 void GetCvars_handleString_Fixup(entity this, entity store, string thisname, float f, .string field, string name, string(entity, string) func)
331 {
332         GetCvars_handleString(this, store, thisname, f, field, name);
333         if (f >= 0) // also initialize to the fitting value for "" when sending cvars out
334                 if (thisname == name)
335                 {
336                         string s = func(this, strcat1(store.(field)));
337                         if (s != store.(field))
338                         {
339                                 strcpy(store.(field), s);
340                         }
341                 }
342 }
343 void GetCvars_handleFloat(entity this, entity store, string thisname, float f, .float field, string name)
344 {
345         if (f < 0)
346         {
347         }
348         else if (f > 0)
349         {
350                 if (thisname == name)
351                         store.(field) = stof(argv(f + 1));
352         }
353         else
354                 stuffcmd(this, strcat("cl_cmd sendcvar ", name, "\n"));
355 }
356 void GetCvars_handleFloatOnce(entity this, entity store, string thisname, float f, .float field, string name)
357 {
358         if (f < 0)
359         {
360         }
361         else if (f > 0)
362         {
363                 if (thisname == name)
364                 {
365                         if (!store.(field))
366                         {
367                                 store.(field) = stof(argv(f + 1));
368                                 if (!store.(field))
369                                         store.(field) = -1;
370                         }
371                 }
372         }
373         else
374         {
375                 if (!store.(field))
376                         stuffcmd(this, strcat("cl_cmd sendcvar ", name, "\n"));
377         }
378 }
379 string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(entity this, string wo)
380 {
381         string o = W_FixWeaponOrder_ForceComplete(wo);
382         strcpy(CS(this).weaponorder_byimpulse, W_FixWeaponOrder_BuildImpulseList(o));
383         return o;
384 }
385
386 /**
387  * @param f -1: cleanup, 0: request, 1: receive
388  */
389 void GetCvars(entity this, entity store, int f)
390 {
391         string s = string_null;
392
393         if (f == 0)
394                 LOG_INFO("Warning: requesting cvar values is deprecated. Client should send them automatically using REPLICATE.\n");
395
396         if (f > 0)
397                 s = strcat1(argv(f));
398
399         get_cvars_f = f;
400         get_cvars_s = s;
401         MUTATOR_CALLHOOK(GetCvars);
402
403         Notification_GetCvars(this);
404
405         ReplicateVars(this, store, s, f);
406
407         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
408         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[0], "cl_weaponpriority0", W_FixWeaponOrder_AllowIncomplete);
409         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[1], "cl_weaponpriority1", W_FixWeaponOrder_AllowIncomplete);
410         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[2], "cl_weaponpriority2", W_FixWeaponOrder_AllowIncomplete);
411         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[3], "cl_weaponpriority3", W_FixWeaponOrder_AllowIncomplete);
412         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[4], "cl_weaponpriority4", W_FixWeaponOrder_AllowIncomplete);
413         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[5], "cl_weaponpriority5", W_FixWeaponOrder_AllowIncomplete);
414         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[6], "cl_weaponpriority6", W_FixWeaponOrder_AllowIncomplete);
415         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete);
416         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete);
417         GetCvars_handleString_Fixup(this, store, s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete);
418
419         GetCvars_handleFloat(this, store, s, f, cvar_cl_allow_uidtracking, "cl_allow_uidtracking");
420
421         // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early)
422         if (f > 0)
423         {
424                 if (s == "cl_weaponpriority")
425                 {
426                         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
427                         {
428                                 .entity weaponentity = weaponentities[slot];
429                                 if (this.(weaponentity) && (this.(weaponentity).m_weapon != WEP_Null || slot == 0))
430                                         this.(weaponentity).m_switchweapon = w_getbestweapon(this, weaponentity);
431                         }
432                 }
433                 if (s == "cl_allow_uidtracking")
434                         PlayerStats_GameReport_AddPlayer(this);
435                 //if (s == "cl_gunalign")
436                         //W_ResetGunAlign(this, store.cvar_cl_gunalign);
437         }
438 }