]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/server/gamecommand.qc
Cvar the distance by which prey are separated in the stomach. Setting the cvar to...
[voretournament/voretournament.git] / data / qcsrc / server / gamecommand.qc
1 string GotoMap(string m);\r
2 void race_DeleteTime(float pos);\r
3 \r
4 float FullTraceFraction(vector a, vector mi, vector ma, vector b)\r
5 {\r
6         vector c;\r
7         float white, black;\r
8 \r
9         white = 0.001;\r
10         black = 0.001;\r
11 \r
12         c = a;\r
13 \r
14         float n, m;\r
15         n = m = 0;\r
16 \r
17         while(vlen(c - b) > 1)\r
18         {\r
19                 ++m;\r
20 \r
21                 tracebox(c, mi, ma, b, MOVE_WORLDONLY, world);\r
22                 ++n;\r
23 \r
24                 if(!trace_startsolid)\r
25                 {\r
26                         black += vlen(trace_endpos - c);\r
27                         c = trace_endpos;\r
28                 }\r
29 \r
30                 n += tracebox_inverted(c, mi, ma, b, MOVE_WORLDONLY, world);\r
31 \r
32                 white += vlen(trace_endpos - c);\r
33                 c = trace_endpos;\r
34         }\r
35 \r
36         if(n > 200)\r
37                 dprint("HOLY SHIT! FullTraceFraction: ", ftos(n), " total traces, ", ftos(m), " iterations\n");\r
38 \r
39         return white / (black + white);\r
40 }\r
41 \r
42 float RadarMapAtPoint_Trace(float x, float y, float w, float h, float zmin, float zsize, float q)\r
43 {\r
44         vector a, b, mi, ma;\r
45 \r
46         mi = '0 0 0';\r
47         ma = '1 0 0' * w + '0 1 0' * h;\r
48         a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;\r
49         b = '1 0 0' * x + '0 1 0' * y + '0 0 1' * (zsize + zmin);\r
50 \r
51         return FullTraceFraction(a, mi, ma, b);\r
52 }\r
53 float RadarMapAtPoint_LineBlock(float x, float y, float w, float h, float zmin, float zsize, float q)\r
54 {\r
55         vector o, mi, ma;\r
56         float i, r;\r
57         vector dz;\r
58 \r
59         q = 256 * q - 1;\r
60         // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value\r
61 \r
62         mi = '0 0 0';\r
63         dz = (zsize / q) * '0 0 1';\r
64         ma = '1 0 0' * w + '0 1 0' * h + dz;\r
65         o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;\r
66 \r
67         if(x < world.absmin_x - w)\r
68                 return 0;\r
69         if(y < world.absmin_y - h)\r
70                 return 0;\r
71         if(x > world.absmax_x)\r
72                 return 0;\r
73         if(y > world.absmax_y)\r
74                 return 0;\r
75 \r
76         r = 0;\r
77         for(i = 0; i < q; ++i)\r
78         {\r
79                 vector v1, v2;\r
80                 v1 = v2 = o + dz * i + mi;\r
81                 v1_x += random() * (ma_x - mi_x);\r
82                 v1_y += random() * (ma_y - mi_y);\r
83                 v1_z += random() * (ma_z - mi_z);\r
84                 v2_x += random() * (ma_x - mi_x);\r
85                 v2_y += random() * (ma_y - mi_y);\r
86                 v2_z += random() * (ma_z - mi_z);\r
87                 traceline(v1, v2, MOVE_WORLDONLY, world);\r
88                 if(trace_startsolid || trace_fraction < 1)\r
89                         ++r;\r
90         }\r
91         return r / q;\r
92 }\r
93 float RadarMapAtPoint_Block(float x, float y, float w, float h, float zmin, float zsize, float q)\r
94 {\r
95         vector o, mi, ma;\r
96         float i, r;\r
97         vector dz;\r
98 \r
99         q = 256 * q - 1;\r
100         // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value\r
101 \r
102         mi = '0 0 0';\r
103         dz = (zsize / q) * '0 0 1';\r
104         ma = '1 0 0' * w + '0 1 0' * h + dz;\r
105         o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;\r
106 \r
107         if(x < world.absmin_x - w)\r
108                 return 0;\r
109         if(y < world.absmin_y - h)\r
110                 return 0;\r
111         if(x > world.absmax_x)\r
112                 return 0;\r
113         if(y > world.absmax_y)\r
114                 return 0;\r
115 \r
116         r = 0;\r
117         for(i = 0; i < q; ++i)\r
118         {\r
119                 tracebox(o + dz * i, mi, ma, o + dz * i, MOVE_WORLDONLY, world);\r
120                 if(trace_startsolid)\r
121                         ++r;\r
122         }\r
123         return r / q;\r
124 }\r
125 float RadarMapAtPoint_Sample(float x, float y, float w, float h, float zmin, float zsize, float q)\r
126 {\r
127         vector a, b, mi, ma;\r
128 \r
129         q *= 4; // choose q so it matches the regular algorithm in speed\r
130 \r
131         q = 256 * q - 1;\r
132         // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value\r
133 \r
134         mi = '0 0 0';\r
135         ma = '1 0 0' * w + '0 1 0' * h;\r
136         a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;\r
137         b = '1 0 0' * w + '0 1 0' * h + '0 0 1' * zsize;\r
138 \r
139         float c, i;\r
140         c = 0;\r
141 \r
142         for(i = 0; i < q; ++i)\r
143         {\r
144                 vector v;\r
145                 v_x = a_x + random() * b_x;\r
146                 v_y = a_y + random() * b_y;\r
147                 v_z = a_z + random() * b_z;\r
148                 traceline(v, v, MOVE_WORLDONLY, world);\r
149                 if(trace_startsolid)\r
150                         ++c;\r
151         }\r
152 \r
153         return c / q;\r
154 }\r
155 \r
156 // FF is contained twice, to map 256 to FF too\r
157 // removes the need to bound()\r
158 string doublehex = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFFFF";\r
159 \r
160 float RADAR_WIDTH_MAX = 2048;\r
161 float RADAR_HEIGHT_MAX = 2048;\r
162 float sharpen_buffer[RADAR_WIDTH_MAX * 3];\r
163 \r
164 void sharpen_set(float x, float v)\r
165 {\r
166         sharpen_buffer[x + 2 * RADAR_WIDTH_MAX] = v;\r
167 }\r
168 \r
169 float sharpen_getpixel(float x, float y)\r
170 {\r
171         if(x < 0)\r
172                 return 0;\r
173         if(x >= RADAR_WIDTH_MAX)\r
174                 return 0;\r
175         if(y < 0)\r
176                 return 0;\r
177         if(y > 2)\r
178                 return 0;\r
179         return sharpen_buffer[x + y * RADAR_WIDTH_MAX];\r
180 }\r
181 \r
182 float sharpen_get(float x, float a)\r
183 {\r
184         float sum;\r
185         sum = sharpen_getpixel(x, 1);\r
186         if(a == 0)\r
187                 return sum;\r
188         sum *= (8 + 1/a);\r
189         sum -= sharpen_getpixel(x - 1, 0);\r
190         sum -= sharpen_getpixel(x - 1, 1);\r
191         sum -= sharpen_getpixel(x - 1, 2);\r
192         sum -= sharpen_getpixel(x + 1, 0);\r
193         sum -= sharpen_getpixel(x + 1, 1);\r
194         sum -= sharpen_getpixel(x + 1, 2);\r
195         sum -= sharpen_getpixel(x, 0);\r
196         sum -= sharpen_getpixel(x, 2);\r
197         return bound(0, sum * a, 1);\r
198 }\r
199 \r
200 void sharpen_shift(float w)\r
201 {\r
202         float i;\r
203         for(i = 0; i < w; ++i)\r
204         {\r
205                 sharpen_buffer[i] = sharpen_buffer[i + RADAR_WIDTH_MAX];\r
206                 sharpen_buffer[i + RADAR_WIDTH_MAX] = sharpen_buffer[i + 2 * RADAR_WIDTH_MAX];\r
207                 sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;\r
208         }\r
209 }\r
210 \r
211 void sharpen_init(float w)\r
212 {\r
213         float i;\r
214         for(i = 0; i < w; ++i)\r
215         {\r
216                 sharpen_buffer[i] = 0;\r
217                 sharpen_buffer[i + RADAR_WIDTH_MAX] = 0;\r
218                 sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;\r
219         }\r
220 }\r
221 \r
222 entity radarmapper;\r
223 void RadarMap_Next()\r
224 {\r
225         if(radarmapper.count & 4)\r
226         {\r
227                 localcmd("quit\n");\r
228         }\r
229         else if(radarmapper.count & 2)\r
230         {\r
231                 localcmd(strcat("defer 1 \"sv_cmd radarmap --flags ", ftos(radarmapper.count), strcat(" --res ", ftos(radarmapper.size_x), " ", ftos(radarmapper.size_y), " --sharpen ", ftos(radarmapper.ltime), " --qual ", ftos(radarmapper.size_z)), "\"\n"));\r
232                 GotoNextMap();\r
233         }\r
234         remove(radarmapper);\r
235         radarmapper = world;\r
236 }\r
237 \r
238 // rough map entity\r
239 //   cnt: current line\r
240 //   size: pixel width/height\r
241 //   maxs: cell width/height\r
242 //   frame: counter\r
243 void RadarMap_Think()\r
244 {\r
245         float i, x, l;\r
246         string si;\r
247 \r
248         if(self.frame == 0)\r
249         {\r
250                 // initialize\r
251                 get_mi_min_max_texcoords(1);\r
252                 self.mins = mi_picmin;\r
253                 self.maxs_x = (mi_picmax_x - mi_picmin_x) / self.size_x;\r
254                 self.maxs_y = (mi_picmax_y - mi_picmin_y) / self.size_y;\r
255                 self.maxs_z = mi_max_z - mi_min_z;\r
256                 print("Picture mins/maxs: ", ftos(self.maxs_x), " and ", ftos(self.maxs_y), " should match\n");\r
257                 self.netname = strzone(strcat("gfx/", mi_shortname, "_radar.xpm"));\r
258                 if(!(self.count & 1))\r
259                 {\r
260                         self.cnt = fopen(self.netname, FILE_READ);\r
261                         if(self.cnt < 0)\r
262                                 self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.tga"), FILE_READ);\r
263                         if(self.cnt < 0)\r
264                                 self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.png"), FILE_READ);\r
265                         if(self.cnt < 0)\r
266                                 self.cnt = fopen(strcat("gfx/", mi_shortname, "_radar.jpg"), FILE_READ);\r
267                         if(self.cnt < 0)\r
268                                 self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.tga"), FILE_READ);\r
269                         if(self.cnt < 0)\r
270                                 self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.png"), FILE_READ);\r
271                         if(self.cnt < 0)\r
272                                 self.cnt = fopen(strcat("gfx/", mi_shortname, "_mini.jpg"), FILE_READ);\r
273                         if(self.cnt >= 0)\r
274                         {\r
275                                 fclose(self.cnt);\r
276 \r
277                                 print(self.netname, " already exists, aborting (you may want to specify --force)\n");\r
278                                 RadarMap_Next();\r
279                                 return;\r
280                         }\r
281                 }\r
282                 self.cnt = fopen(self.netname, FILE_WRITE);\r
283                 if(self.cnt < 0)\r
284                 {\r
285                         print("Error writing ", self.netname, "\n");\r
286                         remove(self);\r
287                         radarmapper = world;\r
288                         return;\r
289                 }\r
290                 print("Writing to ", self.netname, "...\n");\r
291                 fputs(self.cnt, "/* XPM */\n");\r
292                 fputs(self.cnt, "static char *RadarMap[] = {\n");\r
293                 fputs(self.cnt, "/* columns rows colors chars-per-pixel */\n");\r
294                 fputs(self.cnt, strcat("\"", ftos(self.size_x), " ", ftos(self.size_y), " 256 2\",\n"));\r
295                 for(i = 0; i < 256; ++i)\r
296                 {\r
297                         si = substring(doublehex, i*2, 2);\r
298                         fputs(self.cnt, strcat("\"", si, " c #", si, si, si, "\",\n"));\r
299                 }\r
300                 self.frame += 1;\r
301                 self.nextthink = time;\r
302                 sharpen_init(self.size_x);\r
303         }\r
304         else if(self.frame <= self.size_y)\r
305         {\r
306                 // fill the sharpen buffer with this line\r
307                 sharpen_shift(self.size_x);\r
308                 i = self.count & 24;\r
309 \r
310                 switch(i)\r
311                 {\r
312                         case 0:\r
313                         default:\r
314                                 for(x = 0; x < self.size_x; ++x)\r
315                                 {\r
316                                         l = RadarMapAtPoint_Block(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);\r
317                                         sharpen_set(x, l);\r
318                                 }\r
319                                 break;\r
320                         case 8:\r
321                                 for(x = 0; x < self.size_x; ++x)\r
322                                 {\r
323                                         l = RadarMapAtPoint_Trace(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);\r
324                                         sharpen_set(x, l);\r
325                                 }\r
326                                 break;\r
327                         case 16:\r
328                                 for(x = 0; x < self.size_x; ++x)\r
329                                 {\r
330                                         l = RadarMapAtPoint_Sample(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);\r
331                                         sharpen_set(x, l);\r
332                                 }\r
333                                 break;\r
334                         case 24:\r
335                                 for(x = 0; x < self.size_x; ++x)\r
336                                 {\r
337                                         l = RadarMapAtPoint_LineBlock(self.mins_x + x * self.maxs_x, self.mins_y + (self.size_y - self.frame) * self.maxs_y, self.maxs_x, self.maxs_y, self.mins_z, self.maxs_z, self.size_z);\r
338                                         sharpen_set(x, l);\r
339                                 }\r
340                                 break;\r
341                 }\r
342 \r
343                 // do we have enough lines?\r
344                 if(self.frame >= 2)\r
345                 {\r
346                         // write a pixel line\r
347                         fputs(self.cnt, "\"");\r
348                         for(x = 0; x < self.size_x; ++x)\r
349                         {\r
350                                 l = sharpen_get(x, self.ltime);\r
351                                 fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));\r
352                         }\r
353                         if(self.frame == self.size_y)\r
354                                 fputs(self.cnt, "\"\n");\r
355                         else\r
356                         {\r
357                                 fputs(self.cnt, "\",\n");\r
358                                 print(ftos(self.size_y - self.frame), " lines left\n");\r
359                         }\r
360                 }\r
361 \r
362                 // is this the last line? then write back the missing line\r
363                 if(self.frame == self.size_y)\r
364                 {\r
365                         sharpen_shift(self.size_x);\r
366                         // write a pixel line\r
367                         fputs(self.cnt, "\"");\r
368                         for(x = 0; x < self.size_x; ++x)\r
369                         {\r
370                                 l = sharpen_get(x, self.ltime);\r
371                                 fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));\r
372                         }\r
373                         if(self.frame == self.size_y)\r
374                                 fputs(self.cnt, "\"\n");\r
375                         else\r
376                         {\r
377                                 fputs(self.cnt, "\",\n");\r
378                                 print(ftos(self.size_y - self.frame), " lines left\n");\r
379                         }\r
380                 }\r
381 \r
382                 self.frame += 1;\r
383                 self.nextthink = time;\r
384         }\r
385         else\r
386         {\r
387                 // close the file\r
388                 fputs(self.cnt, "};\n");\r
389                 fclose(self.cnt);\r
390                 print("Finished. Please edit data/", self.netname, " with an image editing application and place it in the TGA format in the gfx folder.\n");\r
391                 RadarMap_Next();\r
392         }\r
393 }\r
394 \r
395 void RadarMap(float argc)\r
396 {\r
397         if(radarmapper)\r
398                 return;\r
399         float i;\r
400         radarmapper = spawn();\r
401         radarmapper.classname = "radarmapper";\r
402         radarmapper.think = RadarMap_Think;\r
403         radarmapper.nextthink = time;\r
404         radarmapper.count = 8; // default to the --trace method, as it is faster now\r
405         radarmapper.ltime = 1;\r
406         radarmapper.size_x = 512;\r
407         radarmapper.size_y = 512;\r
408         radarmapper.size_z = 1;\r
409 \r
410         for(i = 1; i < argc; ++i)\r
411         {\r
412                 if(argv(i) == "--force")\r
413                         radarmapper.count |= 1;\r
414                 else if(argv(i) == "--loop")\r
415                         radarmapper.count |= 2;\r
416                 else if(argv(i) == "--quit")\r
417                         radarmapper.count |= 4;\r
418                 else if(argv(i) == "--block")\r
419                 {\r
420                         radarmapper.count &~= 24;\r
421                 }\r
422                 else if(argv(i) == "--trace")\r
423                 {\r
424                         radarmapper.count &~= 24;\r
425                         radarmapper.count |= 8;\r
426                 }\r
427                 else if(argv(i) == "--sample")\r
428                 {\r
429                         radarmapper.count &~= 24;\r
430                         radarmapper.count |= 16;\r
431                 }\r
432                 else if(argv(i) == "--lineblock")\r
433                 {\r
434                         radarmapper.count |= 24;\r
435                 }\r
436                 else if(argv(i) == "--flags") // for the recursive call\r
437                 {\r
438                         ++i;\r
439                         radarmapper.count = stof(argv(i));\r
440                 }\r
441                 else if(argv(i) == "--sharpen") // for the recursive call\r
442                 {\r
443                         ++i;\r
444                         radarmapper.ltime = stof(argv(i));\r
445                 }\r
446                 else if(argv(i) == "--res") // resolution\r
447                 {\r
448                         ++i;\r
449                         radarmapper.size_x = stof(argv(i));\r
450                         ++i;\r
451                         radarmapper.size_y = stof(argv(i));\r
452                 }\r
453                 else if(argv(i) == "--qual") // quality multiplier\r
454                 {\r
455                         ++i;\r
456                         radarmapper.size_z = stof(argv(i));\r
457                 }\r
458                 else\r
459                 {\r
460                         remove(radarmapper);\r
461                         radarmapper = world;\r
462                         print("Usage: sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample | --lineblock] [--sharpen N] [--res W H] [--qual Q]\n");\r
463                         print("The quality factor Q is roughly proportional to the time taken.\n");\r
464                         print("--trace supports no quality factor; its result should look like --block with infinite quality factor.\n");\r
465                         print("--block \n");\r
466                         return;\r
467                 }\r
468         }\r
469 \r
470         print("Radarmap entity spawned.\n");\r
471 }\r
472 \r
473 void BBox()\r
474 {\r
475         print("Original size: ", ftos(world.absmin_x), " ", ftos(world.absmin_y), " ", ftos(world.absmin_z));\r
476         print(" ", ftos(world.absmax_x), " ", ftos(world.absmax_y), " ", ftos(world.absmax_z), "\n");\r
477         print("Currently set size: ", ftos(world.mins_x), " ", ftos(world.mins_y), " ", ftos(world.mins_z));\r
478         print(" ", ftos(world.maxs_x), " ", ftos(world.maxs_y), " ", ftos(world.maxs_z), "\n");\r
479         print("Solid bounding box size:");\r
480 \r
481         tracebox('1 0 0' * world.absmin_x,\r
482                  '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,\r
483                  '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,\r
484                  '1 0 0' * world.absmax_x,\r
485                          MOVE_WORLDONLY,\r
486                          world);\r
487         if(trace_startsolid)\r
488                 print(" ", ftos(world.absmin_x));\r
489         else\r
490                 print(" ", ftos(trace_endpos_x));\r
491 \r
492         tracebox('0 1 0' * world.absmin_y,\r
493                  '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,\r
494                  '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,\r
495                  '0 1 0' * world.absmax_y,\r
496                          MOVE_WORLDONLY,\r
497                          world);\r
498         if(trace_startsolid)\r
499                 print(" ", ftos(world.absmin_y));\r
500         else\r
501                 print(" ", ftos(trace_endpos_y));\r
502 \r
503         tracebox('0 0 1' * world.absmin_z,\r
504                  '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,\r
505                  '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,\r
506                  '0 0 1' * world.absmax_z,\r
507                          MOVE_WORLDONLY,\r
508                          world);\r
509         if(trace_startsolid)\r
510                 print(" ", ftos(world.absmin_z));\r
511         else\r
512                 print(" ", ftos(trace_endpos_z));\r
513 \r
514         tracebox('1 0 0' * world.absmax_x,\r
515                  '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,\r
516                  '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,\r
517                  '1 0 0' * world.absmin_x,\r
518                          MOVE_WORLDONLY,\r
519                          world);\r
520         if(trace_startsolid)\r
521                 print(" ", ftos(world.absmax_x));\r
522         else\r
523                 print(" ", ftos(trace_endpos_x));\r
524 \r
525         tracebox('0 1 0' * world.absmax_y,\r
526                  '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,\r
527                  '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,\r
528                  '0 1 0' * world.absmin_y,\r
529                          MOVE_WORLDONLY,\r
530                          world);\r
531         if(trace_startsolid)\r
532                 print(" ", ftos(world.absmax_y));\r
533         else\r
534                 print(" ", ftos(trace_endpos_y));\r
535 \r
536         tracebox('0 0 1' * world.absmax_z,\r
537                  '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,\r
538                  '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,\r
539                  '0 0 1' * world.absmin_z,\r
540                          MOVE_WORLDONLY,\r
541                          world);\r
542         if(trace_startsolid)\r
543                 print(" ", ftos(world.absmax_z));\r
544         else\r
545                 print(" ", ftos(trace_endpos_z));\r
546 \r
547         print("\n");\r
548 }\r
549 \r
550 void EffectIndexDump()\r
551 {\r
552         float d;\r
553         float fh;\r
554         string s;\r
555 \r
556         d = db_create();\r
557 \r
558         print("begin of effects list\n");\r
559         db_put(d, "TE_GUNSHOT", "1"); print("effect TE_GUNSHOT is ", ftos(particleeffectnum("TE_GUNSHOT")), "\n");\r
560         db_put(d, "TE_GUNSHOTQUAD", "1"); print("effect TE_GUNSHOTQUAD is ", ftos(particleeffectnum("TE_GUNSHOTQUAD")), "\n");\r
561         db_put(d, "TE_SPIKE", "1"); print("effect TE_SPIKE is ", ftos(particleeffectnum("TE_SPIKE")), "\n");\r
562         db_put(d, "TE_SPIKEQUAD", "1"); print("effect TE_SPIKEQUAD is ", ftos(particleeffectnum("TE_SPIKEQUAD")), "\n");\r
563         db_put(d, "TE_SUPERSPIKE", "1"); print("effect TE_SUPERSPIKE is ", ftos(particleeffectnum("TE_SUPERSPIKE")), "\n");\r
564         db_put(d, "TE_SUPERSPIKEQUAD", "1"); print("effect TE_SUPERSPIKEQUAD is ", ftos(particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");\r
565         db_put(d, "TE_WIZSPIKE", "1"); print("effect TE_WIZSPIKE is ", ftos(particleeffectnum("TE_WIZSPIKE")), "\n");\r
566         db_put(d, "TE_KNIGHTSPIKE", "1"); print("effect TE_KNIGHTSPIKE is ", ftos(particleeffectnum("TE_KNIGHTSPIKE")), "\n");\r
567         db_put(d, "TE_EXPLOSION", "1"); print("effect TE_EXPLOSION is ", ftos(particleeffectnum("TE_EXPLOSION")), "\n");\r
568         db_put(d, "TE_EXPLOSIONQUAD", "1"); print("effect TE_EXPLOSIONQUAD is ", ftos(particleeffectnum("TE_EXPLOSIONQUAD")), "\n");\r
569         db_put(d, "TE_TAREXPLOSION", "1"); print("effect TE_TAREXPLOSION is ", ftos(particleeffectnum("TE_TAREXPLOSION")), "\n");\r
570         db_put(d, "TE_TELEPORT", "1"); print("effect TE_TELEPORT is ", ftos(particleeffectnum("TE_TELEPORT")), "\n");\r
571         db_put(d, "TE_LAVASPLASH", "1"); print("effect TE_LAVASPLASH is ", ftos(particleeffectnum("TE_LAVASPLASH")), "\n");\r
572         db_put(d, "TE_SMALLFLASH", "1"); print("effect TE_SMALLFLASH is ", ftos(particleeffectnum("TE_SMALLFLASH")), "\n");\r
573         db_put(d, "TE_FLAMEJET", "1"); print("effect TE_FLAMEJET is ", ftos(particleeffectnum("TE_FLAMEJET")), "\n");\r
574         db_put(d, "EF_FLAME", "1"); print("effect EF_FLAME is ", ftos(particleeffectnum("EF_FLAME")), "\n");\r
575         db_put(d, "TE_BLOOD", "1"); print("effect TE_BLOOD is ", ftos(particleeffectnum("TE_BLOOD")), "\n");\r
576         db_put(d, "TE_SPARK", "1"); print("effect TE_SPARK is ", ftos(particleeffectnum("TE_SPARK")), "\n");\r
577         db_put(d, "TE_PLASMABURN", "1"); print("effect TE_PLASMABURN is ", ftos(particleeffectnum("TE_PLASMABURN")), "\n");\r
578         db_put(d, "TE_TEI_G3", "1"); print("effect TE_TEI_G3 is ", ftos(particleeffectnum("TE_TEI_G3")), "\n");\r
579         db_put(d, "TE_TEI_SMOKE", "1"); print("effect TE_TEI_SMOKE is ", ftos(particleeffectnum("TE_TEI_SMOKE")), "\n");\r
580         db_put(d, "TE_TEI_BIGEXPLOSION", "1"); print("effect TE_TEI_BIGEXPLOSION is ", ftos(particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");\r
581         db_put(d, "TE_TEI_PLASMAHIT", "1"); print("effect TE_TEI_PLASMAHIT is ", ftos(particleeffectnum("TE_TEI_PLASMAHIT")), "\n");\r
582         db_put(d, "EF_STARDUST", "1"); print("effect EF_STARDUST is ", ftos(particleeffectnum("EF_STARDUST")), "\n");\r
583         db_put(d, "TR_ROCKET", "1"); print("effect TR_ROCKET is ", ftos(particleeffectnum("TR_ROCKET")), "\n");\r
584         db_put(d, "TR_GRENADE", "1"); print("effect TR_GRENADE is ", ftos(particleeffectnum("TR_GRENADE")), "\n");\r
585         db_put(d, "TR_BLOOD", "1"); print("effect TR_BLOOD is ", ftos(particleeffectnum("TR_BLOOD")), "\n");\r
586         db_put(d, "TR_WIZSPIKE", "1"); print("effect TR_WIZSPIKE is ", ftos(particleeffectnum("TR_WIZSPIKE")), "\n");\r
587         db_put(d, "TR_SLIGHTBLOOD", "1"); print("effect TR_SLIGHTBLOOD is ", ftos(particleeffectnum("TR_SLIGHTBLOOD")), "\n");\r
588         db_put(d, "TR_KNIGHTSPIKE", "1"); print("effect TR_KNIGHTSPIKE is ", ftos(particleeffectnum("TR_KNIGHTSPIKE")), "\n");\r
589         db_put(d, "TR_VORESPIKE", "1"); print("effect TR_VORESPIKE is ", ftos(particleeffectnum("TR_VORESPIKE")), "\n");\r
590         db_put(d, "TR_NEHAHRASMOKE", "1"); print("effect TR_NEHAHRASMOKE is ", ftos(particleeffectnum("TR_NEHAHRASMOKE")), "\n");\r
591         db_put(d, "TR_VORETOURNAMENTPLASMA", "1"); print("effect TR_VORETOURNAMENTPLASMA is ", ftos(particleeffectnum("TR_VORETOURNAMENTPLASMA")), "\n");\r
592         db_put(d, "TR_GLOWTRAIL", "1"); print("effect TR_GLOWTRAIL is ", ftos(particleeffectnum("TR_GLOWTRAIL")), "\n");\r
593         db_put(d, "SVC_PARTICLE", "1"); print("effect SVC_PARTICLE is ", ftos(particleeffectnum("SVC_PARTICLE")), "\n");\r
594 \r
595         fh = fopen("effectinfo.txt", FILE_READ);\r
596         while((s = fgets(fh)))\r
597         {\r
598                 tokenize(s); // tokenize_console would hit the loop counter :(\r
599                 if(argv(0) == "effect")\r
600                 {\r
601                         if(db_get(d, argv(1)) != "1")\r
602                         {\r
603                                 if(particleeffectnum(argv(1)) >= 0)\r
604                                         print("effect ", argv(1), " is ", ftos(particleeffectnum(argv(1))), "\n");\r
605                                 db_put(d, argv(1), "1");\r
606                         }\r
607                 }\r
608         }\r
609         print("end of effects list\n");\r
610 \r
611         db_close(d);\r
612 }\r
613 \r
614 void make_mapinfo_Think()\r
615 {\r
616         if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))\r
617         {\r
618                 print("Done rebuiling mapinfos.\n");\r
619                 MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);\r
620                 remove(self);\r
621         }\r
622         else\r
623         {\r
624                 self.think = make_mapinfo_Think;\r
625                 self.nextthink = time;\r
626         }\r
627 }\r
628 \r
629 void GameCommand(string command)\r
630 {\r
631         float argc;\r
632         entity client, e;\r
633         vector v;\r
634         float entno, i, n;\r
635         string s;\r
636         argc = tokenize_console(command);\r
637 \r
638         if(argv(0) == "help" || argc == 0)\r
639         {\r
640                 print("Usage: sv_cmd COMMAND..., where possible commands are:\n");\r
641                 print("  adminmsg clientnumber \"message\"\n");\r
642                 print("  teamstatus\n");\r
643                 print("  printstats\n");\r
644                 print("  make_mapinfo\n");\r
645                 print("  gametype dm|ctf|...\n");\r
646                 print("  savedb filename\n");\r
647                 print("  dumpdb filename\n");\r
648                 print("  loaddb filename\n");\r
649                 print("  allready\n");\r
650                 print("  effectindexdump\n");\r
651                 print("  radarmap [--force] [--quit | --loop] [sharpness]\n");\r
652                 print("  bbox\n");\r
653                 print("  cvar_changes\n");\r
654                 print("  find classname\n");\r
655                 GameCommand_Vote("help", world);\r
656                 GameCommand_Ban("help");\r
657                 GameCommand_Generic("help");\r
658                 return;\r
659         }\r
660 \r
661         if(GameCommand_Vote(command, world))\r
662                 return;\r
663 \r
664         if(GameCommand_Ban(command))\r
665                 return;\r
666 \r
667         if(GameCommand_Generic(command))\r
668                 return;\r
669 \r
670         if(argv(0) == "printstats")\r
671         {\r
672                 DumpStats(FALSE);\r
673                 return;\r
674         }\r
675 \r
676         if(argv(0) == "make_mapinfo")\r
677         {\r
678                 e = spawn();\r
679                 e.classname = "make_mapinfo";\r
680                 e.think = make_mapinfo_Think;\r
681                 e.nextthink = time;\r
682                 MapInfo_Enumerate();\r
683                 return;\r
684         }\r
685 \r
686         if(argv(0) == "gotomap") if(argc == 2)\r
687         {\r
688                 print(GotoMap(argv(1)), "\n");\r
689                 return;\r
690         }\r
691 \r
692         if(argv(0) == "gametype") if(argc == 2)\r
693         {\r
694                 float t, tsave;\r
695                 s = argv(1);\r
696                 t = MapInfo_Type_FromString(s);\r
697                 tsave = MapInfo_CurrentGametype();\r
698                 if(t)\r
699                 {\r
700                         MapInfo_SwitchGameType(t);\r
701                         MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);\r
702                         if(MapInfo_count > 0)\r
703                         {\r
704                                 bprint("Game type successfully switched to ", s, "\n");\r
705                         }\r
706                         else\r
707                         {\r
708                                 bprint("Cannot use this game type: no map for it found\n");\r
709                                 MapInfo_SwitchGameType(tsave);\r
710                                 MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);\r
711                         }\r
712                 }\r
713                 else\r
714                         bprint("Game type switch to ", s, " failed: this type does not exist!\n");\r
715                 return;\r
716         }\r
717 \r
718         if(argv(0) == "adminmsg")\r
719         if(argc == 3)\r
720         {\r
721                 entno = stof(argv(1));\r
722 \r
723                 if((entno < 1) | (entno > maxclients)) {\r
724                         print("Player ", argv(1), " doesn't exist\n");\r
725                         return;\r
726                 }\r
727 \r
728                 client = edict_num(entno);\r
729 \r
730                 if(client.flags & FL_CLIENT)\r
731                 {\r
732                         centerprint_atprio(client, CENTERPRIO_ADMIN, strcat("^3", admin_name(), ":\n\n^7", argv(2)));\r
733                         sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", argv(2), "\n"));\r
734                         print("Message sent to ", client.netname, "\n");\r
735                 }\r
736                 else\r
737                         print("Client not found\n");\r
738 \r
739                 return;\r
740         }\r
741 \r
742         if(argv(0) == "savedb") if(argc == 2)\r
743         {\r
744                 db_save(ServerProgsDB, argv(1));\r
745                 print("DB saved.\n");\r
746                 return;\r
747         }\r
748 \r
749         if(argv(0) == "dumpdb") if(argc == 2)\r
750         {\r
751                 db_dump(ServerProgsDB, argv(1));\r
752                 print("DB dumped.\n");\r
753                 return;\r
754         }\r
755 \r
756         if(argv(0) == "loaddb") if(argc == 2)\r
757         {\r
758                 db_close(ServerProgsDB);\r
759                 ServerProgsDB = db_load(argv(1));\r
760                 print("DB loaded.\n");\r
761                 return;\r
762         }\r
763 \r
764         if (argv(0) == "nospectators")\r
765         {\r
766                 blockSpectators = 1;\r
767                 local entity plr;\r
768                 FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player\r
769                 {\r
770                         if(plr.classname == "spectator" || plr.classname == "observer")\r
771                         {\r
772                                 plr.spectatortime = time;\r
773                                 sprint(plr, strcat("^7You have to become a player within the next ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));\r
774                         }\r
775                 }\r
776                 bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds!\n"));\r
777                 return;\r
778         }\r
779 \r
780         if (argv(0) == "lockteams")\r
781         {\r
782                 if(teams_matter)\r
783                 {\r
784                         lockteams = 1;\r
785                         bprint("^1The teams are now locked.\n");\r
786                 }\r
787                 else\r
788                         bprint("That command can only be used in a team-based gamemode.\n");\r
789                 return;\r
790         }\r
791 \r
792         if (argv(0) == "unlockteams")\r
793         {\r
794                 if(teams_matter)\r
795                 {\r
796                         lockteams = 0;\r
797                         bprint("^1The teams are now unlocked.\n");\r
798                 }\r
799                 else\r
800                         bprint("That command can only be used in a team-based gamemode.\n");\r
801                 return;\r
802         }\r
803         if(argv(0) == "movetoteam")\r
804         if(argc == 3 || argc == 4) {\r
805 //      sv_cmd movetoteam  player_id  team_colour\r
806 //      sv_cmd movetoteam  player_id  team_colour  type_of_move\r
807 \r
808 //      type of move\r
809 //      0 (00) automove centerprint, admin message\r
810 //      1 (01) automove centerprint, no admin message\r
811 //      2 (10) no centerprint, admin message\r
812 //      3 (11) no centerprint, no admin message\r
813 \r
814                 if(!teams_matter) {  // death match\r
815                         print("Currently not playing a team game\n");\r
816                         return;\r
817                 }\r
818 \r
819                 entno = stof(argv(1));\r
820 \r
821                 // player_id is out of range\r
822                 if((entno < 1) | (entno > maxclients)) {\r
823                         print("Player ", argv(1), " doesn't exist\n");\r
824                         return;\r
825                 }\r
826 \r
827                         client = edict_num(entno);\r
828 \r
829                 // player entity is not a client\r
830                 if not(client.flags & FL_CLIENT) {\r
831                         print("Player ", argv(1), " doesn't exist\n");\r
832                         return;\r
833                 }\r
834 \r
835                 // find the team to move the player to\r
836                 float team_colour;\r
837 \r
838                 team_colour = ColourToNumber(argv(2));\r
839 \r
840                 if(team_colour == client.team) {  // player already on the team\r
841                         print("Player ", argv(1), " (", client.netname, ") is already on the ", ColoredTeamName(client.team), "\n");\r
842                         return;\r
843                 } else if(team_colour == 0)  // auto team\r
844                         team_colour = NumberToTeamNumber(FindSmallestTeam(client, FALSE));\r
845 \r
846                 switch(team_colour) {\r
847                         case COLOR_TEAM1:\r
848                                 if(c1 == -1) {\r
849                                         print("Sorry, there isn't a red team\n");\r
850                                         return;\r
851                 }\r
852                         break;\r
853 \r
854                         case COLOR_TEAM2:\r
855                                 if(c2 == -1) {\r
856                                         print("Sorry, there isn't a blue team\n");\r
857                 return;\r
858         }\r
859                         break;\r
860 \r
861                         case COLOR_TEAM3:\r
862                                 if(c3 == -1) {\r
863                                         print("Sorry, there isn't a yellow team\n");\r
864                                         return;\r
865                                 }\r
866                         break;\r
867 \r
868                         case COLOR_TEAM4:\r
869                                 if(c4 == -1) {\r
870                                         print("Sorry, there isn't a pink team\n");\r
871                                         return;\r
872                                 }\r
873                         break;\r
874 \r
875                         default:\r
876                                 print("Sorry, team ", argv(2), " doesn't exist\n");\r
877                                 return;\r
878                 }\r
879                 print("Player ", argv(1), " (", client.netname, ") has been moved to the ", ColoredTeamName(team_colour), "\n");\r
880 \r
881                 MoveToTeam(client, team_colour, 6, stof(argv(3)));\r
882 \r
883                 return;\r
884         }\r
885         if (argv(0) == "teamstatus")\r
886         {\r
887                 Score_NicePrint(world);\r
888                 return;\r
889         }\r
890         if (argv(0) == "allready")\r
891         {\r
892                 ReadyRestart();\r
893                 return;\r
894         }\r
895         if (argv(0) == "effectindexdump")\r
896         {\r
897                 EffectIndexDump();\r
898                 return;\r
899         }\r
900         if (argv(0) == "radarmap")\r
901         {\r
902                 RadarMap(argc);\r
903                 return;\r
904         }\r
905         if (argv(0) == "bbox")\r
906         {\r
907                 BBox();\r
908                 return;\r
909         }\r
910         if (argv(0) == "cvar_changes")\r
911         {\r
912                 print(cvar_changes);\r
913                 return;\r
914         }\r
915         if (argv(0) == "find") if(argc == 2)\r
916         {\r
917                 for(client = world; (client = find(client, classname, argv(1))); )\r
918                         print(etos(client), "\n");\r
919                 return;\r
920         }\r
921         if (argv(0) == "records")\r
922         {\r
923                 for (i = 0; i < 10; ++i)\r
924                         print(records_reply[i]);\r
925                 return;\r
926         }\r
927         if (argv(0) == "rankings")\r
928         {\r
929                 strunzone(rankings_reply);\r
930                 rankings_reply = strzone(getrankings());\r
931                 print(rankings_reply);\r
932                 return;\r
933         }\r
934 \r
935         if(argv(0) == "cointoss")\r
936         {\r
937                 bprint("^3Throwing coin... Result: ");\r
938                 if (random() > 0.5)\r
939                         bprint("^1heads ^3!\n");\r
940                 else\r
941                         bprint("^1tails ^3!\n");\r
942                 return;\r
943         }\r
944 \r
945         if(argv(0) == "__FORCE_READY_RESTART")\r
946         {\r
947                 reset_map(FALSE);\r
948                 return;\r
949         }\r
950 \r
951         if(argv(0) == "debug_shotorg")\r
952         {\r
953                 debug_shotorg = stov(argv(1));\r
954                 return;\r
955         }\r
956 \r
957         if(argv(0) == "gettaginfo") if(argc >= 4)\r
958         {\r
959                 e = spawn();\r
960                 if(argv(1) == "w")\r
961                         setmodel(e, (nextent(world)).weaponentity.model);\r
962                 else\r
963                         setmodel(e, argv(1));\r
964                 e.frame = stof(argv(2));\r
965                 i = gettagindex(e, argv(3));\r
966                 if(i)\r
967                 {\r
968                         v = gettaginfo(e, i);\r
969                         print("model ", e.model, " frame ", ftos(e.frame), " tag ", argv(3));\r
970                         print(" index = ", ftos(i));\r
971                         print(" vector = ", ftos(v_x), " ", ftos(v_y), " ", ftos(v_z), "\n");\r
972                         if(argc >= 6)\r
973                         {\r
974                                 v_y = -v_y;\r
975                                 localcmd(strcat(argv(4), vtos(v), argv(5), "\n"));\r
976                         }\r
977                 }\r
978                 else\r
979                         print("bone not found\n");\r
980                 remove(e);\r
981                 return;\r
982         }\r
983 \r
984         if(argv(0) == "time")\r
985         {\r
986                 print("time = ", ftos(time), "\n");\r
987                 print("frame start = ", ftos(gettime(GETTIME_FRAMESTART)), "\n");\r
988                 print("realtime = ", ftos(gettime(GETTIME_REALTIME)), "\n");\r
989                 print("hires = ", ftos(gettime(GETTIME_HIRES)), "\n");\r
990                 print("uptime = ", ftos(gettime(GETTIME_UPTIME)), "\n");\r
991                 print("localtime = ", strftime(TRUE, "%a %b %e %H:%M:%S %Z %Y"), "\n");\r
992                 print("gmtime = ", strftime(FALSE, "%a %b %e %H:%M:%S %Z %Y"), "\n");\r
993                 return;\r
994         }\r
995 \r
996         if(argv(0) == "tracebug")\r
997         {\r
998                 print("TEST CASE. If this returns the runaway loop counter error, possibly everything is oaky.\n");\r
999                 for(;;)\r
1000                 {\r
1001                         vector org, delta, start, end, p, q, q0, pos;\r
1002                         float safe, unsafe, dq, dqf;\r
1003 \r
1004                         org = world.mins;\r
1005                         delta = world.maxs - world.mins;\r
1006 \r
1007                         start_x = org_x + random() * delta_x;\r
1008                         start_y = org_y + random() * delta_y;\r
1009                         start_z = org_z + random() * delta_z;\r
1010 \r
1011                         end_x = org_x + random() * delta_x;\r
1012                         end_y = org_y + random() * delta_y;\r
1013                         end_z = org_z + random() * delta_z;\r
1014 \r
1015                         start = stov(vtos(start));\r
1016                         end = stov(vtos(end));\r
1017 \r
1018                         tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);\r
1019                         if(!trace_startsolid)\r
1020                         {\r
1021                                 p = trace_endpos;\r
1022                                 tracebox(p, PL_MIN, PL_MAX, p, MOVE_NOMONSTERS, world);\r
1023                                 if(trace_startsolid || trace_fraction == 1)\r
1024                                 {\r
1025                                         rint(42); // do an engine breakpoint on VM_rint so you can get the trace that errnoeously returns startsolid\r
1026                                         tracebox(start, PL_MIN, PL_MAX, end, MOVE_NOMONSTERS, world);\r
1027                                         tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);\r
1028 \r
1029                                         if(trace_startsolid)\r
1030                                         {\r
1031                                                 // how much do we need to back off?\r
1032                                                 safe = 1;\r
1033                                                 unsafe = 0;\r
1034                                                 for(;;)\r
1035                                                 {\r
1036                                                         pos = p * (1 - (safe + unsafe) * 0.5) + start * ((safe + unsafe) * 0.5);\r
1037                                                         tracebox(pos, PL_MIN, PL_MAX, pos, MOVE_NOMONSTERS, world);\r
1038                                                         if(trace_startsolid)\r
1039                                                         {\r
1040                                                                 if((safe + unsafe) * 0.5 == unsafe)\r
1041                                                                         break;\r
1042                                                                 unsafe = (safe + unsafe) * 0.5;\r
1043                                                         }\r
1044                                                         else\r
1045                                                         {\r
1046                                                                 if((safe + unsafe) * 0.5 == safe)\r
1047                                                                         break;\r
1048                                                                 safe = (safe + unsafe) * 0.5;\r
1049                                                         }\r
1050                                                 }\r
1051 \r
1052                                                 print("safe distance to back off: ", ftos(safe * vlen(p - start)), "qu\n");\r
1053                                                 print("unsafe distance to back off: ", ftos(unsafe * vlen(p - start)), "qu\n");\r
1054 \r
1055                                                 tracebox(p, PL_MIN + '0.1 0.1 0.1', PL_MAX - '0.1 0.1 0.1', p, MOVE_NOMONSTERS, world);\r
1056                                                 if(trace_startsolid)\r
1057                                                         print("trace_endpos much in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");\r
1058                                                 else\r
1059                                                         print("trace_endpos just in solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");\r
1060                                                 break;\r
1061                                         }\r
1062 \r
1063                                         q0 = p;\r
1064                                         dq = 0;\r
1065                                         dqf = 1;\r
1066                                         for(;;)\r
1067                                         {\r
1068                                                 q = p + normalize(end - p) * (dq + dqf);\r
1069                                                 if(q == q0)\r
1070                                                         break;\r
1071                                                 tracebox(p, PL_MIN, PL_MAX, q, MOVE_NOMONSTERS, world);\r
1072                                                 if(trace_startsolid)\r
1073                                                         error("THIS ONE cannot happen");\r
1074                                                 if(trace_fraction > 0)\r
1075                                                         dq += dqf * trace_fraction;\r
1076                                                 dqf *= 0.5;\r
1077                                                 q0 = q;\r
1078                                         }\r
1079                                         if(dq > 0)\r
1080                                         {\r
1081                                                 print("trace_endpos still before solid when tracing from ", vtos(start), " to ", vtos(end), " endpos ", vtos(p), "\n");\r
1082                                                 print("could go ", ftos(dq), " units further to ", vtos(q), "\n");\r
1083                                                 break;\r
1084                                         }\r
1085                                 }\r
1086                         }\r
1087                 }\r
1088         }\r
1089 \r
1090         if(argv(0) == "tracebug2")\r
1091         {\r
1092                 e = nextent(world);\r
1093                 float f;\r
1094                 vector vv, dv;\r
1095                 tracebox(e.origin + '0 0 32', e.mins, e.maxs, e.origin + '0 0 -1024', MOVE_NORMAL, e);\r
1096                 vv = trace_endpos;\r
1097                 if(trace_fraction == 1)\r
1098                 {\r
1099                         print("not above ground, aborting\n");\r
1100                         return;\r
1101                 }\r
1102                 f = 0;\r
1103                 for(i = 0; i < 100000; ++i)\r
1104                 {\r
1105                         dv = randomvec();\r
1106                         if(dv_z > 0)\r
1107                                 dv = -1 * dv;\r
1108                         tracebox(vv, e.mins, e.maxs, vv + dv, MOVE_NORMAL, e);\r
1109                         if(trace_startsolid)\r
1110                                 print("bug 1\n");\r
1111                         if(trace_fraction == 1)\r
1112                         if(dv_z < f)\r
1113                         {\r
1114                                 print("bug 2: ", ftos(dv_x), " ", ftos(dv_y), " ", ftos(dv_z));\r
1115                                 print(" (", ftos(asin(dv_z / vlen(dv)) * 180 / M_PI), " degrees)\n");\r
1116                                 f = dv_z;\r
1117                         }\r
1118                 }\r
1119                 print("highest possible dist: ", ftos(f), "\n");\r
1120                 return;\r
1121         }\r
1122 \r
1123         if(argv(0) == "tracewalk")\r
1124         {\r
1125                 e = nextent(world);\r
1126                 if(tracewalk(e, stov(argv(1)), e.mins, e.maxs, stov(argv(2)), MOVE_NORMAL))\r
1127                         print("can walk\n");\r
1128                 else\r
1129                         print("cannot walk\n");\r
1130                 return;\r
1131         }\r
1132 \r
1133         if(argv(0) == "onslaught_updatelinks")\r
1134         {\r
1135                 onslaught_updatelinks();\r
1136                 print("ONS links updated\n");\r
1137                 return;\r
1138         }\r
1139 \r
1140         if(argv(0) == "bot_cmd")\r
1141         {\r
1142                 local entity bot;\r
1143 \r
1144                 if(argv(1) == "help")\r
1145                 {\r
1146                         if(argc==2)\r
1147                         {\r
1148                                 bot_list_commands();\r
1149                                 print("\nsv_cmd bot_cmd reset          #Clear the cmd queues of all bots\n");\r
1150                                 print("sv_cmd bot_cmd load <file>    #Load script file\n");\r
1151                                 print("\nUse sv_cmd bot_cmd help <command> for more\n\n");\r
1152                                 return;\r
1153                         }\r
1154 \r
1155                         bot_cmdhelp(argv(2));\r
1156                         return;\r
1157                 }\r
1158 \r
1159                 // Clear all bot queues\r
1160                 if(argv(1) == "reset")\r
1161                 {\r
1162                         bot_resetqueues();\r
1163                         return;\r
1164                 }\r
1165 \r
1166                 // Load cmds from file\r
1167                 if(argv(1) == "load" && argc == 3)\r
1168                 {\r
1169                         float fh;\r
1170                         fh = fopen(argv(2), FILE_READ);\r
1171                         if(fh < 0)\r
1172                         {\r
1173                                 print("cannot open the file\n");\r
1174                                 return;\r
1175                         }\r
1176 \r
1177                         i = 0;\r
1178                         while((s = fgets(fh)))\r
1179                         {\r
1180                                 argc = tokenize_console(s);\r
1181 \r
1182                                 if(argc >= 3 && argv(0) == "sv_cmd" && argv(1) == "bot_cmd")\r
1183                                 {\r
1184                                         // let's start at token 2 so we can skip sv_cmd bot_cmd\r
1185                                         bot = find_bot_by_number(stof(argv(2)));\r
1186                                         if(bot == world)\r
1187                                                 bot = find_bot_by_name(argv(2));\r
1188                                         if(bot)\r
1189                                                 bot_queuecommand(bot, strcat(argv(3), " ", argv(4)));\r
1190                                 }\r
1191                                 else\r
1192                                         localcmd(strcat(s, "\n"));\r
1193 \r
1194                                 ++i;\r
1195                         }\r
1196 \r
1197                         print(ftos(i), " commands read\n");\r
1198 \r
1199                         fclose(fh);\r
1200 \r
1201                         return;\r
1202                 }\r
1203 \r
1204                 if(argc < 3)\r
1205                 {\r
1206                         print("Usage: sv_cmd bot_cmd <bot name or number> <command> [argument]\n");\r
1207                         print("Examples: bot_cmd <id> cc \"say something\"\n");\r
1208                         print("          bot_cmd <id> presskey jump\n");\r
1209                         print("          .. or sv_cmd bot_cmd help <command> for more\n");\r
1210                         return;\r
1211                 }\r
1212 \r
1213                 bot = find_bot_by_number(stof(argv(1)));\r
1214                 if(bot == world)\r
1215                         bot = find_bot_by_name(argv(1));\r
1216 \r
1217                 if(bot)\r
1218                         bot_queuecommand(bot, strcat(argv(2), " ", argv(3)));\r
1219                 else\r
1220                         print(strcat("Error: Unable to find a bot with the name or number '",argv(1),"'\n"));\r
1221 \r
1222                 return;\r
1223         }\r
1224 \r
1225         if(argv(0) == "playerdemo")\r
1226         {\r
1227                 if(argv(1) == "read")\r
1228                 {\r
1229                         entno = stof(argv(2));\r
1230                         if((entno < 1) | (entno > maxclients)) {\r
1231                                 print("Player ", argv(2), " doesn't exist\n");\r
1232                                 return;\r
1233                         }\r
1234                         client = edict_num(entno);\r
1235                         if(clienttype(client) != CLIENTTYPE_BOT) {\r
1236                                 print("Player ", client.netname, " is not a bot\n");\r
1237                                 return;\r
1238                         }\r
1239                         self = client;\r
1240                         playerdemo_open_read(argv(3));\r
1241                         return;\r
1242                 }\r
1243                 else if(argv(1) == "write")\r
1244                 {\r
1245                         entno = stof(argv(2));\r
1246                         if((entno < 1) | (entno > maxclients)) {\r
1247                                 print("Player ", argv(2), " doesn't exist\n");\r
1248                                 return;\r
1249                         }\r
1250                         client = edict_num(entno);\r
1251                         self = client;\r
1252                         playerdemo_open_write(argv(3));\r
1253                         return;\r
1254                 }\r
1255                 else if(argv(1) == "auto_read_and_write")\r
1256                 {\r
1257                         s = argv(2);\r
1258                         n = stof(argv(3));\r
1259                         cvar_set("bot_number", ftos(n));\r
1260                         localcmd("wait; wait; wait\n");\r
1261                         for(i = 0; i < n; ++i)\r
1262                                 localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", s, ftos(i+1), "\n");\r
1263                         localcmd("sv_cmd playerdemo write 1 ", ftos(n+1), "\n");\r
1264                         return;\r
1265                 }\r
1266                 else if(argv(1) == "auto_read")\r
1267                 {\r
1268                         s = argv(2);\r
1269                         n = stof(argv(3));\r
1270                         cvar_set("bot_number", ftos(n));\r
1271                         localcmd("wait; wait; wait\n");\r
1272                         for(i = 0; i < n; ++i)\r
1273                                 localcmd("sv_cmd playerdemo read ", ftos(i+2), " ", s, ftos(i+1), "\n");\r
1274                         return;\r
1275                 }\r
1276         }\r
1277 \r
1278         if(argv(0) == "anticheat")\r
1279         {\r
1280                 entno = stof(argv(1));\r
1281                 if((entno < 1) | (entno > maxclients)) {\r
1282                         print("Player ", argv(1), " doesn't exist\n");\r
1283                         return;\r
1284                 }\r
1285                 client = edict_num(entno);\r
1286                 if(clienttype(client) != CLIENTTYPE_REAL && clienttype(client) != CLIENTTYPE_BOT) {\r
1287                         print("Player ", client.netname, " is not active\n");\r
1288                         return;\r
1289                 }\r
1290                 self = client;\r
1291                 anticheat_report();\r
1292                 return;\r
1293         }\r
1294 \r
1295         if(argv(0) == "defer_clear")\r
1296         if(argc == 2)\r
1297         {\r
1298                 entno = stof(argv(1));\r
1299 \r
1300                 // player_id is out of range\r
1301                 if((entno < 1) | (entno > maxclients)) {\r
1302                         print("Player ", argv(1), " doesn't exist\n");\r
1303                         return;\r
1304                 }\r
1305 \r
1306                 client = edict_num(entno);\r
1307 \r
1308                 if not(client.flags & FL_CLIENT) {\r
1309                         print("Player ", argv(1), " doesn't exist\n");\r
1310                         return;\r
1311                 }\r
1312 \r
1313                 if(clienttype(client) == CLIENTTYPE_BOT) {\r
1314                         print("Player ", argv(1), " (", client.netname, ") is a bot\n");\r
1315                         return;\r
1316                 }\r
1317 \r
1318                 stuffcmd(client, "defer clear\n");\r
1319                 print("defer clear stuffed to ", argv(1), " (", client.netname, ")\n");\r
1320                 return;\r
1321         }\r
1322 \r
1323         if(argv(0) == "defer_clear_all")\r
1324         {\r
1325                 FOR_EACH_CLIENTSLOT(client)\r
1326                         GameCommand(strcat("defer_clear ", ftos(num_for_edict(client))));       \r
1327 \r
1328                 return;\r
1329         }\r
1330         if(argv(0) == "delrec")\r
1331         {\r
1332                 race_DeleteTime(stof(argv(1)));\r
1333                 return;\r
1334         }\r
1335 \r
1336         print("Invalid command. For a list of supported commands, try sv_cmd help.\n");\r
1337 }\r
1338 \r