Xonotic
chat.qc
Go to the documentation of this file.
1 #include "chat.qh"
2 
6 #include <common/teams.qh>
7 #include <common/util.qh>
9 #include <common/wepent.qh>
10 #include <server/command/common.qh>
11 #include <server/gamelog.qh>
12 #include <server/main.qh>
13 #include <server/mapvoting.qh>
14 #include <server/mutators/_mod.qh>
16 #include <server/world.qh>
17 
25 int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
26 {
27  if (!teamsay && !privatesay && substring(msgin, 0, 1) == " ")
28  msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
29 
30  if (source)
31  msgin = formatmessage(source, msgin);
32 
33  string colorstr;
34  if (!(IS_PLAYER(source) || INGAME(source)))
35  colorstr = "^0"; // black for spectators
36  else if(teamplay)
37  colorstr = Team_ColorCode(source.team);
38  else
39  {
40  colorstr = "";
41  teamsay = false;
42  }
43 
44  if (!source) {
45  colorstr = "";
46  teamsay = false;
47  }
48 
49  if(msgin != "")
50  msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin);
51 
52  /*
53  * using bprint solves this... me stupid
54  // how can we prevent the message from appearing in a listen server?
55  // for now, just give "say" back and only handle say_team
56  if(!teamsay)
57  {
58  clientcommand(source, strcat("say ", msgin));
59  return;
60  }
61  */
62 
63  string namestr = "";
64  if (source)
65  namestr = playername(source.netname, source.team, (autocvar_g_chat_teamcolors && IS_PLAYER(source)));
66 
67  string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
68 
69  string msgstr = "", cmsgstr = "";
70  string privatemsgprefix = string_null;
71  int privatemsgprefixlen = 0;
72  if (msgin != "")
73  {
74  bool found_me = false;
75  if(strstrofs(msgin, "/me", 0) >= 0)
76  {
77  string newmsgin = "";
78  string newnamestr = ((teamsay) ? strcat(colorstr, "(", colorprefix, namestr, colorstr, ")", "^7") : strcat(colorprefix, namestr, "^7"));
79  FOREACH_WORD(msgin, true,
80  {
81  if(strdecolorize(it) == "/me")
82  {
83  found_me = true;
84  newmsgin = cons(newmsgin, newnamestr);
85  }
86  else
87  newmsgin = cons(newmsgin, it);
88  });
89  msgin = newmsgin;
90  }
91 
92  if(privatesay)
93  {
94  msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7");
95  privatemsgprefixlen = strlen(msgstr);
96  msgstr = strcat(msgstr, msgin);
97  cmsgstr = strcat(colorstr, colorprefix, namestr, "^3 tells you:\n^7", msgin);
98  privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", playername(privatesay.netname, privatesay.team, (autocvar_g_chat_teamcolors && IS_PLAYER(privatesay))), ": ^7");
99  }
100  else if(teamsay)
101  {
102  if(found_me)
103  {
104  //msgin = strreplace("/me", "", msgin);
105  //msgin = substring(msgin, 3, strlen(msgin));
106  //msgin = strreplace("/me", strcat(colorstr, "(", colorprefix, namestr, colorstr, ")^7"), msgin);
107  msgstr = strcat("\{1}\{13}^4* ", "^7", msgin);
108  }
109  else
110  msgstr = strcat("\{1}\{13}", colorstr, "(", colorprefix, namestr, colorstr, ") ^7", msgin);
111  cmsgstr = strcat(colorstr, "(", colorprefix, namestr, colorstr, ")\n^7", msgin);
112  }
113  else
114  {
115  if(found_me)
116  {
117  //msgin = strreplace("/me", "", msgin);
118  //msgin = substring(msgin, 3, strlen(msgin));
119  //msgin = strreplace("/me", strcat(colorprefix, namestr), msgin);
120  msgstr = strcat("\{1}^4* ^7", msgin);
121  }
122  else {
123  msgstr = "\{1}";
124  msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
125  msgstr = strcat(msgstr, msgin);
126  }
127  cmsgstr = "";
128  }
129  msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint
130  }
131 
132  string fullmsgstr = msgstr;
133  string fullcmsgstr = cmsgstr;
134 
135  // FLOOD CONTROL
136  int flood = 0;
137  var .float flood_field = floodcontrol_chat;
138  if(floodcontrol && source)
139  {
140  float flood_spl, flood_burst, flood_lmax;
141  if(privatesay)
142  {
143  flood_spl = autocvar_g_chat_flood_spl_tell;
144  flood_burst = autocvar_g_chat_flood_burst_tell;
145  flood_lmax = autocvar_g_chat_flood_lmax_tell;
146  flood_field = floodcontrol_chattell;
147  }
148  else if(teamsay)
149  {
150  flood_spl = autocvar_g_chat_flood_spl_team;
151  flood_burst = autocvar_g_chat_flood_burst_team;
152  flood_lmax = autocvar_g_chat_flood_lmax_team;
153  flood_field = floodcontrol_chatteam;
154  }
155  else
156  {
157  flood_spl = autocvar_g_chat_flood_spl;
158  flood_burst = autocvar_g_chat_flood_burst;
159  flood_lmax = autocvar_g_chat_flood_lmax;
160  flood_field = floodcontrol_chat;
161  }
162  flood_burst = max(0, flood_burst - 1);
163  // to match explanation in default.cfg, a value of 3 must allow three-line bursts and not four!
164 
165  // do flood control for the default line size
166  if(msgstr != "")
167  {
168  getWrappedLine_remaining = msgstr;
169  msgstr = "";
170  int lines = 0;
171  while(getWrappedLine_remaining && (!flood_lmax || lines <= flood_lmax))
172  {
173  msgstr = strcat(msgstr, " ", getWrappedLineLen(82.4289758859709, strlennocol)); // perl averagewidth.pl < gfx/vera-sans.width
174  ++lines;
175  }
176  msgstr = substring(msgstr, 1, strlen(msgstr) - 1);
177 
178  if(getWrappedLine_remaining != "")
179  {
180  msgstr = strcat(msgstr, "\n");
181  flood = 2;
182  }
183 
184  if (time >= source.(flood_field))
185  {
186  source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + lines * flood_spl;
187  }
188  else
189  {
190  flood = 1;
191  msgstr = fullmsgstr;
192  }
193  }
194  else
195  {
196  if (time >= source.(flood_field))
197  source.(flood_field) = max(time - flood_burst * flood_spl, source.(flood_field)) + flood_spl;
198  else
199  flood = 1;
200  }
201 
202  if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
203  source.(flood_field) = flood = 0;
204  }
205 
206  string sourcemsgstr, sourcecmsgstr;
207  if(flood == 2) // cannot happen for empty msgstr
208  {
210  {
211  sourcemsgstr = strcat(msgstr, "\n^3FLOOD CONTROL: ^7message too long, trimmed\n");
212  sourcecmsgstr = "";
213  }
214  else
215  {
216  sourcemsgstr = fullmsgstr;
217  sourcecmsgstr = fullcmsgstr;
218  }
219  cmsgstr = "";
220  }
221  else
222  {
223  sourcemsgstr = msgstr;
224  sourcecmsgstr = cmsgstr;
225  }
226 
227  if (!privatesay && source && !(IS_PLAYER(source) || INGAME(source)) && !game_stopped
228  && (teamsay || CHAT_NOSPECTATORS()))
229  {
230  teamsay = -1; // spectators
231  }
232 
233  if(flood)
234  LOG_INFO("NOTE: ", playername(source.netname, source.team, IS_PLAYER(source)), "^7 is flooding.");
235 
236  // build sourcemsgstr by cutting off a prefix and replacing it by the other one
237  if(privatesay)
238  sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1));
239 
240  int ret;
241  if(source && CS(source).muted)
242  {
243  // always fake the message
244  ret = -1;
245  }
246  else if(flood == 1)
247  {
249  {
250  sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.(flood_field) - time), "^3 seconds\n"));
251  ret = 0;
252  }
253  else
254  ret = -1;
255  }
256  else
257  {
258  ret = 1;
259  }
260 
261  if (privatesay && source && !(IS_PLAYER(source) || INGAME(source)) && !game_stopped
262  && (IS_PLAYER(privatesay) || INGAME(privatesay)) && CHAT_NOSPECTATORS())
263  {
264  ret = -1; // just hide the message completely
265  }
266 
267  MUTATOR_CALLHOOK(ChatMessage, source, ret);
268  ret = M_ARGV(1, int);
269 
270  string event_log_msg = "";
271 
272  if(sourcemsgstr != "" && ret != 0)
273  {
274  if(ret < 0) // faked message, because the player is muted
275  {
276  sprint(source, sourcemsgstr);
277  if(sourcecmsgstr != "" && !privatesay)
278  centerprint(source, sourcecmsgstr);
279  }
280  else if(privatesay) // private message, between 2 people only
281  {
282  sprint(source, sourcemsgstr);
283  if (!autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled
284  if(!MUTATOR_CALLHOOK(ChatMessageTo, privatesay, source))
285  {
286  sprint(privatesay, msgstr);
287  if(cmsgstr != "")
288  centerprint(privatesay, cmsgstr);
289  }
290  }
291  else if ( teamsay && CS(source).active_minigame )
292  {
293  sprint(source, sourcemsgstr);
294  dedicated_print(msgstr); // send to server console too
295  FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && CS(it).active_minigame == CS(source).active_minigame && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
296  sprint(it, msgstr);
297  });
298  event_log_msg = sprintf(":chat_minigame:%d:%s:%s", source.playerid, CS(source).active_minigame.netname, msgin);
299 
300  }
301  else if(teamsay > 0) // team message, only sent to team mates
302  {
303  sprint(source, sourcemsgstr);
304  dedicated_print(msgstr); // send to server console too
305  if(sourcecmsgstr != "")
306  centerprint(source, sourcecmsgstr);
307  FOREACH_CLIENT((IS_PLAYER(it) || INGAME(it)) && IS_REAL_CLIENT(it) && it != source && it.team == source.team && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
308  sprint(it, msgstr);
309  if(cmsgstr != "")
310  centerprint(it, cmsgstr);
311  });
312  event_log_msg = sprintf(":chat_team:%d:%d:%s", source.playerid, source.team, strreplace("\n", " ", msgin));
313  }
314  else if(teamsay < 0) // spectator message, only sent to spectators
315  {
316  sprint(source, sourcemsgstr);
317  dedicated_print(msgstr); // send to server console too
318  FOREACH_CLIENT(!(IS_PLAYER(it) || INGAME(it)) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
319  sprint(it, msgstr);
320  });
321  event_log_msg = sprintf(":chat_spec:%d:%s", source.playerid, strreplace("\n", " ", msgin));
322  }
323  else
324  {
325  if (source) {
326  sprint(source, sourcemsgstr);
327  dedicated_print(msgstr); // send to server console too
328  MX_Say(strcat(playername(source.netname, source.team, IS_PLAYER(source)), "^7: ", msgin));
329  }
330  FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
331  sprint(it, msgstr);
332  });
333  event_log_msg = sprintf(":chat:%d:%s", source.playerid, strreplace("\n", " ", msgin));
334  }
335  }
336 
337  if (autocvar_sv_eventlog && (event_log_msg != "")) {
338  GameLogEcho(event_log_msg);
339  }
340 
341  return ret;
342 }
343 
344 entity findnearest(vector point, bool checkitems, vector axismod)
345 {
346  vector dist;
347  int num_nearest = 0;
348 
349  IL_EACH(((checkitems) ? g_items : g_locations), ((checkitems) ? (it.target == "###item###") : (it.classname == "target_location")),
350  {
351  if ((it.items == IT_KEY1 || it.items == IT_KEY2) && it.target == "###item###")
352  dist = it.oldorigin;
353  else
354  dist = it.origin;
355  dist = dist - point;
356  dist = dist.x * axismod.x * '1 0 0' + dist.y * axismod.y * '0 1 0' + dist.z * axismod.z * '0 0 1';
357  float len = vlen2(dist);
358 
359  int l;
360  for (l = 0; l < num_nearest; ++l)
361  {
362  if (len < nearest_length[l])
363  break;
364  }
365 
366  // now i tells us where to insert at
367  // INSERTION SORT! YOU'VE SEEN IT! RUN!
369  {
370  for (int j = NUM_NEAREST_ENTITIES - 1; j >= l; --j)
371  {
372  nearest_length[j + 1] = nearest_length[j];
373  nearest_entity[j + 1] = nearest_entity[j];
374  }
375  nearest_length[l] = len;
376  nearest_entity[l] = it;
377  if (num_nearest < NUM_NEAREST_ENTITIES)
378  num_nearest = num_nearest + 1;
379  }
380  });
381 
382  // now use the first one from our list that we can see
383  for (int j = 0; j < num_nearest; ++j)
384  {
385  traceline(point, nearest_entity[j].origin, true, NULL);
386  if (trace_fraction == 1)
387  {
388  if (j != 0)
389  LOG_TRACEF("Nearest point (%s) is not visible, using a visible one.", nearest_entity[0].netname);
390  return nearest_entity[j];
391  }
392  }
393 
394  if (num_nearest == 0)
395  return NULL;
396 
397  LOG_TRACE("Not seeing any location point, using nearest as fallback.");
398  /* DEBUGGING CODE:
399  dprint("Candidates were: ");
400  for(j = 0; j < num_nearest; ++j)
401  {
402  if(j != 0)
403  dprint(", ");
404  dprint(nearest_entity[j].netname);
405  }
406  dprint("\n");
407  */
408 
409  return nearest_entity[0];
410 }
411 
413 {
414  string ret = "somewhere";
415  entity loc = findnearest(p, false, '1 1 1');
416  if (loc)
417  ret = loc.message;
418  else
419  {
420  loc = findnearest(p, true, '1 1 4');
421  if (loc)
422  ret = loc.netname;
423  }
424  return ret;
425 }
426 
427 string PlayerHealth(entity this)
428 {
429  float myhealth = floor(GetResource(this, RES_HEALTH));
430  if(myhealth == -666)
431  return "spectating";
432  else if(myhealth == -2342 || (myhealth == 2342 && mapvote_initialized))
433  return "observing";
434  else if(myhealth <= 0 || IS_DEAD(this))
435  return "dead";
436  return ftos(myhealth);
437 }
438 
439 string WeaponNameFromWeaponentity(entity this, .entity weaponentity)
440 {
441  entity wepent = this.(weaponentity);
442  if(!wepent)
443  return "none";
444  else if(wepent.m_weapon != WEP_Null)
445  return wepent.m_weapon.m_name;
446  else if(wepent.m_switchweapon != WEP_Null)
447  return wepent.m_switchweapon.m_name;
448  return "none"; //REGISTRY_GET(Weapons, wepent.cnt).m_name;
449 }
450 
451 string formatmessage(entity this, string msg)
452 {
453  float p, p1, p2;
454  float n;
455  vector cursor = '0 0 0';
456  entity cursor_ent = NULL;
457  string escape;
458  string replacement;
459  p = 0;
460  n = 7;
461  bool traced = false;
462 
463  MUTATOR_CALLHOOK(PreFormatMessage, this, msg);
464  msg = M_ARGV(1, string);
465 
466  while (1) {
467  if (n < 1)
468  break; // too many replacements
469 
470  n = n - 1;
471  p1 = strstrofs(msg, "%", p); // NOTE: this destroys msg as it's a tempstring!
472  p2 = strstrofs(msg, "\\", p); // NOTE: this destroys msg as it's a tempstring!
473 
474  if (p1 < 0)
475  p1 = p2;
476 
477  if (p2 < 0)
478  p2 = p1;
479 
480  p = min(p1, p2);
481 
482  if (p < 0)
483  break;
484 
485  if(!traced)
486  {
488  cursor = trace_endpos;
489  cursor_ent = trace_ent;
490  traced = true;
491  }
492 
493  replacement = substring(msg, p, 2);
494  escape = substring(msg, p + 1, 1);
495 
496  .entity weaponentity = weaponentities[0]; // TODO: unhardcode
497 
498  switch(escape)
499  {
500  case "%": replacement = "%"; break;
501  case "\\":replacement = "\\"; break;
502  case "n": replacement = "\n"; break;
503  case "a": replacement = ftos(floor(GetResource(this, RES_ARMOR))); break;
504  case "h": replacement = PlayerHealth(this); break;
505  case "l": replacement = NearestLocation(this.origin); break;
506  case "y": replacement = NearestLocation(cursor); break;
507  case "d": replacement = NearestLocation(this.death_origin); break;
508  case "w": replacement = WeaponNameFromWeaponentity(this, weaponentity); break;
509  case "W": replacement = GetAmmoName(this.(weaponentity).m_weapon.ammo_type); break;
510  case "x": replacement = ((cursor_ent.netname == "" || !cursor_ent) ? "nothing" : cursor_ent.netname); break;
511  case "s": replacement = ftos(vlen(this.velocity - this.velocity_z * '0 0 1')); break;
512  case "S": replacement = ftos(vlen(this.velocity)); break;
513  case "t": replacement = seconds_tostring(ceil(max(0, autocvar_timelimit * 60 + game_starttime - time))); break;
514  case "T": replacement = seconds_tostring(floor(time - game_starttime)); break;
515  default:
516  {
517  MUTATOR_CALLHOOK(FormatMessage, this, escape, replacement, msg);
518  replacement = M_ARGV(2, string);
519  break;
520  }
521  }
522 
523  msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
524  p = p + strlen(replacement);
525  }
526  return msg;
527 }
528 
529 ERASEABLE
530 void PrintToChat(entity client, string text)
531 {
532  text = strcat("\{1}^7", text, "\n");
533  sprint(client, text);
534 }
535 
536 ERASEABLE
537 void DebugPrintToChat(entity client, string text)
538 {
539  if (autocvar_developer > 0)
540  {
541  PrintToChat(client, text);
542  }
543 }
544 
545 ERASEABLE
546 void PrintToChatAll(string text)
547 {
548  text = strcat("\{1}^7", text, "\n");
549  bprint(text);
550 }
551 
552 ERASEABLE
553 void DebugPrintToChatAll(string text)
554 {
555  if (autocvar_developer > 0)
556  {
557  PrintToChatAll(text);
558  }
559 }
560 
561 ERASEABLE
562 void PrintToChatTeam(int team_num, string text)
563 {
564  text = strcat("\{1}^7", text, "\n");
566  {
567  if (it.team == team_num)
568  {
569  sprint(it, text);
570  }
571  });
572 }
573 
574 ERASEABLE
575 void DebugPrintToChatTeam(int team_num, string text)
576 {
577  if (autocvar_developer > 0)
578  {
579  PrintToChatTeam(team_num, text);
580  }
581 }
#define INGAME(it)
Definition: sv_rules.qh:20
void dedicated_print(string input)
print(), but only print if the server is not local
Definition: main.qc:205
#define IL_EACH(this, cond, body)
float nearest_length[NUM_NEAREST_ENTITIES]
Definition: chat.qh:19
float autocvar_g_chat_flood_spl_team
Definition: chat.qh:11
string string_null
Definition: nil.qh:9
string PlayerHealth(entity this)
Definition: chat.qc:427
string getWrappedLine_remaining
Definition: util.qh:108
float autocvar_g_chat_flood_lmax_team
Definition: chat.qh:7
int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
message "": do not say, just test flood control return value: 1 = accept 0 = reject -1 = fake accept ...
Definition: chat.qc:25
entity() spawn
string GetAmmoName(Resource ammotype)
Definition: all.qc:220
ClientState CS(Client this)
Definition: state.qh:47
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
string getWrappedLineLen(float w, textLengthUpToLength_lenFunction_t tw)
Definition: util.qc:918
string netname
Definition: powerups.qc:20
float floodcontrol_chatteam
Definition: chat.qh:22
float autocvar_g_chat_flood_lmax_tell
Definition: chat.qh:8
bool autocvar_g_chat_flood_notify_flooder
Definition: chat.qh:9
origin
Definition: ent_cs.qc:114
bool autocvar_g_chat_teamcolors
Definition: chat.qh:14
const float TIMEOUT_ACTIVE
Definition: common.qh:49
#define ERASEABLE
Definition: _all.inc:35
ERASEABLE void DebugPrintToChatAll(string text)
Prints the string to all clients&#39; chat if the server cvar "developer" is not 0.
Definition: chat.qc:553
#define FOREACH_WORD(words, cond, body)
Definition: iter.qh:33
#define IS_REAL_CLIENT(v)
Definition: utils.qh:17
entity trace_ent
Definition: csprogsdefs.qc:40
entity nearest_entity[NUM_NEAREST_ENTITIES]
Definition: chat.qh:18
RES_HEALTH
Definition: ent_cs.qc:126
#define CHAT_NOSPECTATORS()
Definition: chat.qh:27
float autocvar_g_chat_flood_burst_team
Definition: chat.qh:4
entity active_minigame
Definition: cl_minigames.qh:85
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"))
IntrusiveList g_items
Definition: items.qh:126
bool autocvar_g_chat_tellprivacy
Definition: chat.qh:15
float autocvar_g_chat_flood_burst
Definition: chat.qh:3
void MX_Say(string body)
Definition: matrix.qc:187
#define NULL
Definition: post.qh:17
#define LOG_INFO(...)
Definition: log.qh:70
float autocvar_g_chat_flood_spl_tell
Definition: chat.qh:12
entity findnearest(vector point, bool checkitems, vector axismod)
Definition: chat.qc:344
#define LOG_TRACEF(...)
Definition: log.qh:82
vector trace_endpos
Definition: csprogsdefs.qc:37
#define strstrofs
Definition: dpextensions.qh:42
string NearestLocation(vector p)
Definition: chat.qc:412
void GameLogEcho(string s)
Definition: gamelog.qc:12
ERASEABLE void DebugPrintToChat(entity client, string text)
Print the string to the client&#39;s chat if the server cvar "developer" is not 0.
Definition: chat.qc:537
ERASEABLE void PrintToChatTeam(int team_num, string text)
Print the string to chat of all clients of the specified team.
Definition: chat.qc:562
float teamplay
Definition: progsdefs.qc:31
#define M_ARGV(x, type)
Definition: events.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
float floodcontrol_chat
Definition: chat.qh:21
const float NUM_NEAREST_ENTITIES
Definition: chat.qh:17
vector(float skel, float bonenum) _skel_get_boneabs_hidden
vector death_origin
Definition: damage.qh:70
string Team_ColorCode(int teamid)
Definition: teams.qh:63
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
#define LOG_TRACE(...)
Definition: log.qh:81
float myhealth
Definition: view.qc:577
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
ERASEABLE void PrintToChat(entity client, string text)
Print the string to the client&#39;s chat.
Definition: chat.qc:530
entity weaponentities[MAX_WEAPONSLOTS]
Definition: weapon.qh:14
float mapvote_initialized
Definition: mapvoting.qh:39
noref int autocvar_developer
Definition: log.qh:102
float autocvar_g_chat_flood_spl
Definition: chat.qh:10
ERASEABLE string cons(string a, string b)
Definition: string.qh:257
bool autocvar_sv_eventlog
Definition: gamelog.qh:3
if(IS_DEAD(this))
Definition: impulse.qc:92
void WarpZone_crosshair_trace_plusvisibletriggers(entity pl)
Definition: tracing.qc:518
float autocvar_g_chat_flood_lmax
Definition: chat.qh:6
string formatmessage(entity this, string msg)
Definition: chat.qc:451
float time
Definition: csprogsdefs.qc:16
vector velocity
Definition: csprogsdefs.qc:103
float trace_fraction
Definition: csprogsdefs.qc:36
#define IS_PLAYER(v)
Definition: utils.qh:9
ERASEABLE void PrintToChatAll(string text)
Prints the string to all clients&#39; chat.
Definition: chat.qc:546
ERASEABLE void DebugPrintToChatTeam(int team_num, string text)
Print the string to chat of all clients of the specified team if the server cvar "developer" is not 0...
Definition: chat.qc:575
float autocvar_g_chat_flood_burst_tell
Definition: chat.qh:5
string WeaponNameFromWeaponentity(entity this,.entity weaponentity)
Definition: chat.qc:439
ERASEABLE string seconds_tostring(float seconds)
Definition: string.qh:123
float floodcontrol_chattell
Definition: chat.qh:23