]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/gamecommand.qc
damn typo :P
[divverent/nexuiz.git] / data / qcsrc / server / gamecommand.qc
1 string GotoMap(string m);
2
3 float FullTraceFraction(vector a, vector mi, vector ma, vector b)
4 {
5         vector c;
6         float white, black;
7         if(a_z > b_z)
8                 return 0;
9
10         white = 0;
11         black = 0;
12
13         c = a;
14
15         while(vlen(c - b) > 1)
16         {
17                 tracebox(c, mi, ma, b, MOVE_WORLDONLY, world);
18                 if(!trace_startsolid)
19                 {
20                         black += trace_endpos_z - c_z;
21                         c = trace_endpos;
22                 }
23                 tracebox_inverted(c, mi, ma, b, MOVE_WORLDONLY, world);
24                 white += trace_endpos_z - c_z;
25                 c = trace_endpos;
26         }
27
28         return white / (black + white);
29 }
30
31 float RadarMapAtPoint_Trace(float x, float y, float w, float h, float zmin, float zsize, float q)
32 {
33         vector a, b, mi, ma;
34
35         mi = '0 0 0';
36         ma = '1 0 0' * w + '0 1 0' * h;
37         a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
38         b = '1 0 0' * x + '0 1 0' * y + '0 0 1' * (zsize - zmin);
39
40         return FullTraceFraction(a, mi, ma, b);
41 }
42 float RadarMapAtPoint_Block(float x, float y, float w, float h, float zmin, float zsize, float q)
43 {
44         vector o, mi, ma;
45         float i, r;
46         vector dz;
47
48         q = 256 * q - 1;
49         // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
50
51         mi = '0 0 0';
52         dz = (zsize / q) * '0 0 1';
53         ma = '1 0 0' * w + '0 1 0' * h + dz;
54         o = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
55
56         if(x < world.absmin_x - w)
57                 return 0;
58         if(y < world.absmin_y - h)
59                 return 0;
60         if(x > world.absmax_x)
61                 return 0;
62         if(y > world.absmax_y)
63                 return 0;
64         
65         r = 0;
66         for(i = 0; i < q; ++i)
67         {
68                 tracebox(o + dz * i, mi, ma, o + dz * i, MOVE_WORLDONLY, world);
69                 if(trace_startsolid)
70                         ++r;
71         }
72         return r / q;
73 }
74 float RadarMapAtPoint_Sample(float x, float y, float w, float h, float zmin, float zsize, float q)
75 {
76         vector a, b, mi, ma;
77
78         q *= 4; // choose q so it matches the regular algorithm in speed
79
80         q = 256 * q - 1;
81         // 256q-1 is the ideal sample count to map equal amount of sample values to one pixel value
82
83         mi = '0 0 0';
84         ma = '1 0 0' * w + '0 1 0' * h;
85         a = '1 0 0' * x + '0 1 0' * y + '0 0 1' * zmin;
86         b = '1 0 0' * w + '0 1 0' * h + '0 0 1' * zsize;
87         
88         float c, i;
89         c = 0;
90
91         for(i = 0; i < q; ++i)
92         {
93                 vector v;
94                 v_x = a_x + random() * b_x;
95                 v_y = a_y + random() * b_y;
96                 v_z = a_z + random() * b_z;
97                 traceline(v, v, MOVE_WORLDONLY, world);
98                 if(trace_startsolid)
99                         ++c;
100         }
101
102         return c / q;
103 }
104
105 // FF is contained twice, to map 256 to FF too
106 // removes the need to bound()
107 string doublehex = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFFFF";
108
109 float RADAR_WIDTH_MAX = 2048;
110 float RADAR_HEIGHT_MAX = 2048;
111 float sharpen_buffer[RADAR_WIDTH_MAX * 3];
112
113 void sharpen_set(float x, float v)
114 {
115         sharpen_buffer[x + 2 * RADAR_WIDTH_MAX] = v;
116 }
117
118 float sharpen_getpixel(float x, float y)
119 {
120         if(x < 0)
121                 return 0;
122         if(x >= RADAR_WIDTH_MAX)
123                 return 0;
124         if(y < 0)
125                 return 0;
126         if(y > 2)
127                 return 0;
128         return sharpen_buffer[x + y * RADAR_WIDTH_MAX];
129 }
130
131 float sharpen_get(float x, float a)
132 {
133         float sum;
134         sum = sharpen_getpixel(x, 1);
135         if(a == 0)
136                 return sum;
137         sum *= (8 + 1/a);
138         sum -= sharpen_getpixel(x - 1, 0);
139         sum -= sharpen_getpixel(x - 1, 1);
140         sum -= sharpen_getpixel(x - 1, 2);
141         sum -= sharpen_getpixel(x + 1, 0);
142         sum -= sharpen_getpixel(x + 1, 1);
143         sum -= sharpen_getpixel(x + 1, 2);
144         sum -= sharpen_getpixel(x, 0);
145         sum -= sharpen_getpixel(x, 2);
146         return bound(0, sum * a, 1);
147 }
148
149 void sharpen_shift(float w)
150 {
151         float i;
152         for(i = 0; i < w; ++i)
153         {
154                 sharpen_buffer[i] = sharpen_buffer[i + RADAR_WIDTH_MAX];
155                 sharpen_buffer[i + RADAR_WIDTH_MAX] = sharpen_buffer[i + 2 * RADAR_WIDTH_MAX];
156                 sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;
157         }
158 }
159
160 void sharpen_init(float w)
161 {
162         float i;
163         for(i = 0; i < w; ++i)
164         {
165                 sharpen_buffer[i] = 0;
166                 sharpen_buffer[i + RADAR_WIDTH_MAX] = 0;
167                 sharpen_buffer[i + 2 * RADAR_WIDTH_MAX] = 0;
168         }
169 }
170
171 entity radarmapper;
172 void RadarMap_Next()
173 {
174         if(radarmapper.count & 4)
175         {
176                 localcmd("quit\n");
177         }
178         else if(radarmapper.count & 2)
179         {
180                 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"));
181                 GotoNextMap();
182         }
183         remove(radarmapper);
184         radarmapper = world;
185 }
186
187 // rough map entity
188 //   cnt: current line
189 //   size: pixel width/height
190 //   maxs: cell width/height
191 //   frame: counter
192 void RadarMap_Think()
193 {
194         float i, x, l;
195         string si;
196
197         if(self.frame == 0)
198         {
199                 // initialize
200                 get_mi_min_max_texcoords(1);
201                 self.mins = mi_picmin;
202                 self.maxs_x = (mi_picmax_x - mi_picmin_x) / self.size_x;
203                 self.maxs_y = (mi_picmax_y - mi_picmin_y) / self.size_y;
204                 self.maxs_z = mi_max_z - mi_min_z;
205                 print("Picture mins/maxs: ", ftos(self.maxs_x), " and ", ftos(self.maxs_y), " should match\n");
206                 self.netname = strzone(strcat("gfx/", mi_shortname, "_radar.xpm"));
207                 if(!(self.count & 1))
208                 {
209                         self.cnt = fopen(self.netname, FILE_READ);
210                         if(self.cnt >= 0)
211                         {
212                                 print(self.netname, " already exists, aborting (you may want to specify --force)\n");
213                                 RadarMap_Next();
214                                 return;
215                         }
216                 }
217                 self.cnt = fopen(self.netname, FILE_WRITE);
218                 if(self.cnt < 0)
219                 {
220                         print("Error writing ", self.netname, "\n");
221                         remove(self);
222                         radarmapper = world;
223                         return;
224                 }
225                 print("Writing to ", self.netname, "...\n");
226                 fputs(self.cnt, "/* XPM */\n");
227                 fputs(self.cnt, "static char *RadarMap[] = {\n");
228                 fputs(self.cnt, "/* columns rows colors chars-per-pixel */\n");
229                 fputs(self.cnt, strcat("\"", ftos(self.size_x), " ", ftos(self.size_y), " 256 2\",\n"));
230                 for(i = 0; i < 256; ++i)
231                 {
232                         si = substring(doublehex, i*2, 2);
233                         fputs(self.cnt, strcat("\"", si, " c #", si, si, si, "\",\n"));
234                 }
235                 self.frame += 1;
236                 self.nextthink = time;
237                 sharpen_init(self.size_x);
238         }
239         else if(self.frame <= self.size_y)
240         {
241                 // fill the sharpen buffer with this line
242                 sharpen_shift(self.size_x);
243                 i = self.count & 24;
244
245                 switch(i)
246                 {
247                         case 0:
248                         default:
249                                 for(x = 0; x < self.size_x; ++x)
250                                 {
251                                         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);
252                                         sharpen_set(x, l);
253                                 }
254                                 break;
255                         case 8:
256                                 for(x = 0; x < self.size_x; ++x)
257                                 {
258                                         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);
259                                         sharpen_set(x, l);
260                                 }
261                                 break;
262                         case 16:
263                                 for(x = 0; x < self.size_x; ++x)
264                                 {
265                                         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);
266                                         sharpen_set(x, l);
267                                 }
268                                 break;
269                 }
270
271                 // do we have enough lines?
272                 if(self.frame >= 2)
273                 {
274                         // write a pixel line
275                         fputs(self.cnt, "\"");
276                         for(x = 0; x < self.size_x; ++x)
277                         {
278                                 l = sharpen_get(x, self.ltime);
279                                 fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
280                         }
281                         if(self.frame == self.size_y)
282                                 fputs(self.cnt, "\"\n");
283                         else
284                         {
285                                 fputs(self.cnt, "\",\n");
286                                 print(ftos(self.size_y - self.frame), " lines left\n");
287                         }
288                 }
289
290                 // is this the last line? then write back the missing line
291                 if(self.frame == self.size_y)
292                 {
293                         sharpen_shift(self.size_x);
294                         // write a pixel line
295                         fputs(self.cnt, "\"");
296                         for(x = 0; x < self.size_x; ++x)
297                         {
298                                 l = sharpen_get(x, self.ltime);
299                                 fputs(self.cnt, substring(doublehex, 2 * floor(l * 256.0), 2));
300                         }
301                         if(self.frame == self.size_y)
302                                 fputs(self.cnt, "\"\n");
303                         else
304                         {
305                                 fputs(self.cnt, "\",\n");
306                                 print(ftos(self.size_y - self.frame), " lines left\n");
307                         }
308                 }
309
310                 self.frame += 1;
311                 self.nextthink = time;
312         }
313         else
314         {
315                 // close the file
316                 fputs(self.cnt, "};\n");
317                 fclose(self.cnt);
318                 print("Finished. Please edit data/", self.netname, " with an image editing application and place it in the TGA format in the gfx folder.\n");
319                 RadarMap_Next();
320         }
321 }
322
323 void RadarMap(float argc)
324 {
325         if(radarmapper)
326                 return;
327         float i;
328         radarmapper = spawn();
329         radarmapper.classname = "radarmapper";
330         radarmapper.think = RadarMap_Think;
331         radarmapper.nextthink = time;
332         radarmapper.count = 0;
333         radarmapper.ltime = 1;
334         radarmapper.size_x = 512;
335         radarmapper.size_y = 512;
336         radarmapper.size_z = 1;
337
338         for(i = 1; i < argc; ++i)
339         {
340                 if(argv(i) == "--force")
341                         radarmapper.count |= 1;
342                 else if(argv(i) == "--loop")
343                         radarmapper.count |= 2;
344                 else if(argv(i) == "--quit")
345                         radarmapper.count |= 4;
346                 else if(argv(i) == "--block")
347                 {
348                         radarmapper.count &~= 24;
349                 }
350                 else if(argv(i) == "--trace")
351                 {
352                         radarmapper.count &~= 24;
353                         radarmapper.count |= 8;
354                 }
355                 else if(argv(i) == "--sample")
356                 {
357                         radarmapper.count &~= 24;
358                         radarmapper.count |= 16;
359                 }
360                 else if(argv(i) == "--flags") // for the recursive call
361                 {
362                         ++i;
363                         radarmapper.count = stof(argv(i));
364                 }
365                 else if(argv(i) == "--sharpen") // for the recursive call
366                 {
367                         ++i;
368                         radarmapper.ltime = stof(argv(i));
369                 }
370                 else if(argv(i) == "--res") // resolution
371                 {
372                         ++i;
373                         radarmapper.size_x = stof(argv(i));
374                         ++i;
375                         radarmapper.size_y = stof(argv(i));
376                 }
377                 else if(argv(i) == "--qual") // quality multiplier
378                 {
379                         ++i;
380                         radarmapper.size_z = stof(argv(i));
381                 }
382                 else
383                 {
384                         remove(radarmapper);
385                         print("Usage: sv_cmd radarmap [--force] [--loop] [--quit] [--block | --trace | --sample] [--sharpen N] [--res W H] [--qual Q]\n");
386                         print("The quality factor Q is roughly proportional to the time taken.\n");
387                         print("--trace supports no quality factor; its result should look like --block with infinite quality factor.\n");
388                         print("--block \n");
389                         return;
390                 }
391         }
392 }
393
394 void BBox()
395 {
396         print("Original size: ", ftos(world.absmin_x), " ", ftos(world.absmin_y), " ", ftos(world.absmin_z));
397         print(" ", ftos(world.absmax_x), " ", ftos(world.absmax_y), " ", ftos(world.absmax_z), "\n");
398         print("Currently set size: ", ftos(world.mins_x), " ", ftos(world.mins_y), " ", ftos(world.mins_z));
399         print(" ", ftos(world.maxs_x), " ", ftos(world.maxs_y), " ", ftos(world.maxs_z), "\n");
400         print("Solid bounding box size:");
401
402         tracebox('1 0 0' * world.absmin_x,
403                  '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
404                  '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
405                  '1 0 0' * world.absmax_x,
406                          MOVE_WORLDONLY,
407                          world);
408         if(trace_startsolid)
409                 print(" ", ftos(world.absmin_x));
410         else
411                 print(" ", ftos(trace_endpos_x));
412
413         tracebox('0 1 0' * world.absmin_y,
414                  '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
415                  '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
416                  '0 1 0' * world.absmax_y,
417                          MOVE_WORLDONLY,
418                          world);
419         if(trace_startsolid)
420                 print(" ", ftos(world.absmin_y));
421         else
422                 print(" ", ftos(trace_endpos_y));
423
424         tracebox('0 0 1' * world.absmin_z,
425                  '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
426                  '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
427                  '0 0 1' * world.absmax_z,
428                          MOVE_WORLDONLY,
429                          world);
430         if(trace_startsolid)
431                 print(" ", ftos(world.absmin_z));
432         else
433                 print(" ", ftos(trace_endpos_z));
434
435         tracebox('1 0 0' * world.absmax_x,
436                  '0 1 0' * world.absmin_y + '0 0 1' * world.absmin_z,
437                  '0 1 0' * world.absmax_y + '0 0 1' * world.absmax_z,
438                  '1 0 0' * world.absmin_x,
439                          MOVE_WORLDONLY,
440                          world);
441         if(trace_startsolid)
442                 print(" ", ftos(world.absmax_x));
443         else
444                 print(" ", ftos(trace_endpos_x));
445
446         tracebox('0 1 0' * world.absmax_y,
447                  '1 0 0' * world.absmin_x + '0 0 1' * world.absmin_z,
448                  '1 0 0' * world.absmax_x + '0 0 1' * world.absmax_z,
449                  '0 1 0' * world.absmin_y,
450                          MOVE_WORLDONLY,
451                          world);
452         if(trace_startsolid)
453                 print(" ", ftos(world.absmax_y));
454         else
455                 print(" ", ftos(trace_endpos_y));
456
457         tracebox('0 0 1' * world.absmax_z,
458                  '1 0 0' * world.absmin_x + '0 1 0' * world.absmin_y,
459                  '1 0 0' * world.absmax_x + '0 1 0' * world.absmax_y,
460                  '0 0 1' * world.absmin_z,
461                          MOVE_WORLDONLY,
462                          world);
463         if(trace_startsolid)
464                 print(" ", ftos(world.absmax_z));
465         else
466                 print(" ", ftos(trace_endpos_z));
467
468         print("\n");
469 }
470
471 void EffectIndexDump()
472 {
473         float d;
474         float fh;
475         string s;
476
477         d = db_create();
478
479         print("begin of effects list\n");
480         db_put(d, "TE_GUNSHOT", "1"); print("effect TE_GUNSHOT is ", ftos(particleeffectnum("TE_GUNSHOT")), "\n");
481         db_put(d, "TE_GUNSHOTQUAD", "1"); print("effect TE_GUNSHOTQUAD is ", ftos(particleeffectnum("TE_GUNSHOTQUAD")), "\n");
482         db_put(d, "TE_SPIKE", "1"); print("effect TE_SPIKE is ", ftos(particleeffectnum("TE_SPIKE")), "\n");
483         db_put(d, "TE_SPIKEQUAD", "1"); print("effect TE_SPIKEQUAD is ", ftos(particleeffectnum("TE_SPIKEQUAD")), "\n");
484         db_put(d, "TE_SUPERSPIKE", "1"); print("effect TE_SUPERSPIKE is ", ftos(particleeffectnum("TE_SUPERSPIKE")), "\n");
485         db_put(d, "TE_SUPERSPIKEQUAD", "1"); print("effect TE_SUPERSPIKEQUAD is ", ftos(particleeffectnum("TE_SUPERSPIKEQUAD")), "\n");
486         db_put(d, "TE_WIZSPIKE", "1"); print("effect TE_WIZSPIKE is ", ftos(particleeffectnum("TE_WIZSPIKE")), "\n");
487         db_put(d, "TE_KNIGHTSPIKE", "1"); print("effect TE_KNIGHTSPIKE is ", ftos(particleeffectnum("TE_KNIGHTSPIKE")), "\n");
488         db_put(d, "TE_EXPLOSION", "1"); print("effect TE_EXPLOSION is ", ftos(particleeffectnum("TE_EXPLOSION")), "\n");
489         db_put(d, "TE_EXPLOSIONQUAD", "1"); print("effect TE_EXPLOSIONQUAD is ", ftos(particleeffectnum("TE_EXPLOSIONQUAD")), "\n");
490         db_put(d, "TE_TAREXPLOSION", "1"); print("effect TE_TAREXPLOSION is ", ftos(particleeffectnum("TE_TAREXPLOSION")), "\n");
491         db_put(d, "TE_TELEPORT", "1"); print("effect TE_TELEPORT is ", ftos(particleeffectnum("TE_TELEPORT")), "\n");
492         db_put(d, "TE_LAVASPLASH", "1"); print("effect TE_LAVASPLASH is ", ftos(particleeffectnum("TE_LAVASPLASH")), "\n");
493         db_put(d, "TE_SMALLFLASH", "1"); print("effect TE_SMALLFLASH is ", ftos(particleeffectnum("TE_SMALLFLASH")), "\n");
494         db_put(d, "TE_FLAMEJET", "1"); print("effect TE_FLAMEJET is ", ftos(particleeffectnum("TE_FLAMEJET")), "\n");
495         db_put(d, "EF_FLAME", "1"); print("effect EF_FLAME is ", ftos(particleeffectnum("EF_FLAME")), "\n");
496         db_put(d, "TE_BLOOD", "1"); print("effect TE_BLOOD is ", ftos(particleeffectnum("TE_BLOOD")), "\n");
497         db_put(d, "TE_SPARK", "1"); print("effect TE_SPARK is ", ftos(particleeffectnum("TE_SPARK")), "\n");
498         db_put(d, "TE_PLASMABURN", "1"); print("effect TE_PLASMABURN is ", ftos(particleeffectnum("TE_PLASMABURN")), "\n");
499         db_put(d, "TE_TEI_G3", "1"); print("effect TE_TEI_G3 is ", ftos(particleeffectnum("TE_TEI_G3")), "\n");
500         db_put(d, "TE_TEI_SMOKE", "1"); print("effect TE_TEI_SMOKE is ", ftos(particleeffectnum("TE_TEI_SMOKE")), "\n");
501         db_put(d, "TE_TEI_BIGEXPLOSION", "1"); print("effect TE_TEI_BIGEXPLOSION is ", ftos(particleeffectnum("TE_TEI_BIGEXPLOSION")), "\n");
502         db_put(d, "TE_TEI_PLASMAHIT", "1"); print("effect TE_TEI_PLASMAHIT is ", ftos(particleeffectnum("TE_TEI_PLASMAHIT")), "\n");
503         db_put(d, "EF_STARDUST", "1"); print("effect EF_STARDUST is ", ftos(particleeffectnum("EF_STARDUST")), "\n");
504         db_put(d, "TR_ROCKET", "1"); print("effect TR_ROCKET is ", ftos(particleeffectnum("TR_ROCKET")), "\n");
505         db_put(d, "TR_GRENADE", "1"); print("effect TR_GRENADE is ", ftos(particleeffectnum("TR_GRENADE")), "\n");
506         db_put(d, "TR_BLOOD", "1"); print("effect TR_BLOOD is ", ftos(particleeffectnum("TR_BLOOD")), "\n");
507         db_put(d, "TR_WIZSPIKE", "1"); print("effect TR_WIZSPIKE is ", ftos(particleeffectnum("TR_WIZSPIKE")), "\n");
508         db_put(d, "TR_SLIGHTBLOOD", "1"); print("effect TR_SLIGHTBLOOD is ", ftos(particleeffectnum("TR_SLIGHTBLOOD")), "\n");
509         db_put(d, "TR_KNIGHTSPIKE", "1"); print("effect TR_KNIGHTSPIKE is ", ftos(particleeffectnum("TR_KNIGHTSPIKE")), "\n");
510         db_put(d, "TR_VORESPIKE", "1"); print("effect TR_VORESPIKE is ", ftos(particleeffectnum("TR_VORESPIKE")), "\n");
511         db_put(d, "TR_NEHAHRASMOKE", "1"); print("effect TR_NEHAHRASMOKE is ", ftos(particleeffectnum("TR_NEHAHRASMOKE")), "\n");
512         db_put(d, "TR_NEXUIZPLASMA", "1"); print("effect TR_NEXUIZPLASMA is ", ftos(particleeffectnum("TR_NEXUIZPLASMA")), "\n");
513         db_put(d, "TR_GLOWTRAIL", "1"); print("effect TR_GLOWTRAIL is ", ftos(particleeffectnum("TR_GLOWTRAIL")), "\n");
514         db_put(d, "SVC_PARTICLE", "1"); print("effect SVC_PARTICLE is ", ftos(particleeffectnum("SVC_PARTICLE")), "\n");
515
516         fh = fopen("effectinfo.txt", FILE_READ);
517         while((s = fgets(fh)))
518         {
519                 tokenize_insane(s); // tokenize_sane would hit the loop counter :(
520                 if(argv(0) == "effect")
521                 {
522                         if(db_get(d, argv(1)) != "1")
523                         {
524                                 if(particleeffectnum(argv(1)) >= 0)
525                                         print("effect ", argv(1), " is ", ftos(particleeffectnum(argv(1))), "\n");
526                                 db_put(d, argv(1), "1");
527                         }
528                 }
529         }
530         print("end of effects list\n");
531
532         db_close(d);
533 }
534
535 void make_mapinfo_Think()
536 {
537         if(MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
538         {
539                 print("Done rebuiling mapinfos.\n");
540                 MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), 0, (g_maplist_allow_hidden ? MAPINFO_FLAG_HIDDEN : 0), 0);
541                 remove(self);
542         }
543         else
544         {
545                 self.think = make_mapinfo_Think;
546                 self.nextthink = time;
547         }
548 }
549
550 void GameCommand(string command)
551 {
552         float argc;
553         entity client;
554         float entno;
555         argc = tokenize_sane(command);
556
557         if(argv(0) == "help" || argc == 0)
558         {
559                 print("Usage: sv_cmd COMMAND..., where possible commands are:\n");
560                 print("  adminmsg clientnumber \"message\"\n");
561                 print("  teamstatus\n");
562                 print("  printstats\n");
563                 print("  make_mapinfo\n");
564                 print("  gametype dm|ctf|...\n");
565                 print("  savedb filename\n");
566                 print("  dumpdb filename\n");
567                 print("  loaddb filename\n");
568                 print("  allready\n");
569                 print("  effectindexdump\n");
570                 print("  radarmap [--force] [--quit | --loop] [sharpness]\n");
571                 print("  bbox\n");
572                 print("  cvar_changes\n");
573                 print("  find classname\n");
574                 GameCommand_Vote("help", world);
575                 GameCommand_Ban("help");
576                 GameCommand_Generic("help");
577                 return;
578         }
579
580         if(GameCommand_Vote(command, world))
581                 return;
582
583         if(GameCommand_Ban(command))
584                 return;
585
586         if(GameCommand_Generic(command))
587                 return;
588
589         if(argv(0) == "printstats")
590         {
591                 DumpStats(FALSE);
592                 return;
593         }
594
595         if(argv(0) == "make_mapinfo")
596         {
597                 entity e;
598                 e = spawn();
599                 e.classname = "make_mapinfo";
600                 e.think = make_mapinfo_Think;
601                 e.nextthink = time;
602                 MapInfo_Enumerate();
603                 return;
604         }
605
606         if(argv(0) == "warp") if(argc == 2) if(cvar("g_campaign"))
607         {
608                 CampaignLevelWarp(stof(argv(1)));
609                 return;
610         }
611
612         if(argv(0) == "gotomap") if(argc == 2)
613         {
614                 print(GotoMap(argv(1)), "\n");
615                 return;
616         }
617
618         if(argv(0) == "gametype") if(argc == 2)
619         {
620                 float t, tsave;
621                 string s;
622                 s = argv(1);
623                 t = MapInfo_Type_FromString(s);
624                 tsave = MapInfo_CurrentGametype();
625                 if(t)
626                 {
627                         MapInfo_SwitchGameType(t);
628                         MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), 0, MAPINFO_FLAG_HIDDEN, 0);
629                         if(MapInfo_count > 0)
630                         {
631                                 bprint("Game type successfully switched to ", s, "\n");
632                                 MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), 0, (g_maplist_allow_hidden ? MAPINFO_FLAG_HIDDEN : 0), 0);
633                         }
634                         else
635                         {
636                                 bprint("Cannot use this game type: no map for it found\n");
637                                 MapInfo_SwitchGameType(tsave);
638                                 MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), 0, (g_maplist_allow_hidden ? MAPINFO_FLAG_HIDDEN : 0), 0);
639                         }
640                 }
641                 else
642                         bprint("Game type switch to ", s, " failed: this type does not exist!\n");
643                 return;
644         }
645
646         if(argv(0) == "adminmsg") if(argc == 3)
647         {
648                 entno = stof(argv(1));
649                 client = world;
650                 if(entno <= maxclients)
651                         client = edict_num(entno);
652                 if(client.flags & FL_CLIENT)
653                 {
654                         centerprint_atprio(client, CENTERPRIO_ADMIN, strcat("^3SERVER ADMIN:\n\n^7", argv(2)));
655                         sprint(client, strcat("\{1}\{13}^3SERVER ADMIN^7: ", argv(2), "\n"));
656                         print("Message sent to ", client.netname, "\n");
657                 }
658                 else
659                         print("Client not found\n");
660                 return;
661         }
662
663         if(argv(0) == "savedb") if(argc == 2)
664         {
665                 db_save(ServerProgsDB, argv(1));
666                 print("DB saved.\n");
667                 return;
668         }
669
670         if(argv(0) == "dumpdb") if(argc == 2)
671         {
672                 db_dump(ServerProgsDB, argv(1));
673                 print("DB dumped.\n");
674                 return;
675         }
676
677         if(argv(0) == "loaddb") if(argc == 2)
678         {
679                 db_close(ServerProgsDB);
680                 ServerProgsDB = db_load(argv(1));
681                 print("DB loaded.\n");
682                 return;
683         }
684         if (argv(0) == "nospectators")
685         {
686                 blockSpectators = 1;
687                 local entity plr;
688                 FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
689                 {
690                         if(plr.classname == "spectator" || plr.classname == "observer")
691                         {
692                                 plr.spectatortime = time;
693                                 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"));
694                         }
695                 }
696                 bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds!\n"));
697                 return;
698         }
699         if (argv(0) == "lockteams")
700         {
701                 if(teamplay)
702                 {
703                         lockteams = 1;
704                         bprint("^1The teams are now locked.\n");
705                 }
706                 else
707                         bprint("That command can only be used in a team-based gamemode.\n");
708                 return;
709         }
710         if (argv(0) == "unlockteams")
711         {
712                 if(teamplay)
713                 {
714                         lockteams = 0;
715                         bprint("^1The teams are now unlocked.\n");
716                 }
717                 else
718                         bprint("That command can only be used in a team-based gamemode.\n");
719                 return;
720         }
721         if (argv(0) == "movetoteam") if(argc == 3)
722         {
723                 entno = stof(argv(1));
724                 client = world;
725                 if(entno <= maxclients)
726                         client = edict_num(entno);
727                 if(client.flags & FL_CLIENT)
728                 {
729                         float lt;
730                         lt = lockteams;
731                         lockteams = 0;
732
733                         self = client;
734                         SV_ParseClientCommand(strcat("selectteam ", argv(2)));
735
736                         lockteams = lt;
737                 }
738                 else
739                         print("Client not found\n");
740                 return;
741         }
742         if (argv(0) == "teamstatus")
743         {
744                 Score_NicePrint(world);
745                 return;
746         }
747         if (argv(0) == "allready")
748         {
749                 ReadyRestart();
750                 return;
751         }
752         if (argv(0) == "effectindexdump")
753         {
754                 EffectIndexDump();
755                 return;
756         }
757         if (argv(0) == "radarmap")
758         {
759                 RadarMap(argc);
760                 return;
761         }
762         if (argv(0) == "bbox")
763         {
764                 BBox();
765                 return;
766         }
767         if (argv(0) == "cvar_changes")
768         {
769                 print(cvar_changes);
770                 return;
771         }
772         if (argv(0) == "find") if(argc == 2)
773         {
774                 for(client = world; (client = find(client, classname, argv(1))); )
775                         print(etos(client), "\n");
776                 return;
777         }
778         if (argv(0) == "records")
779         {
780                 strunzone(records_reply);
781                 records_reply = strzone(getrecords());
782                 print(records_reply);
783                 return;
784         }
785
786         print("Invalid command. For a list of supported commands, try sv_cmd help.\n");
787 }
788