Xonotic
util.qc
Go to the documentation of this file.
1 #include "util.qh"
2 
3 #if defined(CSQC)
4  #include <client/mutators/_mod.qh>
5  #include <common/constants.qh>
6  #include <common/deathtypes/all.qh>
7  #include <common/gamemodes/_mod.qh>
8  #include <common/mapinfo.qh>
10  #include <common/scores.qh>
11 #elif defined(MENUQC)
12 #elif defined(SVQC)
13  #include <common/constants.qh>
14  #include <common/deathtypes/all.qh>
15  #include <common/gamemodes/_mod.qh>
16  #include <common/mapinfo.qh>
18  #include <common/scores.qh>
19  #include <server/mutators/_mod.qh>
20 #endif
21 
22 #ifdef SVQC
23 float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking
24 {
25  vector pos, dir, t;
26  float nudge;
27  entity stopentity;
28 
29  //nudge = 2 * cvar("collision_impactnudge"); // why not?
30  nudge = 0.5;
31 
32  dir = normalize(v2 - v1);
33 
34  pos = v1 + dir * nudge;
35 
36  float c;
37  c = 0;
38 
39  for (;;)
40  {
41  if(pos * dir >= v2 * dir)
42  {
43  // went too far
44  trace_fraction = 1;
45  trace_endpos = v2;
46  return c;
47  }
48 
49  tracebox(pos, mi, ma, v2, nomonsters, forent);
50  ++c;
51 
52  if(c == 50)
53  {
54  LOG_TRACE("When tracing from ", vtos(v1), " to ", vtos(v2));
55  LOG_TRACE(" Nudging gets us nowhere at ", vtos(pos));
56  LOG_TRACE(" trace_endpos is ", vtos(trace_endpos));
57  LOG_TRACE(" trace distance is ", ftos(vlen(pos - trace_endpos)));
58  }
59 
60  stopentity = trace_ent;
61 
63  {
64  // we started inside solid.
65  // then trace from endpos to pos
66  t = trace_endpos;
67  tracebox(t, mi, ma, pos, nomonsters, forent);
68  ++c;
70  {
71  // t is still inside solid? bad
72  // force advance, then, and retry
73  pos = t + dir * nudge;
74 
75  // but if we hit an entity, stop RIGHT before it
76  if(stopatentity && stopentity && stopentity != ignorestopatentity)
77  {
78  trace_ent = stopentity;
79  trace_endpos = t;
80  trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
81  return c;
82  }
83  }
84  else
85  {
86  // we actually LEFT solid!
87  trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
88  return c;
89  }
90  }
91  else
92  {
93  // pos is outside solid?!? but why?!? never mind, just return it.
94  trace_endpos = pos;
95  trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
96  return c;
97  }
98  }
99 }
100 
101 void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
102 {
103  tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
104 }
105 #endif
106 
107 #ifdef GAMEQC
108 /*
109 ==================
110 findbetterlocation
111 
112 Returns a point at least 12 units away from walls
113 (useful for explosion animations, although the blast is performed where it really happened)
114 Ripped from DPMod
115 ==================
116 */
117 vector findbetterlocation (vector org, float mindist)
118 {
119  vector vec = mindist * '1 0 0';
120  int c = 0;
121  while (c < 6)
122  {
123  traceline (org, org + vec, true, NULL);
124  vec = vec * -1;
125  if (trace_fraction < 1)
126  {
127  vector loc = trace_endpos;
128  traceline (loc, loc + vec, true, NULL);
129  if (trace_fraction >= 1)
130  org = loc + vec;
131  }
132  if (c & 1)
133  {
134  float h = vec.y;
135  vec.y = vec.x;
136  vec.x = vec.z;
137  vec.z = h;
138  }
139  c = c + 1;
140  }
141 
142  return org;
143 }
144 
145 /*
146 * Get "real" origin, in worldspace, even if ent is attached to something else.
147 */
148 vector real_origin(entity ent)
149 {
150  vector v = ((ent.absmin + ent.absmax) * 0.5);
151  entity e = ent.tag_entity;
152 
153  while(e)
154  {
155  v = v + ((e.absmin + e.absmax) * 0.5);
156  e = e.tag_entity;
157  }
158 
159  return v;
160 }
161 #endif
162 
164 
165 void wordwrap_buffer_put(string s)
166 {
167  wordwrap_buffer = strcat(wordwrap_buffer, s);
168 }
169 
170 string wordwrap(string s, float l)
171 {
172  string r;
173  wordwrap_buffer = "";
175  r = wordwrap_buffer;
176  wordwrap_buffer = "";
177  return r;
178 }
179 
180 #ifdef SVQC
181 entity _wordwrap_buffer_sprint_ent;
182 void wordwrap_buffer_sprint(string s)
183 {
184  wordwrap_buffer = strcat(wordwrap_buffer, s);
185  if(s == "\n")
186  {
187  sprint(_wordwrap_buffer_sprint_ent, wordwrap_buffer);
188  wordwrap_buffer = "";
189  }
190 }
191 
192 void wordwrap_sprint(entity to, string s, float l)
193 {
194  wordwrap_buffer = "";
195  _wordwrap_buffer_sprint_ent = to;
196  wordwrap_cb(s, l, wordwrap_buffer_sprint);
197  _wordwrap_buffer_sprint_ent = NULL;
198  if(wordwrap_buffer != "")
199  sprint(to, strcat(wordwrap_buffer, "\n"));
200  wordwrap_buffer = "";
201  return;
202 }
203 #endif
204 
205 #ifndef SVQC
206 string draw_UseSkinFor(string pic)
207 {
208  if(substring(pic, 0, 1) == "/")
209  return substring(pic, 1, strlen(pic)-1);
210  else
211  return strcat(draw_currentSkin, "/", pic);
212 }
213 #endif
214 
215 void wordwrap_cb(string s, float l, void(string) callback)
216 {
217  string c;
218  float lleft, i, j, wlen;
219 
220  s = strzone(s);
221  lleft = l;
222  int len = strlen(s);
223  for (i = 0; i < len; ++i)
224  {
225  if (substring(s, i, 2) == "\\n")
226  {
227  callback("\n");
228  lleft = l;
229  ++i;
230  }
231  else if (substring(s, i, 1) == "\n")
232  {
233  callback("\n");
234  lleft = l;
235  }
236  else if (substring(s, i, 1) == " ")
237  {
238  if (lleft > 0)
239  {
240  callback(" ");
241  --lleft;
242  }
243  }
244  else
245  {
246  for (j = i+1; j < len; ++j)
247  // ^^ this skips over the first character of a word, which
248  // is ALWAYS part of the word
249  // this is safe since if i+1 == strlen(s), i will become
250  // strlen(s)-1 at the end of this block and the function
251  // will terminate. A space can't be the first character we
252  // read here, and neither can a \n be the start, since these
253  // two cases have been handled above.
254  {
255  c = substring(s, j, 1);
256  if (c == " ")
257  break;
258  if (c == "\\")
259  break;
260  if (c == "\n")
261  break;
262  // we need to keep this tempstring alive even if substring is
263  // called repeatedly, so call strcat even though we're not
264  // doing anything
265  callback("");
266  }
267  wlen = j - i;
268  if (lleft < wlen)
269  {
270  callback("\n");
271  lleft = l;
272  }
273  callback(substring(s, i, wlen));
274  lleft -= wlen;
275  i = j - 1;
276  }
277  }
278  strunzone(s);
279 }
280 
281 void depthfirst(entity start, .entity up, .entity downleft, .entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
282 {
283  entity e;
284  e = start;
285  funcPre(pass, e);
286  while (e.(downleft))
287  {
288  e = e.(downleft);
289  funcPre(pass, e);
290  }
291  funcPost(pass, e);
292  while(e != start)
293  {
294  if (e.(right))
295  {
296  e = e.(right);
297  funcPre(pass, e);
298  while (e.(downleft))
299  {
300  e = e.(downleft);
301  funcPre(pass, e);
302  }
303  }
304  else
305  e = e.(up);
306  funcPost(pass, e);
307  }
308 }
309 
310 #ifdef GAMEQC
311 string ScoreString(int pFlags, float pValue)
312 {
313  string valstr;
314  float l;
315 
316  pValue = floor(pValue + 0.5); // round
317 
318  if((pValue == 0) && (pFlags & (SFL_HIDE_ZERO | SFL_RANK | SFL_TIME)))
319  valstr = "";
320  else if(pFlags & SFL_RANK)
321  valstr = (pValue < 256 ? count_ordinal(pValue) : _("N/A"));
322  else if(pFlags & SFL_TIME)
323  valstr = TIME_ENCODED_TOSTRING(pValue);
324  else
325  valstr = ftos(pValue);
326 
327  return valstr;
328 }
329 #endif
330 
331 // compressed vector format:
332 // like MD3, just even shorter
333 // 4 bit pitch (16 angles), 0 is -90, 8 is 0, 16 would be 90
334 // 5 bit yaw (32 angles), 0=0, 8=90, 16=180, 24=270
335 // 7 bit length (logarithmic encoding), 1/8 .. about 7844
336 // length = 2^(length_encoded/8) / 8
337 // if pitch is 90, yaw does nothing and therefore indicates the sign (yaw is then either 11111 or 11110); 11111 is pointing DOWN
338 // thus, valid values are from 0000.11110.0000000 to 1111.11111.1111111
339 // the special value 0 indicates the zero vector
340 
341 float lengthLogTable[128];
342 
343 float invertLengthLog(float dist)
344 {
345  int l, r, m;
346 
347  if(dist >= lengthLogTable[127])
348  return 127;
349  if(dist <= lengthLogTable[0])
350  return 0;
351 
352  l = 0;
353  r = 127;
354 
355  while(r - l > 1)
356  {
357  m = floor((l + r) / 2);
358  if(lengthLogTable[m] < dist)
359  l = m;
360  else
361  r = m;
362  }
363 
364  // now: r is >=, l is <
365  float lerr = (dist - lengthLogTable[l]);
366  float rerr = (lengthLogTable[r] - dist);
367  if(lerr < rerr)
368  return l;
369  return r;
370 }
371 
373 {
374  vector out;
375  if(data == 0)
376  return '0 0 0';
377  float p = (data & 0xF000) / 0x1000;
378  float q = (data & 0x0F80) / 0x80;
379  int len = (data & 0x007F);
380 
381  //print("\ndecompress: p ", ftos(p)); print("q ", ftos(q)); print("len ", ftos(len), "\n");
382 
383  if(p == 0)
384  {
385  out.x = 0;
386  out.y = 0;
387  if(q == 31)
388  out.z = -1;
389  else
390  out.z = +1;
391  }
392  else
393  {
394  q = .19634954084936207740 * q;
395  p = .19634954084936207740 * p - 1.57079632679489661922;
396  out.x = cos(q) * cos(p);
397  out.y = sin(q) * cos(p);
398  out.z = -sin(p);
399  }
400 
401  //print("decompressed: ", vtos(out), "\n");
402 
403  return out * lengthLogTable[len];
404 }
405 
407 {
408  vector ang;
409  float p, y, len;
410  if(vec == '0 0 0')
411  return 0;
412  //print("compress: ", vtos(vec), "\n");
413  ang = vectoangles(vec);
414  ang.x = -ang.x;
415  if(ang.x < -90)
416  ang.x += 360;
417  if(ang.x < -90 && ang.x > +90)
418  error("BOGUS vectoangles");
419  //print("angles: ", vtos(ang), "\n");
420 
421  p = floor(0.5 + (ang.x + 90) * 16 / 180) & 15; // -90..90 to 0..14
422  if(p == 0)
423  {
424  if(vec.z < 0)
425  y = 31;
426  else
427  y = 30;
428  }
429  else
430  y = floor(0.5 + ang.y * 32 / 360) & 31; // 0..360 to 0..32
431  len = invertLengthLog(vlen(vec));
432 
433  //print("compressed: p ", ftos(p)); print("y ", ftos(y)); print("len ", ftos(len), "\n");
434 
435  return (p * 0x1000) + (y * 0x80) + len;
436 }
437 
439 {
440  float l = 1;
441  float f = (2 ** (1/8));
442  int i;
443  for(i = 0; i < 128; ++i)
444  {
445  lengthLogTable[i] = l;
446  l *= f;
447  }
448 
449  if(cvar("developer") > 0)
450  {
451  LOG_TRACE("Verifying vector compression table...");
452  for(i = 0x0F00; i < 0xFFFF; ++i)
454  {
455  LOG_FATALF(
456  "BROKEN vector compression: %s -> %s -> %s",
457  ftos(i),
460  );
461  }
462  LOG_TRACE("Done.");
463  }
464 }
465 
466 #ifdef GAMEQC
467 float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz)
468 {
469  traceline(v0, v0 + dvx, true, forent); if(trace_fraction < 1) return 0;
470  traceline(v0, v0 + dvy, true, forent); if(trace_fraction < 1) return 0;
471  traceline(v0, v0 + dvz, true, forent); if(trace_fraction < 1) return 0;
472  traceline(v0 + dvx, v0 + dvx + dvy, true, forent); if(trace_fraction < 1) return 0;
473  traceline(v0 + dvx, v0 + dvx + dvz, true, forent); if(trace_fraction < 1) return 0;
474  traceline(v0 + dvy, v0 + dvy + dvx, true, forent); if(trace_fraction < 1) return 0;
475  traceline(v0 + dvy, v0 + dvy + dvz, true, forent); if(trace_fraction < 1) return 0;
476  traceline(v0 + dvz, v0 + dvz + dvx, true, forent); if(trace_fraction < 1) return 0;
477  traceline(v0 + dvz, v0 + dvz + dvy, true, forent); if(trace_fraction < 1) return 0;
478  traceline(v0 + dvx + dvy, v0 + dvx + dvy + dvz, true, forent); if(trace_fraction < 1) return 0;
479  traceline(v0 + dvx + dvz, v0 + dvx + dvy + dvz, true, forent); if(trace_fraction < 1) return 0;
480  traceline(v0 + dvy + dvz, v0 + dvx + dvy + dvz, true, forent); if(trace_fraction < 1) return 0;
481  return 1;
482 }
483 #endif
484 
485 string fixPriorityList(string order, float from, float to, float subtract, float complete)
486 {
487  string neworder;
488  float i, n, w;
489 
490  n = tokenize_console(order);
491  neworder = "";
492  for(i = 0; i < n; ++i)
493  {
494  w = stof(argv(i));
495  if(w == floor(w))
496  {
497  if(w >= from && w <= to)
498  neworder = strcat(neworder, ftos(w), " ");
499  else
500  {
501  w -= subtract;
502  if(w >= from && w <= to)
503  neworder = strcat(neworder, ftos(w), " ");
504  }
505  }
506  }
507 
508  if(complete)
509  {
510  n = tokenize_console(neworder);
511  for(w = to; w >= from; --w)
512  {
513  int wflags = REGISTRY_GET(Weapons, w).spawnflags;
514  if(wflags & WEP_FLAG_SPECIALATTACK)
515  continue;
516  for(i = 0; i < n; ++i)
517  if(stof(argv(i)) == w)
518  break;
519  if(i == n) // not found
520  neworder = strcat(neworder, ftos(w), " ");
521  }
522  }
523 
524  return substring(neworder, 0, strlen(neworder) - 1);
525 }
526 
527 string mapPriorityList(string order, string(string) mapfunc)
528 {
529  string neworder;
530  float n;
531 
532  n = tokenize_console(order);
533  neworder = "";
534  for(float i = 0; i < n; ++i)
535  neworder = strcat(neworder, mapfunc(argv(i)), " ");
536 
537  return substring(neworder, 0, strlen(neworder) - 1);
538 }
539 
540 string swapInPriorityList(string order, float i, float j)
541 {
542  float n = tokenize_console(order);
543 
544  if(i >= 0 && i < n && j >= 0 && j < n && i != j)
545  {
546  string s = "";
547  for(float w = 0; w < n; ++w)
548  {
549  if(w == i)
550  s = strcat(s, argv(j), " ");
551  else if(w == j)
552  s = strcat(s, argv(i), " ");
553  else
554  s = strcat(s, argv(w), " ");
555  }
556  return substring(s, 0, strlen(s) - 1);
557  }
558 
559  return order;
560 }
561 
562 #ifdef GAMEQC
563 void get_mi_min_max(float mode)
564 {
565  vector mi, ma;
566 
567  string s = mapname;
568  if(!strcasecmp(substring(s, 0, 5), "maps/"))
569  s = substring(s, 5, strlen(s) - 5);
570  if(!strcasecmp(substring(s, strlen(s) - 4, 4), ".bsp"))
571  s = substring(s, 0, strlen(s) - 4);
572  strcpy(mi_shortname, s);
573 
574 #ifdef CSQC
575  mi = world.mins;
576  ma = world.maxs;
577 #else
578  mi = world.absmin;
579  ma = world.absmax;
580 #endif
581 
582  mi_min = mi;
583  mi_max = ma;
584  MapInfo_Get_ByName(mi_shortname, 0, NULL);
586  {
587  mi_min = MapInfo_Map_mins;
588  mi_max = MapInfo_Map_maxs;
589  }
590  else
591  {
592  // not specified
593  if(mode)
594  {
595  // be clever
596  tracebox('1 0 0' * mi.x,
597  '0 1 0' * mi.y + '0 0 1' * mi.z,
598  '0 1 0' * ma.y + '0 0 1' * ma.z,
599  '1 0 0' * ma.x,
601  NULL);
602  if(!trace_startsolid)
603  mi_min.x = trace_endpos.x;
604 
605  tracebox('0 1 0' * mi.y,
606  '1 0 0' * mi.x + '0 0 1' * mi.z,
607  '1 0 0' * ma.x + '0 0 1' * ma.z,
608  '0 1 0' * ma.y,
610  NULL);
611  if(!trace_startsolid)
612  mi_min.y = trace_endpos.y;
613 
614  tracebox('0 0 1' * mi.z,
615  '1 0 0' * mi.x + '0 1 0' * mi.y,
616  '1 0 0' * ma.x + '0 1 0' * ma.y,
617  '0 0 1' * ma.z,
619  NULL);
620  if(!trace_startsolid)
621  mi_min.z = trace_endpos.z;
622 
623  tracebox('1 0 0' * ma.x,
624  '0 1 0' * mi.y + '0 0 1' * mi.z,
625  '0 1 0' * ma.y + '0 0 1' * ma.z,
626  '1 0 0' * mi.x,
628  NULL);
629  if(!trace_startsolid)
630  mi_max.x = trace_endpos.x;
631 
632  tracebox('0 1 0' * ma.y,
633  '1 0 0' * mi.x + '0 0 1' * mi.z,
634  '1 0 0' * ma.x + '0 0 1' * ma.z,
635  '0 1 0' * mi.y,
637  NULL);
638  if(!trace_startsolid)
639  mi_max.y = trace_endpos.y;
640 
641  tracebox('0 0 1' * ma.z,
642  '1 0 0' * mi.x + '0 1 0' * mi.y,
643  '1 0 0' * ma.x + '0 1 0' * ma.y,
644  '0 0 1' * mi.z,
646  NULL);
647  if(!trace_startsolid)
648  mi_max.z = trace_endpos.z;
649  }
650  }
651 }
652 
653 void get_mi_min_max_texcoords(float mode)
654 {
655  vector extend;
656 
657  get_mi_min_max(mode);
658 
659  mi_picmin = mi_min;
660  mi_picmax = mi_max;
661 
662  // extend mi_picmax to get a square aspect ratio
663  // center the map in that area
664  extend = mi_picmax - mi_picmin;
665  if(extend.y > extend.x)
666  {
667  mi_picmin.x -= (extend.y - extend.x) * 0.5;
668  mi_picmax.x += (extend.y - extend.x) * 0.5;
669  }
670  else
671  {
672  mi_picmin.y -= (extend.x - extend.y) * 0.5;
673  mi_picmax.y += (extend.x - extend.y) * 0.5;
674  }
675 
676  // add another some percent
677  extend = (mi_picmax - mi_picmin) * (1 / 64.0);
678  mi_picmin -= extend;
679  mi_picmax += extend;
680 
681  // calculate the texcoords
682  mi_pictexcoord0 = mi_pictexcoord1 = mi_pictexcoord2 = mi_pictexcoord3 = '0 0 0';
683  // first the two corners of the origin
684  mi_pictexcoord0_x = (mi_min.x - mi_picmin.x) / (mi_picmax.x - mi_picmin.x);
685  mi_pictexcoord0_y = (mi_min.y - mi_picmin.y) / (mi_picmax.y - mi_picmin.y);
686  mi_pictexcoord2_x = (mi_max.x - mi_picmin.x) / (mi_picmax.x - mi_picmin.x);
687  mi_pictexcoord2_y = (mi_max.y - mi_picmin.y) / (mi_picmax.y - mi_picmin.y);
688  // then the other corners
689  mi_pictexcoord1_x = mi_pictexcoord0_x;
690  mi_pictexcoord1_y = mi_pictexcoord2_y;
691  mi_pictexcoord3_x = mi_pictexcoord2_x;
692  mi_pictexcoord3_y = mi_pictexcoord0_y;
693 }
694 #endif
695 
696 float cvar_settemp(string tmp_cvar, string tmp_value)
697 {
698  float created_saved_value;
699 
700  created_saved_value = 0;
701 
702  if (!(tmp_cvar || tmp_value))
703  {
704  LOG_TRACE("Error: Invalid usage of cvar_settemp(string, string); !");
705  return 0;
706  }
707 
708  if(!cvar_type(tmp_cvar))
709  {
710  LOG_INFOF("Error: cvar %s doesn't exist!", tmp_cvar);
711  return 0;
712  }
713 
714  IL_EACH(g_saved_cvars, it.netname == tmp_cvar,
715  {
716  created_saved_value = -1; // skip creation
717  break; // no need to continue
718  });
719 
720  if(created_saved_value != -1)
721  {
722  // creating a new entity to keep track of this cvar
723  entity e = new_pure(saved_cvar_value);
725  e.netname = strzone(tmp_cvar);
726  e.message = strzone(cvar_string(tmp_cvar));
727  created_saved_value = 1;
728  }
729 
730  // update the cvar to the value given
731  cvar_set(tmp_cvar, tmp_value);
732 
733  return created_saved_value;
734 }
735 
737 {
738  int j = 0;
739  // FIXME this new-style loop fails!
740 #if 0
741  FOREACH_ENTITY_CLASS("saved_cvar_value", true,
742  {
743  if(cvar_type(it.netname))
744  {
745  cvar_set(it.netname, it.message);
746  strunzone(it.netname);
747  strunzone(it.message);
748  delete(it);
749  ++j;
750  }
751  else
752  LOG_INFOF("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.", it.netname);
753  });
754 
755 #else
756  entity e = NULL;
757  while((e = find(e, classname, "saved_cvar_value")))
758  {
759  if(cvar_type(e.netname))
760  {
761  cvar_set(e.netname, e.message);
762  delete(e);
763  ++j;
764  }
765  else
766  print(sprintf("Error: cvar %s doesn't exist anymore! It can still be restored once it's manually recreated.", e.netname));
767  }
768 #endif
769 
770  return j;
771 }
772 
773 float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w)
774 {
775  // STOP.
776  // The following function is SLOW.
777  // For your safety and for the protection of those around you...
778  // DO NOT CALL THIS AT HOME.
779  // No really, don't.
780  if(w(theText, theSize) <= maxWidth)
781  return strlen(theText); // yeah!
782 
783  bool colors = (w("^7", theSize) == 0);
784 
785  // binary search for right place to cut string
786  int len, left, right, middle;
787  left = 0;
788  right = len = strlen(theText);
789  int ofs = 0;
790  do
791  {
792  middle = floor((left + right) / 2);
793  if(colors)
794  {
795  vector res = checkColorCode(theText, len, middle, false);
796  ofs = (res.x) ? res.x - res.y : 0;
797  }
798 
799  if(w(substring(theText, 0, middle + ofs), theSize) <= maxWidth)
800  left = middle + ofs;
801  else
802  right = middle;
803  }
804  while(left < right - 1);
805 
806  return left;
807 }
808 
809 float textLengthUpToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t w)
810 {
811  // STOP.
812  // The following function is SLOW.
813  // For your safety and for the protection of those around you...
814  // DO NOT CALL THIS AT HOME.
815  // No really, don't.
816  if(w(theText) <= maxWidth)
817  return strlen(theText); // yeah!
818 
819  bool colors = (w("^7") == 0);
820 
821  // binary search for right place to cut string
822  int len, left, right, middle;
823  left = 0;
824  right = len = strlen(theText);
825  int ofs = 0;
826  do
827  {
828  middle = floor((left + right) / 2);
829  if(colors)
830  {
831  vector res = checkColorCode(theText, len, middle, true);
832  ofs = (!res.x) ? 0 : res.x - res.y;
833  }
834 
835  if(w(substring(theText, 0, middle + ofs)) <= maxWidth)
836  left = middle + ofs;
837  else
838  right = middle;
839  }
840  while(left < right - 1);
841 
842  return left;
843 }
844 
845 string find_last_color_code(string s)
846 {
847  int start = strstrofs(s, "^", 0);
848  if (start == -1) // no caret found
849  return "";
850  int len = strlen(s)-1;
851  for(int i = len; i >= start; --i)
852  {
853  if(substring(s, i, 1) != "^")
854  continue;
855 
856  int carets = 1;
857  while (i-carets >= start && substring(s, i-carets, 1) == "^")
858  ++carets;
859 
860  // check if carets aren't all escaped
861  if (carets & 1)
862  {
863  if(i+1 <= len)
864  if(IS_DIGIT(substring(s, i+1, 1)))
865  return substring(s, i, 2);
866 
867  if(i+4 <= len)
868  if(substring(s, i+1, 1) == "x")
869  if(IS_HEXDIGIT(substring(s, i + 2, 1)))
870  if(IS_HEXDIGIT(substring(s, i + 3, 1)))
871  if(IS_HEXDIGIT(substring(s, i + 4, 1)))
872  return substring(s, i, 5);
873  }
874  i -= carets; // this also skips one char before the carets
875  }
876 
877  return "";
878 }
879 
881 {
882  string s = getWrappedLine_remaining;
883 
884  if(w <= 0)
885  {
887  return s; // the line has no size ANYWAY, nothing would be displayed.
888  }
889 
890  int take_until = textLengthUpToWidth(s, w, theFontSize, tw);
891  if(take_until > 0 && take_until < strlen(s))
892  {
893  int last_word = take_until - 1;
894  while(last_word > 0 && substring(s, last_word, 1) != " ")
895  --last_word;
896 
897  int skip = 0;
898  if(last_word != 0)
899  {
900  take_until = last_word;
901  skip = 1;
902  }
903 
904  getWrappedLine_remaining = substring(s, take_until + skip, strlen(s) - take_until);
905  if(getWrappedLine_remaining == "")
907  else if (tw("^7", theFontSize) == 0)
909  return substring(s, 0, take_until);
910  }
911  else
912  {
914  return s;
915  }
916 }
917 
919 {
920  string s = getWrappedLine_remaining;
921 
922  if(w <= 0)
923  {
925  return s; // the line has no size ANYWAY, nothing would be displayed.
926  }
927 
928  int take_until = textLengthUpToLength(s, w, tw);
929  if(take_until > 0 && take_until < strlen(s))
930  {
931  int last_word = take_until - 1;
932  while(last_word > 0 && substring(s, last_word, 1) != " ")
933  --last_word;
934 
935  int skip = 0;
936  if(last_word != 0)
937  {
938  take_until = last_word;
939  skip = 1;
940  }
941 
942  getWrappedLine_remaining = substring(s, take_until + skip, strlen(s) - take_until);
943  if(getWrappedLine_remaining == "")
945  else if (tw("^7") == 0)
947  return substring(s, 0, take_until);
948  }
949  else
950  {
952  return s;
953  }
954 }
955 
956 string textShortenToWidth(string theText, float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
957 {
958  if(tw(theText, theFontSize) <= maxWidth)
959  return theText;
960  else
961  return strcat(substring(theText, 0, textLengthUpToWidth(theText, maxWidth - tw("...", theFontSize), theFontSize, tw)), "...");
962 }
963 
964 string textShortenToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t tw)
965 {
966  if(tw(theText) <= maxWidth)
967  return theText;
968  else
969  return strcat(substring(theText, 0, textLengthUpToLength(theText, maxWidth - tw("..."), tw)), "...");
970 }
971 
972 float isGametypeInFilter(Gametype gt, float tp, float ts, string pattern)
973 {
974  string subpattern, subpattern2, subpattern3, subpattern4;
975  subpattern = strcat(",", MapInfo_Type_ToString(gt), ",");
976  if(tp)
977  subpattern2 = ",teams,";
978  else
979  subpattern2 = ",noteams,";
980  if(ts)
981  subpattern3 = ",teamspawns,";
982  else
983  subpattern3 = ",noteamspawns,";
984  if(gt == MAPINFO_TYPE_RACE || gt == MAPINFO_TYPE_CTS)
985  subpattern4 = ",race,";
986  else
987  subpattern4 = string_null;
988 
989  if(substring(pattern, 0, 1) == "-")
990  {
991  pattern = substring(pattern, 1, strlen(pattern) - 1);
992  if(strstrofs(strcat(",", pattern, ","), subpattern, 0) >= 0)
993  return 0;
994  if(strstrofs(strcat(",", pattern, ","), subpattern2, 0) >= 0)
995  return 0;
996  if(strstrofs(strcat(",", pattern, ","), subpattern3, 0) >= 0)
997  return 0;
998  if(subpattern4 && strstrofs(strcat(",", pattern, ","), subpattern4, 0) >= 0)
999  return 0;
1000  }
1001  else
1002  {
1003  if(substring(pattern, 0, 1) == "+")
1004  pattern = substring(pattern, 1, strlen(pattern) - 1);
1005  if(strstrofs(strcat(",", pattern, ","), subpattern, 0) < 0)
1006  if(strstrofs(strcat(",", pattern, ","), subpattern2, 0) < 0)
1007  if(strstrofs(strcat(",", pattern, ","), subpattern3, 0) < 0)
1008  {
1009  if (!subpattern4)
1010  return 0;
1011  if(strstrofs(strcat(",", pattern, ","), subpattern4, 0) < 0)
1012  return 0;
1013  }
1014  }
1015  return 1;
1016 }
1017 
1018 vector solve_shotdirection(vector myorg, vector myvel, vector eorg, vector evel, float spd, float newton_style)
1019 {
1020  vector ret;
1021 
1022  // make origin and speed relative
1023  eorg -= myorg;
1024  if(newton_style)
1025  evel -= myvel;
1026 
1027  // now solve for ret, ret normalized:
1028  // eorg + t * evel == t * ret * spd
1029  // or, rather, solve for t:
1030  // |eorg + t * evel| == t * spd
1031  // eorg^2 + t^2 * evel^2 + 2 * t * (eorg * evel) == t^2 * spd^2
1032  // t^2 * (evel^2 - spd^2) + t * (2 * (eorg * evel)) + eorg^2 == 0
1033  vector solution = solve_quadratic(evel * evel - spd * spd, 2 * (eorg * evel), eorg * eorg);
1034  // p = 2 * (eorg * evel) / (evel * evel - spd * spd)
1035  // q = (eorg * eorg) / (evel * evel - spd * spd)
1036  if(!solution.z) // no real solution
1037  {
1038  // happens if D < 0
1039  // (eorg * evel)^2 < (evel^2 - spd^2) * eorg^2
1040  // (eorg * evel)^2 / eorg^2 < evel^2 - spd^2
1041  // spd^2 < ((evel^2 * eorg^2) - (eorg * evel)^2) / eorg^2
1042  // spd^2 < evel^2 * (1 - cos^2 angle(evel, eorg))
1043  // spd^2 < evel^2 * sin^2 angle(evel, eorg)
1044  // spd < |evel| * sin angle(evel, eorg)
1045  return '0 0 0';
1046  }
1047  else if(solution.x > 0)
1048  {
1049  // both solutions > 0: take the smaller one
1050  // happens if p < 0 and q > 0
1051  ret = normalize(eorg + solution.x * evel);
1052  }
1053  else if(solution.y > 0)
1054  {
1055  // one solution > 0: take the larger one
1056  // happens if q < 0 or q == 0 and p < 0
1057  ret = normalize(eorg + solution.y * evel);
1058  }
1059  else
1060  {
1061  // no solution > 0: reject
1062  // happens if p > 0 and q >= 0
1063  // 2 * (eorg * evel) / (evel * evel - spd * spd) > 0
1064  // (eorg * eorg) / (evel * evel - spd * spd) >= 0
1065  //
1066  // |evel| >= spd
1067  // eorg * evel > 0
1068  //
1069  // "Enemy is moving away from me at more than spd"
1070  return '0 0 0';
1071  }
1072 
1073  // NOTE: we always got a solution if spd > |evel|
1074 
1075  if(newton_style == 2)
1076  ret = normalize(ret * spd + myvel);
1077 
1078  return ret;
1079 }
1080 
1081 vector get_shotvelocity(vector myvel, vector mydir, float spd, float newton_style, float mi, float ma)
1082 {
1083  if(!newton_style)
1084  return spd * mydir;
1085 
1086  if(newton_style == 2)
1087  {
1088  // true Newtonian projectiles with automatic aim adjustment
1089  //
1090  // solve: |outspeed * mydir - myvel| = spd
1091  // outspeed^2 - 2 * outspeed * (mydir * myvel) + myvel^2 - spd^2 = 0
1092  // outspeed = (mydir * myvel) +- sqrt((mydir * myvel)^2 - myvel^2 + spd^2)
1093  // PLUS SIGN!
1094  // not defined?
1095  // then...
1096  // myvel^2 - (mydir * myvel)^2 > spd^2
1097  // velocity without mydir component > spd
1098  // fire at smallest possible spd that works?
1099  // |(mydir * myvel) * myvel - myvel| = spd
1100 
1101  vector solution = solve_quadratic(1, -2 * (mydir * myvel), myvel * myvel - spd * spd);
1102 
1103  float outspeed;
1104  if(solution.z)
1105  outspeed = solution.y; // the larger one
1106  else
1107  {
1108  //outspeed = 0; // slowest possible shot
1109  outspeed = solution.x; // the real part (that is, the average!)
1110  //dprint("impossible shot, adjusting\n");
1111  }
1112 
1113  outspeed = bound(spd * mi, outspeed, spd * ma);
1114  return mydir * outspeed;
1115  }
1116 
1117  // real Newtonian
1118  return myvel + spd * mydir;
1119 }
1120 
1122 {
1123  float rx = rint(v.x * 2);
1124  float ry = rint(v.y * 4) + 128;
1125  float rz = rint(v.z * 4) + 128;
1126  if(rx > 255 || rx < 0)
1127  {
1128  LOG_DEBUG("shot origin ", vtos(v), " x out of bounds\n");
1129  rx = bound(0, rx, 255);
1130  }
1131  if(ry > 255 || ry < 0)
1132  {
1133  LOG_DEBUG("shot origin ", vtos(v), " y out of bounds\n");
1134  ry = bound(0, ry, 255);
1135  }
1136  if(rz > 255 || rz < 0)
1137  {
1138  LOG_DEBUG("shot origin ", vtos(v), " z out of bounds\n");
1139  rz = bound(0, rz, 255);
1140  }
1141  return rx * 0x10000 + ry * 0x100 + rz;
1142 }
1144 {
1145  vector v;
1146  v.x = ((f & 0xFF0000) / 0x10000) / 2;
1147  v.y = ((f & 0xFF00) / 0x100 - 128) / 4;
1148  v.z = ((f & 0xFF) - 128) / 4;
1149  return v;
1150 }
1151 
1152 #ifdef GAMEQC
1153 vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype)
1154 {
1155  // NOTE: we'll always choose the SMALLER value...
1156  float healthdamage, armordamage, armorideal;
1157  if (DEATH_IS(deathtype, DEATH_DROWN)) // Why should armor help here...
1158  armorblock = 0;
1159  vector v;
1160  healthdamage = (h - 1) / (1 - armorblock); // damage we can take if we could use more health
1161  armordamage = a + (h - 1); // damage we can take if we could use more armor
1162  armorideal = healthdamage * armorblock;
1163  v.y = armorideal;
1164  if(armordamage < healthdamage)
1165  {
1166  v.x = armordamage;
1167  v.z = 1;
1168  }
1169  else
1170  {
1171  v.x = healthdamage;
1172  v.z = 0;
1173  }
1174  return v;
1175 }
1176 
1177 vector healtharmor_applydamage(float a, float armorblock, int deathtype, float damage)
1178 {
1179  vector v;
1180  if (DEATH_IS(deathtype, DEATH_DROWN)) // Why should armor help here...
1181  armorblock = 0;
1182  if (deathtype & HITTYPE_ARMORPIERCE)
1183  armorblock = 0;
1184  v.y = bound(0, damage * armorblock, a); // save
1185  v.x = bound(0, damage - v.y, damage); // take
1186  v.z = 0;
1187  return v;
1188 }
1189 #endif
1190 
1192 {
1193  float n;
1194  string m;
1195  m = cvar_string("fs_gamedir");
1196  n = tokenize_console(m);
1197  if(n == 0)
1198  return "data";
1199  else
1200  return argv(n - 1);
1201 }
1202 
1203 float matchacl(string acl, string str)
1204 {
1205  string t, s;
1206  float r, d;
1207  r = 0;
1208  while(acl)
1209  {
1210  t = car(acl); acl = cdr(acl);
1211 
1212  d = 1;
1213  if(substring(t, 0, 1) == "-")
1214  {
1215  d = -1;
1216  t = substring(t, 1, strlen(t) - 1);
1217  }
1218  else if(substring(t, 0, 1) == "+")
1219  t = substring(t, 1, strlen(t) - 1);
1220 
1221  if(substring(t, -1, 1) == "*")
1222  {
1223  t = substring(t, 0, strlen(t) - 1);
1224  s = substring(str, 0, strlen(t));
1225  }
1226  else
1227  s = str;
1228 
1229  if(s == t)
1230  {
1231  r = d;
1232  break; // if we found a killing case, apply it! other settings may be allowed in the future, but this one is caught
1233  }
1234  }
1235  return r;
1236 }
1237 
1238 ERASEABLE
1239 void write_String_To_File(int fh, string str, bool alsoprint)
1240 {
1241  fputs(fh, str);
1242  if (alsoprint) LOG_HELP(str);
1243 }
1244 
1245 string get_model_datafilename(string m, float sk, string fil)
1246 {
1247  if(m)
1248  m = strcat(m, "_");
1249  else
1250  m = "models/player/*_";
1251  if(sk >= 0)
1252  m = strcat(m, ftos(sk));
1253  else
1254  m = strcat(m, "*");
1255  return strcat(m, ".", fil);
1256 }
1257 
1258 float get_model_parameters(string m, float sk)
1259 {
1270  for(int i = 0; i < MAX_AIM_BONES; ++i)
1271  {
1274  }
1277 
1278 #ifdef GAMEQC
1279  MUTATOR_CALLHOOK(ClearModelParams);
1280 #endif
1281 
1282  if (!m)
1283  return 1;
1284 
1285  if(substring(m, -9, 5) == "_lod1" || substring(m, -9, 5) == "_lod2")
1286  m = strcat(substring(m, 0, -10), substring(m, -4, -1));
1287 
1288  if(sk < 0)
1289  {
1290  if(substring(m, -4, -1) != ".txt")
1291  return 0;
1292  if(substring(m, -6, 1) != "_")
1293  return 0;
1294  sk = stof(substring(m, -5, 1));
1295  m = substring(m, 0, -7);
1296  }
1297 
1298  string fn = get_model_datafilename(m, sk, "txt");
1299  int fh = fopen(fn, FILE_READ);
1300  if(fh < 0)
1301  {
1302  sk = 0;
1303  fn = get_model_datafilename(m, sk, "txt");
1304  fh = fopen(fn, FILE_READ);
1305  if(fh < 0)
1306  return 0;
1307  }
1308 
1311  string s, c;
1312  while((s = fgets(fh)))
1313  {
1314  if(s == "")
1315  break; // next lines will be description
1316  c = car(s);
1317  s = cdr(s);
1318  if(c == "name")
1320  if(c == "species")
1321  switch(s)
1322  {
1323  case "human": get_model_parameters_species = SPECIES_HUMAN; break;
1324  case "alien": get_model_parameters_species = SPECIES_ALIEN; break;
1325  case "robot_shiny": get_model_parameters_species = SPECIES_ROBOT_SHINY; break;
1326  case "robot_rusty": get_model_parameters_species = SPECIES_ROBOT_RUSTY; break;
1327  case "robot_solid": get_model_parameters_species = SPECIES_ROBOT_SOLID; break;
1328  case "animal": get_model_parameters_species = SPECIES_ANIMAL; break;
1329  case "reserved": get_model_parameters_species = SPECIES_RESERVED; break;
1330  }
1331  if(c == "sex")
1332  {
1333  if (s == "Male") s = _("Male");
1334  else if (s == "Female") s = _("Female");
1335  else if (s == "Undisclosed") s = _("Undisclosed");
1337  }
1338  if(c == "weight")
1340  if(c == "age")
1342  if(c == "description")
1344  if(c == "bone_upperbody")
1346  if(c == "bone_weapon")
1348  #ifdef GAMEQC
1349  MUTATOR_CALLHOOK(GetModelParams, c, s);
1350  #endif
1351  for(int i = 0; i < MAX_AIM_BONES; ++i)
1352  if(c == strcat("bone_aim", ftos(i)))
1353  {
1356  }
1357  if(c == "fixbone")
1359  if(c == "hidden")
1361  }
1362 
1363  while((s = fgets(fh)))
1364  {
1367  if(s != "")
1369  }
1370 
1371  fclose(fh);
1372 
1373  return 1;
1374 }
1375 
1376 string translate_key(string key)
1377 {
1378  if (prvm_language == "en") return key;
1379 
1380  if (substring(key, 0, 1) == "<")
1381  {
1382  if (key == "<KEY NOT FOUND>") return _("<KEY NOT FOUND>");
1383  if (key == "<UNKNOWN KEYNUM>") return _("<UNKNOWN KEYNUM>");
1384  }
1385 
1386  switch(key)
1387  {
1388  case "TAB": return _("TAB");
1389  case "ENTER": return _("ENTER");
1390  case "ESCAPE": return _("ESCAPE");
1391  case "SPACE": return _("SPACE");
1392 
1393  case "BACKSPACE": return _("BACKSPACE");
1394  case "UPARROW": return _("UPARROW");
1395  case "DOWNARROW": return _("DOWNARROW");
1396  case "LEFTARROW": return _("LEFTARROW");
1397  case "RIGHTARROW": return _("RIGHTARROW");
1398 
1399  case "ALT": return _("ALT");
1400  case "CTRL": return _("CTRL");
1401  case "SHIFT": return _("SHIFT");
1402 
1403  case "INS": return _("INS");
1404  case "DEL": return _("DEL");
1405  case "PGDN": return _("PGDN");
1406  case "PGUP": return _("PGUP");
1407  case "HOME": return _("HOME");
1408  case "END": return _("END");
1409 
1410  case "PAUSE": return _("PAUSE");
1411 
1412  case "NUMLOCK": return _("NUMLOCK");
1413  case "CAPSLOCK": return _("CAPSLOCK");
1414  case "SCROLLOCK": return _("SCROLLOCK");
1415 
1416  case "SEMICOLON": return _("SEMICOLON");
1417  case "TILDE": return _("TILDE");
1418  case "BACKQUOTE": return _("BACKQUOTE");
1419  case "QUOTE": return _("QUOTE");
1420  case "APOSTROPHE": return _("APOSTROPHE");
1421  case "BACKSLASH": return _("BACKSLASH");
1422  }
1423 
1424  if (substring(key, 0, 1) == "F")
1425  {
1426  string subkey = substring(key, 1, -1);
1427  if (IS_DIGIT(substring(key, 3, 1))) // check only first digit
1428  {
1429  return sprintf(_("F%d"), stof(subkey));
1430  }
1431  // continue in case there is another key name starting with F
1432  }
1433 
1434  if (substring(key, 0, 3) == "KP_")
1435  {
1436  string subkey = substring(key, 3, -1);
1437  if (IS_DIGIT(substring(key, 3, 1))) // check only first digit
1438  {
1439  return sprintf(_("KP_%d"), stof(subkey));
1440  }
1441 
1442  switch(subkey)
1443  {
1444  case "INS": return sprintf(_("KP_%s"), _("INS"));
1445  case "END": return sprintf(_("KP_%s"), _("END"));
1446  case "DOWNARROW": return sprintf(_("KP_%s"), _("DOWNARROW"));
1447  case "PGDN": return sprintf(_("KP_%s"), _("PGDN"));
1448  case "LEFTARROW": return sprintf(_("KP_%s"), _("LEFTARROW"));
1449  case "RIGHTARROW": return sprintf(_("KP_%s"), _("RIGHTARROW"));
1450  case "HOME": return sprintf(_("KP_%s"), _("HOME"));
1451  case "UPARROW": return sprintf(_("KP_%s"), _("UPARROW"));
1452  case "PGUP": return sprintf(_("KP_%s"), _("PGUP"));
1453  case "PERIOD": return sprintf(_("KP_%s"), _("PERIOD"));
1454  case "DEL": return sprintf(_("KP_%s"), _("DEL"));
1455  case "DIVIDE": return sprintf(_("KP_%s"), _("DIVIDE"));
1456  case "SLASH": return sprintf(_("KP_%s"), _("SLASH"));
1457  case "MULTIPLY": return sprintf(_("KP_%s"), _("MULTIPLY"));
1458  case "MINUS": return sprintf(_("KP_%s"), _("MINUS"));
1459  case "PLUS": return sprintf(_("KP_%s"), _("PLUS"));
1460  case "ENTER": return sprintf(_("KP_%s"), _("ENTER"));
1461  case "EQUALS": return sprintf(_("KP_%s"), _("EQUALS"));
1462  default: return key;
1463  }
1464  }
1465 
1466  if (key == "PRINTSCREEN") return _("PRINTSCREEN");
1467 
1468  if (substring(key, 0, 5) == "MOUSE")
1469  return sprintf(_("MOUSE%d"), stof(substring(key, 5, -1)));
1470 
1471  if (key == "MWHEELUP") return _("MWHEELUP");
1472  if (key == "MWHEELDOWN") return _("MWHEELDOWN");
1473 
1474  if (substring(key, 0,3) == "JOY")
1475  return sprintf(_("JOY%d"), stof(substring(key, 3, -1)));
1476 
1477  if (substring(key, 0,3) == "AUX")
1478  return sprintf(_("AUX%d"), stof(substring(key, 3, -1)));
1479 
1480  if (substring(key, 0, 4) == "X360_")
1481  {
1482  string subkey = substring(key, 4, -1);
1483  switch(subkey)
1484  {
1485  case "DPAD_UP": return sprintf(_("X360_%s"), _("DPAD_UP"));
1486  case "DPAD_DOWN": return sprintf(_("X360_%s"), _("DPAD_DOWN"));
1487  case "DPAD_LEFT": return sprintf(_("X360_%s"), _("DPAD_LEFT"));
1488  case "DPAD_RIGHT": return sprintf(_("X360_%s"), _("DPAD_RIGHT"));
1489  case "START": return sprintf(_("X360_%s"), _("START"));
1490  case "BACK": return sprintf(_("X360_%s"), _("BACK"));
1491  case "LEFT_THUMB": return sprintf(_("X360_%s"), _("LEFT_THUMB"));
1492  case "RIGHT_THUMB": return sprintf(_("X360_%s"), _("RIGHT_THUMB"));
1493  case "LEFT_SHOULDER": return sprintf(_("X360_%s"), _("LEFT_SHOULDER"));
1494  case "RIGHT_SHOULDER": return sprintf(_("X360_%s"), _("RIGHT_SHOULDER"));
1495  case "LEFT_TRIGGER": return sprintf(_("X360_%s"), _("LEFT_TRIGGER"));
1496  case "RIGHT_TRIGGER": return sprintf(_("X360_%s"), _("RIGHT_TRIGGER"));
1497  case "LEFT_THUMB_UP": return sprintf(_("X360_%s"), _("LEFT_THUMB_UP"));
1498  case "LEFT_THUMB_DOWN": return sprintf(_("X360_%s"), _("LEFT_THUMB_DOWN"));
1499  case "LEFT_THUMB_LEFT": return sprintf(_("X360_%s"), _("LEFT_THUMB_LEFT"));
1500  case "LEFT_THUMB_RIGHT": return sprintf(_("X360_%s"), _("LEFT_THUMB_RIGHT"));
1501  case "RIGHT_THUMB_UP": return sprintf(_("X360_%s"), _("RIGHT_THUMB_UP"));
1502  case "RIGHT_THUMB_DOWN": return sprintf(_("X360_%s"), _("RIGHT_THUMB_DOWN"));
1503  case "RIGHT_THUMB_LEFT": return sprintf(_("X360_%s"), _("RIGHT_THUMB_LEFT"));
1504  case "RIGHT_THUMB_RIGHT": return sprintf(_("X360_%s"), _("RIGHT_THUMB_RIGHT"));
1505  default: return key;
1506  }
1507  }
1508 
1509  if (substring(key, 0, 4) == "JOY_")
1510  {
1511  string subkey = substring(key, 4, -1);
1512  switch(subkey)
1513  {
1514  case "UP": return sprintf(_("JOY_%s"), _("UP"));
1515  case "DOWN": return sprintf(_("JOY_%s"), _("DOWN"));
1516  case "LEFT": return sprintf(_("JOY_%s"), _("LEFT"));
1517  case "RIGHT": return sprintf(_("JOY_%s"), _("RIGHT"));
1518  default: return key;
1519  }
1520  }
1521 
1522  if (substring(key, 0, 8) == "MIDINOTE")
1523  return sprintf(_("MIDINOTE%d"), stof(substring(key, 8, -1)));
1524 
1525  return key;
1526 }
1527 
1528 // x-encoding (encoding as zero length invisible string)
1529 const string XENCODE_2 = "xX";
1530 const string XENCODE_22 = "0123456789abcdefABCDEF";
1531 string xencode(int f)
1532 {
1533  float a, b, c, d;
1534  d = f % 22; f = floor(f / 22);
1535  c = f % 22; f = floor(f / 22);
1536  b = f % 22; f = floor(f / 22);
1537  a = f % 2; // f = floor(f / 2);
1538  return strcat(
1539  "^",
1540  substring(XENCODE_2, a, 1),
1541  substring(XENCODE_22, b, 1),
1542  substring(XENCODE_22, c, 1),
1543  substring(XENCODE_22, d, 1)
1544  );
1545 }
1546 float xdecode(string s)
1547 {
1548  float a, b, c, d;
1549  if(substring(s, 0, 1) != "^")
1550  return -1;
1551  if(strlen(s) < 5)
1552  return -1;
1553  a = strstrofs(XENCODE_2, substring(s, 1, 1), 0);
1554  b = strstrofs(XENCODE_22, substring(s, 2, 1), 0);
1555  c = strstrofs(XENCODE_22, substring(s, 3, 1), 0);
1556  d = strstrofs(XENCODE_22, substring(s, 4, 1), 0);
1557  if(a < 0 || b < 0 || c < 0 || d < 0)
1558  return -1;
1559  return ((a * 22 + b) * 22 + c) * 22 + d;
1560 }
1561 
1562 /*
1563 string strlimitedlen(string input, string truncation, float strip_colors, float limit)
1564 {
1565  if(strlen((strip_colors ? strdecolorize(input) : input)) <= limit)
1566  return input;
1567  else
1568  return strcat(substring(input, 0, (strlen(input) - strlen(truncation))), truncation);
1569 }*/
1570 
1572 #ifdef SVQC
1573 void SV_Shutdown()
1574 #endif
1575 #ifdef CSQC
1576 void CSQC_Shutdown()
1577 #endif
1578 #ifdef MENUQC
1579 void m_shutdown()
1580 #endif
1582  if(shutdown_running)
1583  {
1584  LOG_INFO("Recursive shutdown detected! Only restoring cvars...");
1585  }
1586  else
1587  {
1588  shutdown_running = 1;
1589  Shutdown();
1590  shutdownhooks();
1591  }
1592  cvar_settemp_restore(); // this must be done LAST, but in any case
1593 }
1594 
1595 #ifdef GAMEQC
1596 .float skeleton_bones_index;
1597 void Skeleton_SetBones(entity e)
1598 {
1599  // set skeleton_bones to the total number of bones on the model
1600  if(e.skeleton_bones_index == e.modelindex)
1601  return; // same model, nothing to update
1602 
1603  float skelindex;
1604  skelindex = skel_create(e.modelindex);
1605  e.skeleton_bones = skel_get_numbones(skelindex);
1606  skel_delete(skelindex);
1607  e.skeleton_bones_index = e.modelindex;
1608 }
1609 #endif
1610 
1611 string to_execute_next_frame;
1613 {
1614  if(to_execute_next_frame)
1615  {
1616  localcmd("\n", to_execute_next_frame, "\n");
1617  strfree(to_execute_next_frame);
1618  }
1619 }
1621 {
1622  if(to_execute_next_frame)
1623  {
1624  s = strcat(s, "\n", to_execute_next_frame);
1625  }
1626  strcpy(to_execute_next_frame, s);
1627 }
1628 
1631 {
1632  entity queue_start, queue_end;
1633 
1634  // we build a queue of to-be-processed entities.
1635  // queue_start is the next entity to be checked for neighbors
1636  // queue_end is the last entity added
1637 
1638  if(e.FindConnectedComponent_processing)
1639  error("recursion or broken cleanup");
1640 
1641  // start with a 1-element queue
1642  queue_start = queue_end = e;
1643  queue_end.(fld) = NULL;
1644  queue_end.FindConnectedComponent_processing = 1;
1645 
1646  // for each queued item:
1647  for (; queue_start; queue_start = queue_start.(fld))
1648  {
1649  // find all neighbors of queue_start
1650  entity t;
1651  for(t = NULL; (t = nxt(t, queue_start, pass)); )
1652  {
1653  if(t.FindConnectedComponent_processing)
1654  continue;
1655  if(iscon(t, queue_start, pass))
1656  {
1657  // it is connected? ADD IT. It will look for neighbors soon too.
1658  queue_end.(fld) = t;
1659  queue_end = t;
1660  queue_end.(fld) = NULL;
1661  queue_end.FindConnectedComponent_processing = 1;
1662  }
1663  }
1664  }
1665 
1666  // unmark
1667  for (queue_start = e; queue_start; queue_start = queue_start.(fld))
1668  queue_start.FindConnectedComponent_processing = 0;
1669 }
1670 
1671 #ifdef GAMEQC
1672 vector animfixfps(entity e, vector a, vector b)
1673 {
1674  // multi-frame anim: keep as-is
1675  if(a.y == 1)
1676  {
1677  float dur = frameduration(e.modelindex, a.x);
1678  if (dur <= 0 && b.y)
1679  {
1680  a = b;
1681  dur = frameduration(e.modelindex, a.x);
1682  }
1683  if (dur > 0)
1684  a.z = 1.0 / dur;
1685  }
1686  return a;
1687 }
1688 #endif
1689 
1690 #ifdef GAMEQC
1691 Notification Announcer_PickNumber(int type, int num)
1692 {
1693  return = NULL;
1694  switch (type)
1695  {
1696  case CNT_GAMESTART:
1697  {
1698  switch(num)
1699  {
1700  case 10: return ANNCE_NUM_GAMESTART_10;
1701  case 9: return ANNCE_NUM_GAMESTART_9;
1702  case 8: return ANNCE_NUM_GAMESTART_8;
1703  case 7: return ANNCE_NUM_GAMESTART_7;
1704  case 6: return ANNCE_NUM_GAMESTART_6;
1705  case 5: return ANNCE_NUM_GAMESTART_5;
1706  case 4: return ANNCE_NUM_GAMESTART_4;
1707  case 3: return ANNCE_NUM_GAMESTART_3;
1708  case 2: return ANNCE_NUM_GAMESTART_2;
1709  case 1: return ANNCE_NUM_GAMESTART_1;
1710  }
1711  break;
1712  }
1713  case CNT_KILL:
1714  {
1715  switch(num)
1716  {
1717  case 10: return ANNCE_NUM_KILL_10;
1718  case 9: return ANNCE_NUM_KILL_9;
1719  case 8: return ANNCE_NUM_KILL_8;
1720  case 7: return ANNCE_NUM_KILL_7;
1721  case 6: return ANNCE_NUM_KILL_6;
1722  case 5: return ANNCE_NUM_KILL_5;
1723  case 4: return ANNCE_NUM_KILL_4;
1724  case 3: return ANNCE_NUM_KILL_3;
1725  case 2: return ANNCE_NUM_KILL_2;
1726  case 1: return ANNCE_NUM_KILL_1;
1727  }
1728  break;
1729  }
1730  case CNT_RESPAWN:
1731  {
1732  switch(num)
1733  {
1734  case 10: return ANNCE_NUM_RESPAWN_10;
1735  case 9: return ANNCE_NUM_RESPAWN_9;
1736  case 8: return ANNCE_NUM_RESPAWN_8;
1737  case 7: return ANNCE_NUM_RESPAWN_7;
1738  case 6: return ANNCE_NUM_RESPAWN_6;
1739  case 5: return ANNCE_NUM_RESPAWN_5;
1740  case 4: return ANNCE_NUM_RESPAWN_4;
1741  case 3: return ANNCE_NUM_RESPAWN_3;
1742  case 2: return ANNCE_NUM_RESPAWN_2;
1743  case 1: return ANNCE_NUM_RESPAWN_1;
1744  }
1745  break;
1746  }
1747  case CNT_ROUNDSTART:
1748  {
1749  switch(num)
1750  {
1751  case 10: return ANNCE_NUM_ROUNDSTART_10;
1752  case 9: return ANNCE_NUM_ROUNDSTART_9;
1753  case 8: return ANNCE_NUM_ROUNDSTART_8;
1754  case 7: return ANNCE_NUM_ROUNDSTART_7;
1755  case 6: return ANNCE_NUM_ROUNDSTART_6;
1756  case 5: return ANNCE_NUM_ROUNDSTART_5;
1757  case 4: return ANNCE_NUM_ROUNDSTART_4;
1758  case 3: return ANNCE_NUM_ROUNDSTART_3;
1759  case 2: return ANNCE_NUM_ROUNDSTART_2;
1760  case 1: return ANNCE_NUM_ROUNDSTART_1;
1761  }
1762  break;
1763  }
1764  case CNT_NORMAL:
1765  default:
1766  {
1767  switch(num)
1768  {
1769  case 10: return ANNCE_NUM_10;
1770  case 9: return ANNCE_NUM_9;
1771  case 8: return ANNCE_NUM_8;
1772  case 7: return ANNCE_NUM_7;
1773  case 6: return ANNCE_NUM_6;
1774  case 5: return ANNCE_NUM_5;
1775  case 4: return ANNCE_NUM_4;
1776  case 3: return ANNCE_NUM_3;
1777  case 2: return ANNCE_NUM_2;
1778  case 1: return ANNCE_NUM_1;
1779  }
1780  break;
1781  }
1782  }
1783 }
1784 #endif
1785 
1786 #ifdef GAMEQC
1787 int Mod_Q1BSP_SuperContentsFromNativeContents(int nativecontents)
1788 {
1789  switch(nativecontents)
1790  {
1791  case CONTENT_EMPTY:
1792  return 0;
1793  case CONTENT_SOLID:
1795  case CONTENT_WATER:
1796  return DPCONTENTS_WATER;
1797  case CONTENT_SLIME:
1798  return DPCONTENTS_SLIME;
1799  case CONTENT_LAVA:
1801  case CONTENT_SKY:
1802  return DPCONTENTS_SKY | DPCONTENTS_NODROP | DPCONTENTS_OPAQUE; // to match behaviour of Q3 maps, let sky count as opaque
1803  }
1804  return 0;
1805 }
1806 
1807 int Mod_Q1BSP_NativeContentsFromSuperContents(int supercontents)
1808 {
1809  if(supercontents & (DPCONTENTS_SOLID | DPCONTENTS_BODY))
1810  return CONTENT_SOLID;
1811  if(supercontents & DPCONTENTS_SKY)
1812  return CONTENT_SKY;
1813  if(supercontents & DPCONTENTS_LAVA)
1814  return CONTENT_LAVA;
1815  if(supercontents & DPCONTENTS_SLIME)
1816  return CONTENT_SLIME;
1817  if(supercontents & DPCONTENTS_WATER)
1818  return CONTENT_WATER;
1819  return CONTENT_EMPTY;
1820 }
1821 #endif
1822 
1823 #ifdef SVQC
1824 void attach_sameorigin(entity e, entity to, string tag)
1825 {
1826  vector org, t_forward, t_left, t_up, e_forward, e_up;
1827  float tagscale;
1828 
1829  org = e.origin - gettaginfo(to, gettagindex(to, tag));
1830  tagscale = (vlen(v_forward) ** -2); // undo a scale on the tag
1831  t_forward = v_forward * tagscale;
1832  t_left = v_right * -tagscale;
1833  t_up = v_up * tagscale;
1834 
1835  e.origin_x = org * t_forward;
1836  e.origin_y = org * t_left;
1837  e.origin_z = org * t_up;
1838 
1839  // current forward and up directions
1840  if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
1841  e.angles = AnglesTransform_FromVAngles(e.angles);
1842  else
1843  e.angles = AnglesTransform_FromAngles(e.angles);
1844  fixedmakevectors(e.angles);
1845 
1846  // untransform forward, up!
1847  e_forward.x = v_forward * t_forward;
1848  e_forward.y = v_forward * t_left;
1849  e_forward.z = v_forward * t_up;
1850  e_up.x = v_up * t_forward;
1851  e_up.y = v_up * t_left;
1852  e_up.z = v_up * t_up;
1853 
1854  e.angles = fixedvectoangles2(e_forward, e_up);
1855  if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
1856  e.angles = AnglesTransform_ToVAngles(e.angles);
1857  else
1858  e.angles = AnglesTransform_ToAngles(e.angles);
1859 
1860  setattachment(e, to, tag);
1861  setorigin(e, e.origin);
1862 }
1863 
1864 void detach_sameorigin(entity e)
1865 {
1866  vector org;
1867  org = gettaginfo(e, 0);
1868  e.angles = fixedvectoangles2(v_forward, v_up);
1869  if (substring(e.model, 0, 1) == "*") // bmodels have their own rules
1870  e.angles = AnglesTransform_ToVAngles(e.angles);
1871  else
1872  e.angles = AnglesTransform_ToAngles(e.angles);
1873  setorigin(e, org);
1874  setattachment(e, NULL, "");
1875  setorigin(e, e.origin);
1876 }
1877 
1878 void follow_sameorigin(entity e, entity to)
1879 {
1880  set_movetype(e, MOVETYPE_FOLLOW); // make the hole follow
1881  e.aiment = to; // make the hole follow bmodel
1882  e.punchangle = to.angles; // the original angles of bmodel
1883  e.view_ofs = e.origin - to.origin; // relative origin
1884  e.v_angle = e.angles - to.angles; // relative angles
1885 }
1886 
1887 #if 0
1888 // TODO: unused, likely for a reason, possibly needs extensions (allow setting the new movetype as a parameter?)
1889 void unfollow_sameorigin(entity e)
1890 {
1892 }
1893 #endif
1894 
1895 .string aiment_classname;
1896 .float aiment_deadflag;
1897 void SetMovetypeFollow(entity ent, entity e)
1898 {
1899  // FIXME this may not be warpzone aware
1900  set_movetype(ent, MOVETYPE_FOLLOW); // make the hole follow
1901  ent.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid - this means this cannot be teleported by warpzones any more! Instead, we must notice when our owner gets teleported.
1902  ent.aiment = e; // make the hole follow bmodel
1903  ent.punchangle = e.angles; // the original angles of bmodel
1904  ent.view_ofs = ent.origin - e.origin; // relative origin
1905  ent.v_angle = ent.angles - e.angles; // relative angles
1906  ent.aiment_classname = strzone(e.classname);
1907  ent.aiment_deadflag = e.deadflag;
1908 
1909  if(IS_PLAYER(ent.aiment))
1910  {
1911  entity pl = ent.aiment;
1912  ent.view_ofs.x = bound(pl.mins.x + 4, ent.view_ofs.x, pl.maxs.x - 4);
1913  ent.view_ofs.y = bound(pl.mins.y + 4, ent.view_ofs.y, pl.maxs.y - 4);
1914  ent.view_ofs.z = bound(pl.mins.z + 4, ent.view_ofs.z, pl.maxs.z - 4);
1915  }
1916 }
1917 
1918 void UnsetMovetypeFollow(entity ent)
1919 {
1920  set_movetype(ent, MOVETYPE_FLY);
1922  if (ent.aiment_classname)
1923  strunzone(ent.classname);
1924  // FIXME: engine bug?
1925  // resetting aiment the engine will set orb's origin close to world's origin
1926  //ent.aiment = NULL;
1927 }
1928 
1929 int LostMovetypeFollow(entity ent)
1930 {
1931 /*
1932  if(ent.move_movetype != MOVETYPE_FOLLOW)
1933  if(ent.aiment)
1934  error("???");
1935 */
1936  // FIXME: engine bug?
1937  // when aiment disconnects the engine will set orb's origin close to world's origin
1938  if(!ent.aiment)
1939  return 2;
1940  if(ent.aiment.classname != ent.aiment_classname || ent.aiment.deadflag != ent.aiment_deadflag)
1941  return 1;
1942  return 0;
1943 }
1944 #endif
1945 
1946 #ifdef GAMEQC
1947 // decolorizes and team colors the player name when needed
1948 string playername(string thename, int teamid, bool team_colorize)
1949 {
1950  TC(int, teamid);
1951  bool do_colorize = (teamplay && team_colorize);
1952 #ifdef SVQC
1953  if(do_colorize && !intermission_running)
1954 #else
1955  if(do_colorize)
1956 #endif
1957  {
1958  string t = Team_ColorCode(teamid);
1959  return strcat(t, strdecolorize(thename));
1960  }
1961  else
1962  return thename;
1963 }
1964 
1965 float trace_hits_box_a0, trace_hits_box_a1;
1966 
1967 float trace_hits_box_1d(float end, float thmi, float thma)
1968 {
1969  if (end == 0)
1970  {
1971  // just check if x is in range
1972  if (0 < thmi)
1973  return false;
1974  if (0 > thma)
1975  return false;
1976  }
1977  else
1978  {
1979  // do the trace with respect to x
1980  // 0 -> end has to stay in thmi -> thma
1981  trace_hits_box_a0 = max(trace_hits_box_a0, min(thmi / end, thma / end));
1982  trace_hits_box_a1 = min(trace_hits_box_a1, max(thmi / end, thma / end));
1983  if (trace_hits_box_a0 > trace_hits_box_a1)
1984  return false;
1985  }
1986  return true;
1987 }
1988 
1989 float trace_hits_box(vector start, vector end, vector thmi, vector thma)
1990 {
1991  end -= start;
1992  thmi -= start;
1993  thma -= start;
1994  // now it is a trace from 0 to end
1995 
1996  trace_hits_box_a0 = 0;
1997  trace_hits_box_a1 = 1;
1998 
1999  if (!trace_hits_box_1d(end.x, thmi.x, thma.x))
2000  return false;
2001  if (!trace_hits_box_1d(end.y, thmi.y, thma.y))
2002  return false;
2003  if (!trace_hits_box_1d(end.z, thmi.z, thma.z))
2004  return false;
2005 
2006  return true;
2007 }
2008 
2009 float tracebox_hits_box(vector start, vector mi, vector ma, vector end, vector thmi, vector thma)
2010 {
2011  return trace_hits_box(start, end, thmi - ma, thma - mi);
2012 }
2013 #endif
2014 
2015 ERASEABLE
2016 float cvar_or(string cv, float v)
2017 {
2018  string s = cvar_string(cv);
2019  if(s == "")
2020  return v;
2021  else
2022  return stof(s);
2023 }
2024 
2025 // NOTE base is the central value
2026 // freq: circle frequency, = 2*pi*frequency in hertz
2027 // start_pos:
2028 // -1 start from the lower value
2029 // 0 start from the base value
2030 // 1 start from the higher value
2031 ERASEABLE
2032 float blink_synced(float base, float range, float freq, float start_time, int start_pos)
2033 {
2034  // note:
2035  // RMS = sqrt(base^2 + 0.5 * range^2)
2036  // thus
2037  // base = sqrt(RMS^2 - 0.5 * range^2)
2038  // ensure RMS == 1
2039 
2040  return base + range * sin((time - start_time - (M_PI / 2) * start_pos) * freq);
2041 }
2042 
2043 ERASEABLE
2044 float blink(float base, float range, float freq)
2045 {
2046  return blink_synced(base, range, freq, 0, 0);
2047 }
const float SOLID_NOT
Definition: csprogsdefs.qc:244
float get_model_parameters_weight
Definition: util.qh:142
string MapInfo_Type_ToString(Gametype t)
Definition: mapinfo.qc:616
string get_model_datafilename(string m, float sk, string fil)
Definition: util.qc:1245
#define IL_EACH(this, cond, body)
float MOVETYPE_NONE
Definition: progsdefs.qc:246
string get_model_parameters_desc
Definition: util.qh:152
vector AnglesTransform_ToAngles(vector v)
const int SPECIES_ALIEN
Definition: constants.qh:22
#define stob(s)
Definition: int.qh:5
vector AnglesTransform_ToVAngles(vector v)
string string_null
Definition: nil.qh:9
const float CONTENT_LAVA
Definition: csprogsdefs.qc:240
float compressShortVector(vector vec)
Definition: util.qc:406
entity world
Definition: csprogsdefs.qc:15
const int SPECIES_HUMAN
Definition: constants.qh:20
string find_last_color_code(string s)
Definition: util.qc:845
ERASEABLE vector solve_quadratic(float a, float b, float c)
ax^2 + bx + c = 0
Definition: math.qh:307
vector AnglesTransform_FromAngles(vector v)
#define PROJECTILE_MAKETRIGGER(e)
Definition: common.qh:29
string getWrappedLine_remaining
Definition: util.qh:108
ERASEABLE float blink(float base, float range, float freq)
Definition: util.qc:2044
const int SPECIES_ROBOT_RUSTY
Definition: constants.qh:24
float FindConnectedComponent_processing
Definition: util.qc:1629
float get_model_parameters(string m, float sk)
Definition: util.qc:1258
float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w)
Definition: util.qc:773
vector MapInfo_Map_maxs
Definition: mapinfo.qh:17
const int MAX_AIM_BONES
Definition: util.qh:148
void wordwrap_buffer_put(string s)
Definition: util.qc:165
#define shutdownhooks()
Definition: static.qh:50
STATIC_INIT(compressShortVector)
Definition: util.qc:438
float cvar_settemp(string tmp_cvar, string tmp_value)
Definition: util.qc:696
const int SPECIES_ANIMAL
Definition: constants.qh:23
const int SFL_HIDE_ZERO
Don&#39;t show zero values as scores.
Definition: scores.qh:103
float(entity a, entity b, entity pass) isConnectedFunction_t
Definition: util.qh:184
string draw_currentSkin
Definition: util.qh:45
string get_model_parameters_description
Definition: util.qh:145
entity(entity cur, entity near, entity pass) findNextEntityNearFunction_t
Definition: util.qh:183
entity() spawn
#define REGISTRY_GET(id, i)
Definition: registry.qh:43
ERASEABLE float cvar_or(string cv, float v)
Definition: util.qc:2016
void depthfirst(entity start,.entity up,.entity downleft,.entity right, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
Definition: util.qc:281
float shutdown_running
Definition: util.qc:1571
ERASEABLE string cdr(string s)
returns all but first word
Definition: string.qh:249
float DPCONTENTS_SKY
const float CONTENT_SOLID
Definition: csprogsdefs.qc:237
void FindConnectedComponent(entity e,.entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass)
Definition: util.qc:1630
string getWrappedLineLen(float w, textLengthUpToLength_lenFunction_t tw)
Definition: util.qc:918
const float FILE_READ
Definition: csprogsdefs.qc:231
string textShortenToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t tw)
Definition: util.qc:964
string textShortenToWidth(string theText, float maxWidth, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
Definition: util.qc:956
entity to
Definition: self.qh:96
#define gettaginfo
Definition: post.qh:32
string classname
Definition: csprogsdefs.qc:107
float get_model_parameters_fixbone
Definition: util.qh:151
#define ERASEABLE
Definition: _all.inc:35
ERASEABLE string car(string s)
returns first word
Definition: string.qh:240
float matchacl(string acl, string str)
Definition: util.qc:1203
string mapPriorityList(string order, string(string) mapfunc)
Definition: util.qc:527
#define TIME_ENCODED_TOSTRING(n)
Definition: util.qh:57
const int SFL_RANK
Display as a rank (with st, nd, rd, th suffix)
Definition: scores.qh:113
#define LOG_HELP(...)
Definition: log.qh:95
vector decompressShotOrigin(int f)
Definition: util.qc:1143
#define gettagindex
Definition: dpextensions.qh:16
entity trace_ent
Definition: csprogsdefs.qc:40
string draw_UseSkinFor(string pic)
Definition: util.qc:206
float compressShotOrigin(vector v)
Definition: util.qc:1121
const string XENCODE_22
Definition: util.qc:1530
#define strcpy(this, s)
Definition: string.qh:49
string get_model_parameters_sex
Definition: util.qh:141
float(string s, vector size) textLengthUpToWidth_widthFunction_t
Definition: util.qh:101
string mapname
Definition: csprogsdefs.qc:26
float xdecode(string s)
Definition: util.qc:1546
ERASEABLE string count_ordinal(int interval)
Definition: counting.qh:66
const float CONTENT_EMPTY
Definition: csprogsdefs.qc:236
#define FOREACH_ENTITY_CLASS(class, cond, body)
Definition: iter.qh:189
float get_model_parameters_age
Definition: util.qh:143
float get_model_parameters_modelskin
Definition: util.qh:138
const int HITTYPE_ARMORPIERCE
Definition: all.qh:29
ERASEABLE void write_String_To_File(int fh, string str, bool alsoprint)
Definition: util.qc:1239
float invertLengthLog(float dist)
Definition: util.qc:343
float lengthLogTable[128]
Definition: util.qc:341
const string XENCODE_2
Definition: util.qc:1529
float get_model_parameters_species
Definition: util.qh:140
float textLengthUpToLength(string theText, float maxWidth, textLengthUpToLength_lenFunction_t w)
Definition: util.qc:809
string get_model_parameters_modelname
Definition: util.qh:137
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
const float CONTENT_SLIME
Definition: csprogsdefs.qc:239
string getcurrentmod()
Definition: util.qc:1191
#define LOG_INFOF(...)
Definition: log.qh:71
vector v_up
Definition: csprogsdefs.qc:31
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
string get_model_parameters_bone_aim[MAX_AIM_BONES]
Definition: util.qh:149
const float CONTENT_WATER
Definition: csprogsdefs.qc:238
const float CONTENT_SKY
Definition: csprogsdefs.qc:241
vector MapInfo_Map_mins
Definition: mapinfo.qh:16
int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
Definition: mapinfo.qc:1067
#define NULL
Definition: post.qh:17
#define LOG_INFO(...)
Definition: log.qh:70
float isGametypeInFilter(Gametype gt, float tp, float ts, string pattern)
Definition: util.qc:972
float DPCONTENTS_SOLID
#define TC(T, sym)
Definition: _all.inc:82
vector trace_endpos
Definition: csprogsdefs.qc:37
#define strstrofs
Definition: dpextensions.qh:42
string fixPriorityList(string order, float from, float to, float subtract, float complete)
Definition: util.qc:485
string to_execute_next_frame
Definition: util.qc:1581
string swapInPriorityList(string order, float i, float j)
Definition: util.qc:540
float teamplay
Definition: progsdefs.qc:31
#define IS_DIGIT(d)
Definition: string.qh:507
float DPCONTENTS_WATER
const int SPECIES_ROBOT_SHINY
Definition: constants.qh:25
vector decompressShortVector(int data)
Definition: util.qc:372
ERASEABLE float blink_synced(float base, float range, float freq, float start_time, int start_pos)
Definition: util.qc:2032
#define DEATH_IS(t, dt)
Definition: all.qh:36
string get_model_parameters_bone_weapon
Definition: util.qh:147
vector AnglesTransform_FromVAngles(vector v)
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define tokenize_console
Definition: dpextensions.qh:24
string get_model_parameters_bone_upperbody
Definition: util.qh:146
float DPCONTENTS_OPAQUE
const float M_PI
Definition: csprogsdefs.qc:269
const int SPECIES_RESERVED
Definition: constants.qh:26
#define IS_HEXDIGIT(d)
Definition: string.qh:504
vector solve_shotdirection(vector myorg, vector myvel, vector eorg, vector evel, float spd, float newton_style)
Definition: util.qc:1018
string wordwrap(string s, float l)
Definition: util.qc:170
string Team_ColorCode(int teamid)
Definition: teams.qh:63
vector v
Definition: ent_cs.qc:116
string prvm_language
Definition: i18n.qh:8
float DPCONTENTS_BODY
const int WEP_FLAG_SPECIALATTACK
Definition: weapon.qh:211
float MOVETYPE_FOLLOW
#define LOG_TRACE(...)
Definition: log.qh:81
entity Notification
always last
Definition: all.qh:82
ERASEABLE vector checkColorCode(string theText, int text_len, int pos, bool check_at_the_end)
Definition: string.qh:540
const int SPECIES_ROBOT_SOLID
Definition: constants.qh:21
vector v_right
Definition: csprogsdefs.qc:31
#define LOG_FATALF(...)
Definition: log.qh:59
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
float DPCONTENTS_NODROP
#define new_pure(class)
purely logical entities (.origin doesn&#39;t work)
Definition: oo.qh:62
setorigin(ent, v)
float DPCONTENTS_SLIME
IntrusiveList g_saved_cvars
Definition: util.qh:33
bool intermission_running
Definition: intermission.qh:9
float(string s) textLengthUpToLength_lenFunction_t
Definition: util.qh:102
#define strfree(this)
Definition: string.qh:56
bool get_model_parameters_hidden
Definition: util.qh:144
void execute_next_frame()
Definition: util.qc:1612
float get_model_parameters_bone_aimweight[MAX_AIM_BONES]
Definition: util.qh:150
float trace_startsolid
Definition: csprogsdefs.qc:35
int cvar_settemp_restore()
Definition: util.qc:736
float MOVE_WORLDONLY
string getWrappedLine(float w, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
Definition: util.qc:880
float time
Definition: csprogsdefs.qc:16
#define strcasecmp
Definition: dpextensions.qh:57
#define pass(name, colormin, colormax)
string translate_key(string key)
Definition: util.qc:1376
int dir
Definition: impulse.qc:89
float trace_fraction
Definition: csprogsdefs.qc:36
vector get_shotvelocity(vector myvel, vector mydir, float spd, float newton_style, float mi, float ma)
Definition: util.qc:1081
const int SFL_TIME
Display as mm:ss.s, value is stored as 10ths of a second (AND 0 is the worst possible value!) ...
Definition: scores.qh:118
#define fixedmakevectors
void set_movetype(entity this, int mt)
float MOVETYPE_FLY
Definition: progsdefs.qc:251
#define IS_PLAYER(v)
Definition: utils.qh:9
#define fixedvectoangles2(a, b)
string xencode(int f)
Definition: util.qc:1531
string wordwrap_buffer
Definition: util.qc:163
void wordwrap_cb(string s, float l, void(string) callback)
Definition: util.qc:215
void queue_to_execute_next_frame(string s)
Definition: util.qc:1620
#define LOG_DEBUG(...)
Definition: log.qh:85
string get_model_parameters_name
Definition: util.qh:139
vector v_forward
Definition: csprogsdefs.qc:31
float DPCONTENTS_LAVA
void Shutdown()
Definition: main.qc:152