]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/notifications.qc
Move this macro inside the function (no need for larger scope)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / notifications.qc
1 // ================================================
2 //  Unified notification system, written by Samual
3 //  Last updated: September, 2012
4 // ================================================
5
6 // main types/groups of notifications
7 #define MSG_INFO 1 // "Global" information messages (sent to console, and notify panel if it has an icon)
8 #define MSG_CENTER 2 // "Personal" centerprint messages
9 #define MSG_WEAPON 3 // "Personal" weapon messages (like "You got the Nex", sent to weapon notify panel)
10
11 #define NO_STR_ARG ""
12 #define NO_FL_ARG -12345
13
14 #define F_NAME 1
15 #define F_STRNUM 2
16 #define F_FLNUM 3
17
18 // allow sending of notifications to also pass through to spectators (specifically for centerprints)
19 #ifdef SVQC
20 #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
21 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
22 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
23 #endif
24
25 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
26 #define NOTIF_MATCH(a,b) if(min(NOTIF_MAX, a) == b)
27
28
29 // ====================================
30 //  Notifications List and Information
31 // ====================================
32 /*
33  List of all notifications (including identifiers and display information)
34  Format: name, strnum, flnum, args, *icon/CPID, *durcnt, normal, gentle
35  Asterisked fields are not present in all notification types.
36  Specifications:
37     Name of notification
38     Number of STRING arguments (so that networking knows how many to send/receive)
39     Number of FLOAT arguments (so that networking knows how many to send/receive)
40     Arguments for sprintf(string, args), if no args needed then use ""
41     *Icon/CPID:
42       MSG_INFO: STRING: icon string name for the hud notify panel, "" if no icon is used
43       MSG_CENTER: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
44     *Duration/Countdown:
45       MSG_CENTER: XPND2(FLOAT, FLOAT): extra arguments for centerprint messages
46     Normal message (string for sprintf when gentle messages are NOT enabled)
47     Gentle message (string for sprintf when gentle messages ARE enabled)
48
49  Messages have ^F1, ^F2, and ^BG in them-- these are replaced
50  with colors according to the cvars the user has chosen.
51     ^F1 = highest priority, "primary"
52     ^F2 = next highest priority, "secondary"
53     ^BG = normal/less important priority, "tertiary"
54
55  Guidlines (please try and follow these):
56     ALWAYS start the string with a color, preferably background.
57     ALWAYS properly use tab spacing to even out the notifications.
58     NEVER re-declare an event twice.
59     NEVER add or remove fields from the format, it SHOULD already work.
60     MSG_INFO messages must ALWAYS end with a new line: \n
61     Be clean and simple with your notification naming, nothing too long.
62     Keep the notifications in alphabetical order.
63     ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^
64 */
65
66 // flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag");
67 // weaponorder[f1].netname
68 #define MSG_INFO_NOTIFICATIONS \
69         MSG_INFO_NOTIF(INFO_CTF_EVENT_PICKUP_RED, 2, 1, XPND3(s1, s2, "foobar"), "notify_death", _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
70         #undef MSG_INFO_NOTIF
71
72 #define MSG_CENTER_NOTIFICATIONS \
73         MSG_CENTER_NOTIF(CENTER_EMPTY,                                                  0, 0, NO_STR_ARG,                       NO_CPID,                                XPND2(0, 0), "", "") \
74         MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_SHIELDED,             0, 0, NO_STR_ARG,                       CPID_CTF_CAPTURESHIELD, XPND2(0, 0), _("^BGYou are now ^F1shielded^BG from the flag\n^BGfor ^F2too many unsuccessful attempts^BG to capture.\n^BGMake some defensive scores before trying again."), "") \
75         MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_FREE,                 0, 0, NO_STR_ARG,                       CPID_CTF_CAPTURESHIELD, XPND2(0, 0), _("^BGYou are now free.\n^BGFeel free to ^F2try to capture^BG the flag again\n^BGif you think you will succeed."), "") \
76         MSG_CENTER_NOTIF(CENTER_CTF_PASS_OTHER_RED,                     2, 0, XPND2(s1, s2),            CPID_CTF_PASS,                  XPND2(0, 0), _("^BG%s passed the ^1RED^BG flag to %s"), "") \
77         MSG_CENTER_NOTIF(CENTER_CTF_PASS_OTHER_BLUE,                    2, 0, XPND2(s1, s2),            CPID_CTF_PASS,                  XPND2(0, 0), _("^BG%s passed the ^4BLUE^BG flag to %s"), "") \
78         MSG_CENTER_NOTIF(CENTER_CTF_PASS_SENT_RED,                              1, 0, s1,                                       CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou passed the ^1RED^BG flag to %s"), "") \
79         MSG_CENTER_NOTIF(CENTER_CTF_PASS_SENT_BLUE,                     1, 0, s1,                                       CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou passed the ^4BLUE^BG flag to %s"), "") \
80         MSG_CENTER_NOTIF(CENTER_CTF_PASS_RECEIVED_RED,                  1, 0, s1,                                       CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou received the ^1RED^BG flag from %s"), "") \
81         MSG_CENTER_NOTIF(CENTER_CTF_PASS_RECEIVED_BLUE,                 1, 0, s1,                                       CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou received the ^4BLUE^BG flag from %s"), "") \
82         MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTING,                    1, 0, s1,                                       CPID_CTF_PASS,                  XPND2(0, 0), _("^BGRequesting %s to pass you the flag"), "") \
83         MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTED,                             1, 0, s1,                                       CPID_CTF_PASS,                  XPND2(0, 0), _("^BG%s requests you to pass the flag"), "") \
84         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_RETURN_RED,                   0, 0, NO_STR_ARG,                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou returned the ^1RED^BG flag"), "") \
85         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_RETURN_BLUE,                  0, 0, NO_STR_ARG,                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou returned the ^4BLUE^BG flag"), "") \
86         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_CAPTURE_RED,                  0, 0, NO_STR_ARG,                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou captured the ^1RED^BG flag"), "") \
87         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_CAPTURE_BLUE,                 0, 0, NO_STR_ARG,                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou captured the ^4BLUE^BG flag"), "") \
88         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PICKUP_RED,                   0, 0, NO_STR_ARG,                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou got the ^1RED^BG flag!"), "") \
89         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PICKUP_BLUE,                  0, 0, NO_STR_ARG,                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou got the ^4BLUE^BG flag!"), "") \
90         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PICKUP_TEAM,                  1, 0, s1,                                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYour %steam mate^BG got the flag! Protect them!"), "") \
91         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PICKUP_TEAM_VERBOSE,  2, 0, XPND3(s1, s2, s1),        CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"), "") \
92         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PICKUP_ENEMY,                 1, 0, s1,                                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
93         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PICKUP_ENEMY_VERBOSE, 2, 0, XPND3(s1, s2, s1),        CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"), "") \
94         MSG_CENTER_NOTIF(CENTER_CTF_STALEMATE_CARRIER,                  0, 0, NO_STR_ARG,                       CPID_STALEMATE,                 XPND2(0, 0), _("^BGStalemate! Enemies can now see you on radar!"), "") \
95         MSG_CENTER_NOTIF(CENTER_CTF_STALEMATE_OTHER,                    0, 0, NO_STR_ARG,                       CPID_STALEMATE,                 XPND2(0, 0), _("^BGStalemate! Flag carriers can now be seen by enemies on radar!"), "") \
96         MSG_CENTER_NOTIF(CENTER_CTF_FLAG_THROW_PUNISH,                  0, 1, f1,                                       CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGToo many flag throws! Throwing disabled for %d seconds."), "") \
97         #undef MSG_CENTER_NOTIF
98
99 #define MSG_WEAPON_NOTIFICATIONS \
100         MSG_WEAPON_NOTIF(DEATH_MARBLES_LOST3, 2, 1, XPND3(s1, s2, f1), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
101         #undef MSG_WEAPON_NOTIF
102
103
104 // ====================================
105 //  Initialization/Create Declarations
106 // ====================================
107
108 #define NOTIF_FIRST 1
109 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
110 float NOTIF_INFO_COUNT;
111 float NOTIF_CENTER_COUNT;
112 float NOTIF_WEAPON_COUNT;
113 float NOTIF_CPID_COUNT;
114
115 #ifdef CSQC
116 #define ADD_CSQC_AUTOCVAR(name) var float autocvar_notification_##name = TRUE;
117 #define CHECK_AUTOCVAR(name) if(autocvar_notification_##name)
118 #else
119 #define ADD_CSQC_AUTOCVAR(name)
120 #endif
121
122 #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
123         ADD_CSQC_AUTOCVAR(name) \
124         float name; \
125         void RegisterNotification_##name() \
126         { \
127                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
128                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_INFO_COUNT, "notifications") \
129         } \
130         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
131
132 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
133         ADD_CSQC_AUTOCVAR(name) \
134         float name; \
135         float cpid; \
136         void RegisterNotification_##name() \
137         { \
138                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
139                 SET_FIELD_COUNT(cpid, NOTIF_FIRST, NOTIF_CPID_COUNT) \
140                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_CENTER_COUNT, "notifications") \
141         } \
142         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
143
144 #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
145         ADD_CSQC_AUTOCVAR(name) \
146         float name; \
147         void RegisterNotification_##name() \
148         { \
149                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_WEAPON_COUNT) \
150                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_WEAPON_COUNT, "notifications") \
151         } \
152         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
153
154 // NOW we actually activate the declarations
155 MSG_INFO_NOTIFICATIONS
156 MSG_CENTER_NOTIFICATIONS
157 MSG_WEAPON_NOTIFICATIONS
158
159
160 // ======================
161 //  Supporting Functions
162 // ======================
163
164 // select between the normal or the gentle message string based on client (or server) settings
165 string normal_or_gentle(string normal, string gentle)
166 {
167         #ifdef CSQC
168         if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
169         #else
170         if(autocvar_sv_gentle)
171         #endif
172                 return ((gentle != "") ? gentle : normal);
173         else
174                 return normal;
175 }
176
177 float notif_stringcount(string s1, string s2)
178 {
179         float stringcount;
180         if(s1 != NO_STR_ARG) ++stringcount;
181         if(s2 != NO_STR_ARG) ++stringcount;
182         return stringcount;
183 }
184
185 float notif_floatcount(float f1, float f2, float f3)
186 {
187         float floatcount;
188         if(f1 != NO_FL_ARG) ++floatcount;
189         if(f2 != NO_FL_ARG) ++floatcount;
190         if(f3 != NO_FL_ARG) ++floatcount;
191         return floatcount;
192 }
193
194 // get the actual name of a notification and return it as a string
195 string Get_Field_Value(float field, float net_type, float net_name)
196 {
197         string output;
198         
199         #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \
200                 if(field == F_NAME) { output = VAR_TO_TEXT(name); } \
201                 else if(field == F_STRNUM) { output = ftos(strnum); } \
202                 else if(field == F_FLNUM) { output = ftos(flnum); }
203         
204         switch(net_type)
205         {
206                 case MSG_INFO:
207                 {
208                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
209                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
210                         MSG_INFO_NOTIFICATIONS
211                         break;
212                 }
213                 case MSG_CENTER:
214                 {
215                         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
216                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
217                         MSG_CENTER_NOTIFICATIONS
218                         break;
219                 }
220                 case MSG_WEAPON:
221                 {
222                         #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
223                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
224                         MSG_WEAPON_NOTIFICATIONS
225                         break;
226                 }
227         }
228
229         #undef GET_FIELD_VALUE_OUTPUT
230         return output;
231 }
232
233 // color code replace, place inside of sprintf and parse the string
234 string CCR(string input)
235 {
236         input = strreplace("^F1", "^3", input); // autocvar_notification_colors_F1 
237         input = strreplace("^F2", "^2", input); // autocvar_notification_colors_F2
238         input = strreplace("^K1", "^1", input); // autocvar_notification_colors_K1
239         input = strreplace("^K2", "^5", input); // autocvar_notification_colors_K2
240         input = strreplace("^BG", "^7", input); // autocvar_notification_colors_BG
241
242         input = strreplace("^N", "^7", input); // "none"-- reset to white
243
244         return input;
245 }
246
247
248 // ===============================
249 //  Frontend Notification Pushing
250 // ===============================
251
252 #ifdef CSQC
253 void Local_Notification(float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
254 {
255         switch(net_type)
256         {
257                 case MSG_INFO:
258                 {
259                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
260                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
261                         MSG_INFO_NOTIFICATIONS
262                         break;
263                 }
264                 case MSG_CENTER:
265                 {
266                         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
267                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); } }
268                         MSG_CENTER_NOTIFICATIONS
269                         break;
270                 }
271                 case MSG_WEAPON:
272                 {
273                         #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
274                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { print("unhandled\n"); } }
275                         MSG_WEAPON_NOTIFICATIONS
276                         break;
277                 }
278         }
279 }
280 #endif
281
282
283 // =========================
284 //  Notification Networking
285 // =========================
286
287 #ifdef CSQC
288 void Read_Notification(void)
289 {
290         float net_type = ReadByte();
291         float net_name = ReadShort();
292
293         float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
294         float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));  
295         
296         Local_Notification(net_type, net_name,
297                 ((stringcount >= 1) ? ReadString() : ""),
298                 ((stringcount == 2) ? ReadString() : ""),
299                 ((floatcount >= 1) ? ReadLong() : 0),
300                 ((floatcount >= 2) ? ReadLong() : 0),
301                 ((floatcount == 3) ? ReadLong() : 0));
302 }
303 #endif
304
305 #ifdef SVQC
306 void Send_Notification(entity client, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
307 {
308         if(net_type && net_name)
309         {
310                 print("notification: ", Get_Field_Value(F_NAME, net_type, net_name), ": ", ftos(net_name), ".\n");
311
312                 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
313                 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
314                 
315                 if(notif_stringcount(s1, s2) > stringcount) { backtrace("Too many string arguments for notification!\n"); return; }
316                 if(notif_floatcount(f1, f2, f3) > floatcount) { backtrace("Too many float arguments for notification!\n"); return; }
317                 
318                 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
319                 {
320                         // personal/direct notification sent to ONE person and their spectators
321                         msg_entity = client;
322                         WRITESPECTATABLE_MSG_ONE({
323                                 WriteByte(MSG_ONE, SVC_TEMPENTITY);
324                                 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
325                                 WriteByte(MSG_ONE, net_type);
326                                 WriteShort(MSG_ONE, net_name);
327                                 if(stringcount >= 1) { WriteString(MSG_ONE, s1); }
328                                 if(stringcount == 2) { WriteString(MSG_ONE, s2); }
329                                 if(floatcount >= 1) { WriteLong(MSG_ONE, f1); }
330                                 if(floatcount >= 2) { WriteLong(MSG_ONE, f2); }
331                                 if(floatcount == 3) { WriteLong(MSG_ONE, f3); }
332                         });
333                 }
334                 else
335                 {
336                         // global notification sent to EVERYONE
337                         WriteByte(MSG_ALL, SVC_TEMPENTITY);
338                         WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
339                         WriteByte(MSG_ALL, net_type);
340                         WriteShort(MSG_ALL, net_name);
341                         if(stringcount >= 1) { WriteString(MSG_ALL, s1); }
342                         if(stringcount == 2) { WriteString(MSG_ALL, s2); }
343                         if(floatcount >= 1) { WriteLong(MSG_ALL, f1); }
344                         if(floatcount >= 2) { WriteLong(MSG_ALL, f2); }
345                         if(floatcount == 3) { WriteLong(MSG_ALL, f3); }
346                 }
347
348                 if(!server_is_local && (net_type == MSG_INFO))
349                 {
350                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
351                                 { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
352                         MSG_INFO_NOTIFICATIONS
353                 }
354         }
355         else { backtrace("Incorrect usage of Send_Notification!\n"); }
356 }
357
358 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
359 {
360         entity tmp_entity;
361         FOR_EACH_REALCLIENT(tmp_entity)
362         {
363                 if(tmp_entity.classname == STR_PLAYER)
364                 if(tmp_entity.team == targetteam)
365                 if(tmp_entity != except)
366                 {
367                         Send_Notification(tmp_entity, net_type, net_name, s1, s2, f1, f2, f3);
368                 }
369         }
370 }
371
372 // WARNING: use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(..., world, ...)
373 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
374 {
375         entity tmp_entity;
376         FOR_EACH_REALCLIENT(tmp_entity)
377         {
378                 if((tmp_entity.classname == STR_PLAYER) || spectators)
379                 if(tmp_entity != except)
380                 {
381                         Send_Notification(tmp_entity, net_type, net_name, s1, s2, f1, f2, f3);
382                 }
383         }
384 }
385
386
387 // =============================
388 //  LEGACY NOTIFICATION SYSTEMS
389 // =============================
390
391 void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
392 {
393         WriteByte(MSG_ALL, SVC_TEMPENTITY);
394         WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
395         WriteString(MSG_ALL, s1);
396         WriteString(MSG_ALL, s2);
397         WriteString(MSG_ALL, s3);
398         WriteShort(MSG_ALL, msg);
399         WriteByte(MSG_ALL, type);
400 }
401
402 // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
403 void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
404 {
405         if (clienttype(e) == CLIENTTYPE_REAL)
406         {
407                 msg_entity = e;
408                 WRITESPECTATABLE_MSG_ONE({
409                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
410                         WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
411                         WriteString(MSG_ONE, s1);
412                         WriteString(MSG_ONE, s2);
413                         WriteShort(MSG_ONE, msg);
414                         WriteByte(MSG_ONE, type);
415                 });
416         }
417 }
418
419 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
420 {
421         if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
422         {
423                 msg_entity = e;
424                 WRITESPECTATABLE_MSG_ONE({
425                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
426                         WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
427                         WriteByte(MSG_ONE, id);
428                         WriteString(MSG_ONE, s);
429                         if (id != 0 && s != "")
430                         {
431                                 WriteByte(MSG_ONE, duration);
432                                 WriteByte(MSG_ONE, countdown_num);
433                         }
434                 });
435         }
436 }
437 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
438 {
439         Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
440 }
441 #endif