]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/notifications.qc
Move ALL of the centerprints in CTF over to the new system
[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 #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \
195         if(field == F_NAME) { output = VAR_TO_TEXT(name); } \
196         else if(field == F_STRNUM) { output = ftos(strnum); } \
197         else if(field == F_FLNUM) { output = ftos(flnum); }
198
199 // get the actual name of a notification and return it as a string
200 string Get_Field_Value(float field, float net_type, float net_name)
201 {
202         string output;
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         return output;
230 }
231
232 // color code replace, place inside of sprintf and parse the string
233 string CCR(string input)
234 {
235         input = strreplace("^F1", "^3", input); // autocvar_notification_colors_F1 
236         input = strreplace("^F2", "^2", input); // autocvar_notification_colors_F2
237         input = strreplace("^K1", "^1", input); // autocvar_notification_colors_K1
238         input = strreplace("^K2", "^5", input); // autocvar_notification_colors_K2
239         input = strreplace("^BG", "^7", input); // autocvar_notification_colors_BG
240
241         input = strreplace("^N", "^7", input); // "none"-- reset to white
242
243         return input;
244 }
245
246
247 // ===============================
248 //  Frontend Notification Pushing
249 // ===============================
250
251 #ifdef CSQC
252 void Local_Notification(float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
253 {
254         switch(net_type)
255         {
256                 case MSG_INFO:
257                 {
258                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
259                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
260                         MSG_INFO_NOTIFICATIONS
261                         break;
262                 }
263                 case MSG_CENTER:
264                 {
265                         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
266                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); } }
267                         MSG_CENTER_NOTIFICATIONS
268                         break;
269                 }
270                 case MSG_WEAPON:
271                 {
272                         #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
273                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { print("unhandled\n"); } }
274                         MSG_WEAPON_NOTIFICATIONS
275                         break;
276                 }
277         }
278 }
279 #endif
280
281
282 // =========================
283 //  Notification Networking
284 // =========================
285
286 #ifdef CSQC
287 void Read_Notification(void)
288 {
289         float net_type = ReadByte();
290         float net_name = ReadShort();
291
292         float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
293         float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));  
294         
295         Local_Notification(net_type, net_name,
296                 ((stringcount >= 1) ? ReadString() : ""),
297                 ((stringcount == 2) ? ReadString() : ""),
298                 ((floatcount >= 1) ? ReadLong() : 0),
299                 ((floatcount >= 2) ? ReadLong() : 0),
300                 ((floatcount == 3) ? ReadLong() : 0));
301 }
302 #endif
303
304 #ifdef SVQC
305 void Send_Notification(entity client, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
306 {
307         if(net_type && net_name)
308         {
309                 print("notification: ", Get_Field_Value(F_NAME, net_type, net_name), ": ", ftos(net_name), ".\n");
310
311                 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
312                 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
313                 
314                 if(notif_stringcount(s1, s2) > stringcount) { backtrace("Too many string arguments for notification!\n"); return; }
315                 if(notif_floatcount(f1, f2, f3) > floatcount) { backtrace("Too many float arguments for notification!\n"); return; }
316                 
317                 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
318                 {
319                         // personal/direct notification sent to ONE person and their spectators
320                         msg_entity = client;
321                         WRITESPECTATABLE_MSG_ONE({
322                                 WriteByte(MSG_ONE, SVC_TEMPENTITY);
323                                 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
324                                 WriteByte(MSG_ONE, net_type);
325                                 WriteShort(MSG_ONE, net_name);
326                                 if(stringcount >= 1) { WriteString(MSG_ONE, s1); }
327                                 if(stringcount == 2) { WriteString(MSG_ONE, s2); }
328                                 if(floatcount >= 1) { WriteLong(MSG_ONE, f1); }
329                                 if(floatcount >= 2) { WriteLong(MSG_ONE, f2); }
330                                 if(floatcount == 3) { WriteLong(MSG_ONE, f3); }
331                         });
332                 }
333                 else
334                 {
335                         // global notification sent to EVERYONE
336                         WriteByte(MSG_ALL, SVC_TEMPENTITY);
337                         WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
338                         WriteByte(MSG_ALL, net_type);
339                         WriteShort(MSG_ALL, net_name);
340                         if(stringcount >= 1) { WriteString(MSG_ALL, s1); }
341                         if(stringcount == 2) { WriteString(MSG_ALL, s2); }
342                         if(floatcount >= 1) { WriteLong(MSG_ALL, f1); }
343                         if(floatcount >= 2) { WriteLong(MSG_ALL, f2); }
344                         if(floatcount == 3) { WriteLong(MSG_ALL, f3); }
345                 }
346
347                 if(!server_is_local && (net_type == MSG_INFO))
348                 {
349                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
350                                 { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
351                         MSG_INFO_NOTIFICATIONS
352                 }
353         }
354         else { backtrace("Incorrect usage of Send_Notification!\n"); }
355 }
356
357 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
358 {
359         entity tmp_entity;
360         FOR_EACH_REALCLIENT(tmp_entity)
361         {
362                 if(tmp_entity.classname == STR_PLAYER)
363                 if(tmp_entity.team == targetteam)
364                 if(tmp_entity != except)
365                 {
366                         Send_Notification(tmp_entity, net_type, net_name, s1, s2, f1, f2, f3);
367                 }
368         }
369 }
370
371 // WARNING: use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(..., world, ...)
372 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
373 {
374         entity tmp_entity;
375         FOR_EACH_REALCLIENT(tmp_entity)
376         {
377                 if((tmp_entity.classname == STR_PLAYER) || spectators)
378                 if(tmp_entity != except)
379                 {
380                         Send_Notification(tmp_entity, net_type, net_name, s1, s2, f1, f2, f3);
381                 }
382         }
383 }
384
385
386 // =============================
387 //  LEGACY NOTIFICATION SYSTEMS
388 // =============================
389
390 void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
391 {
392         WriteByte(MSG_ALL, SVC_TEMPENTITY);
393         WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
394         WriteString(MSG_ALL, s1);
395         WriteString(MSG_ALL, s2);
396         WriteString(MSG_ALL, s3);
397         WriteShort(MSG_ALL, msg);
398         WriteByte(MSG_ALL, type);
399 }
400
401 // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
402 void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
403 {
404         if (clienttype(e) == CLIENTTYPE_REAL)
405         {
406                 msg_entity = e;
407                 WRITESPECTATABLE_MSG_ONE({
408                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
409                         WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
410                         WriteString(MSG_ONE, s1);
411                         WriteString(MSG_ONE, s2);
412                         WriteShort(MSG_ONE, msg);
413                         WriteByte(MSG_ONE, type);
414                 });
415         }
416 }
417
418 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
419 {
420         if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
421         {
422                 msg_entity = e;
423                 WRITESPECTATABLE_MSG_ONE({
424                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
425                         WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
426                         WriteByte(MSG_ONE, id);
427                         WriteString(MSG_ONE, s);
428                         if (id != 0 && s != "")
429                         {
430                                 WriteByte(MSG_ONE, duration);
431                                 WriteByte(MSG_ONE, countdown_num);
432                         }
433                 });
434         }
435 }
436 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
437 {
438         Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
439 }
440 #endif