]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/notifications.qc
Support up to 4 team definitions
[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 NOTIF_MATCH(a,b) if(min(NOTIF_MAX, a) == b)
26 #ifdef CSQC
27 string got_commandkey;
28 #define ADD_CSQC_AUTOCVAR(name) var float autocvar_notification_##name = TRUE;
29 var float autocvar_notification_ctf_capture_verbose = TRUE;
30 var float autocvar_notification_ctf_pickup_team_verbose = TRUE;
31 var float autocvar_notification_ctf_pickup_enemy_verbose = TRUE;
32 #define CHECK_AUTOCVAR(name) if(autocvar_notification_##name)
33 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
34 #define PASS_KEY ((((got_commandkey = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(got_commandkey, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), got_commandkey) : "")
35 #else
36 #define ADD_CSQC_AUTOCVAR(name)
37 #endif
38
39 string team_name_red = _("RED");
40 string team_name_blue = _("BLUE");
41 string team_color_red = _("^1");
42 string team_color_blue = _("^4");
43
44
45 // ====================================
46 //  Notifications List and Information
47 // ====================================
48 /*
49  List of all notifications (including identifiers and display information)
50  Format: name, strnum, flnum, args, *icon/CPID, *durcnt, normal, gentle
51  Asterisked fields are not present in all notification types.
52  Specifications:
53     Name of notification
54     Number of STRING arguments (so that networking knows how many to send/receive)
55     Number of FLOAT arguments (so that networking knows how many to send/receive)
56     Arguments for sprintf(string, args), if no args needed then use ""
57     *Icon/CPID:
58       MSG_INFO: STRING: icon string name for the hud notify panel, "" if no icon is used
59       MSG_CENTER: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
60     *Duration/Countdown:
61       MSG_CENTER: XPND2(FLOAT, FLOAT): extra arguments for centerprint messages
62     Normal message (string for sprintf when gentle messages are NOT enabled)
63     Gentle message (string for sprintf when gentle messages ARE enabled)
64
65  Messages have ^F1, ^F2, and ^BG in them-- these are replaced
66  with colors according to the cvars the user has chosen.
67     ^F1 = highest priority, "primary"
68     ^F2 = next highest priority, "secondary"
69     ^BG = normal/less important priority, "tertiary"
70
71  Guidlines (please try and follow these):
72     -ALWAYS start the string with a color, preferably background.
73     -ALWAYS reset a color after a name (this way they don't set it for the whole string).
74     -NEVER re-declare an event twice.
75     -NEVER add or remove fields from the format, it SHOULD already work.
76     -MSG_INFO messages must ALWAYS end with a new line: \n
77     -Be clean and simple with your notification naming,
78      nothing too long for the name field... Abbreviations are your friend. :D
79     -Keep the spacing as clean as possible... if the arguments are abnormally long,
80       it's okay to go out of line a bit... but try and keep it clean still.
81     -Keep the notifications in alphabetical order.
82     ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^
83 */
84
85 // flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag");
86 // weaponorder[f1].netname
87
88
89 #define MULTITEAM_INFO(prefix,teams,strnum,flnum,args,icon,normal,gentle) \
90         MSG_INFO_NOTIF(prefix##RED, strnum, flnum, args, sprintf(icon, strtolower(team_name_red)), TEAM_CCR(normal, team_color_red, team_name_red), TEAM_CCR(gentle, team_color_red, team_name_red)) \
91         MSG_INFO_NOTIF(prefix##BLUE, strnum, flnum, args, sprintf(icon, strtolower(team_name_blue)), TEAM_CCR(normal, team_color_blue, team_name_blue), TEAM_CCR(gentle, team_color_blue, team_name_blue)) \
92         #if teams >= 3 \
93                 MSG_INFO_NOTIF(prefix##YELLOW, strnum, flnum, args, sprintf(icon, strtolower(team_name_yellow)), TEAM_CCR(normal, team_color_yellow, team_name_yellow), TEAM_CCR(gentle, team_color_yellow, team_name_yellow)) \
94         #endif \
95         #if teams >= 4 \
96                 MSG_INFO_NOTIF(prefix##PINK, strnum, flnum, args, sprintf(icon, strtolower(team_name_pink)), TEAM_CCR(normal, team_color_pink, team_name_pink), TEAM_CCR(gentle, team_color_pink, team_name_pink)) \
97         #endif
98 #define MSG_INFO_NOTIFICATIONS \
99         MSG_INFO_NOTIF(INFO_EMPTY,                                                      0, 0, NO_STR_ARG,                                               "", "", "") \
100         MULTITEAM_INFO(INFO_SCORES_, 2,                                         0, 0, NO_STR_ARG,                                               "", _("^TC^TT ^BGteam scores!\n"), "") \
101         MULTITEAM_INFO(INFO_CTF_FLAGRETURN_DROPPED_, 2,         0, 0, NO_STR_ARG,                                               "", _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself\n"), "") \
102         MULTITEAM_INFO(INFO_CTF_FLAGRETURN_DAMAGED_, 2,         0, 0, NO_STR_ARG,                                               "", _("^BGThe ^TC^TT^BG flag was destroyed and returned to base\n"), "") \
103         MULTITEAM_INFO(INFO_CTF_FLAGRETURN_SPEEDRUN_, 2,        0, 1, f1/100,                                                   "", _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself\n"), "") \
104         MULTITEAM_INFO(INFO_CTF_FLAGRETURN_NEEDKILL_, 2,        0, 0, NO_STR_ARG,                                               "", _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base\n"), "") \
105         MULTITEAM_INFO(INFO_CTF_FLAGRETURN_ABORTRUN_, 2,        0, 0, NO_STR_ARG,                                               "", _("^BGThe ^TC^TT^BG flag was returned to base by its owner\n"), "") \
106         MULTITEAM_INFO(INFO_CTF_FLAGRETURN_TIMEOUT_, 2,         0, 0, NO_STR_ARG,                                               "", _("^BGThe ^TC^TT^BG flag has returned to the base\n"), "") \
107         MULTITEAM_INFO(INFO_CTF_PICKUP_, 2,                                     1, 0, s1,                                                               "notify_%s_taken", _("^BG%s^BG got the ^TC^TT^BG flag\n"), "") \
108         MULTITEAM_INFO(INFO_CTF_RETURN_, 2,                                     1, 0, s1,                                                               "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag\n"), "") \
109         MULTITEAM_INFO(INFO_CTF_LOST_, 2,                                       1, 0, s1,                                                               "notify_%s_lost", _("^BG%s^BG lost the ^TC^TT^BG flag\n"), "") \
110         MULTITEAM_INFO(INFO_CTF_CAPTURE_, 2,                            1, 0, s1,                                                               "notify_%s_capture", _("^BG%s^BG captured the ^TC^TT^BG flag\n"), "") \
111         MULTITEAM_INFO(INFO_CTF_CAPTURE_TIME_, 2,                       1, 1, XPND2(s1, f1/100),                                "notify_%s_capture", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%.2f^BG seconds\n"), "") \
112         MULTITEAM_INFO(INFO_CTF_CAPTURE_BROKEN_, 2,                     2, 2, XPND4(s1, f1/100, s2, f2/100),    "notify_%s_capture", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%.2f^BG seconds, breaking ^BG%s^BG's previous record of ^F2%.2f^BG seconds\n"), "") \
113         MULTITEAM_INFO(INFO_CTF_CAPTURE_UNBROKEN_, 2,           2, 2, XPND4(s1, f1/100, s2, f2/100),    "notify_%s_capture", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F2%.2f^BG seconds, failing to break ^BG%s^BG's previous record of ^F1%.2f^BG seconds\n"), "") \
114         #undef MSG_INFO_NOTIF
115
116
117 #define MULTITEAM_CENTER(prefix,teams,strnum,flnum,args,cpid,durcnt,normal,gentle) \
118         MSG_CENTER_NOTIF(prefix##RED, strnum, flnum, args, cpid, durcnt, TEAM_CCR(normal, team_color_red, team_name_red), TEAM_CCR(gentle, team_color_red, team_name_red)) \
119         MSG_CENTER_NOTIF(prefix##BLUE, strnum, flnum, args, cpid, durcnt, TEAM_CCR(normal, team_color_blue, team_name_blue), TEAM_CCR(gentle, team_color_blue, team_name_blue)) \
120         #if teams >= 3 \
121                 MSG_CENTER_NOTIF(prefix##YELLOW, strnum, flnum, args, cpid, durcnt, TEAM_CCR(normal, team_color_yellow, team_name_yellow), TEAM_CCR(gentle, team_color_yellow, team_name_yellow)) \
122         #endif \
123         #if teams >= 4 \
124                 MSG_CENTER_NOTIF(prefix##PINK, strnum, flnum, args, cpid, durcnt, TEAM_CCR(normal, team_color_pink, team_name_pink), TEAM_CCR(gentle, team_color_pink, team_name_pink)) \
125         #endif
126 #define MSG_CENTER_NOTIFICATIONS \
127         MSG_CENTER_NOTIF(CENTER_EMPTY,                                                  0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), "", "") \
128         MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_SHIELDED,             0, 0, NO_STR_ARG,                               CPID_CTF_CAPSHIELD,             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."), "") \
129         MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_FREE,                 0, 0, NO_STR_ARG,                               CPID_CTF_CAPSHIELD,             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."), "") \
130         MULTITEAM_CENTER(CENTER_CTF_PASS_OTHER_, 2,                             2, 0, XPND2(s1, s2),                    CPID_CTF_PASS,                  XPND2(0, 0), _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "") \
131         MULTITEAM_CENTER(CENTER_CTF_PASS_SENT_, 2,                              1, 0, s1,                                               CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou passed the ^TC^TT^BG flag to %s"), "") \
132         MULTITEAM_CENTER(CENTER_CTF_PASS_RECEIVED_, 2,                  1, 0, s1,                                               CPID_CTF_PASS,                  XPND2(0, 0), _("^BGYou received the ^TC^TT^BG flag from %s"), "") \
133         MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTING,                    1, 0, s1,                                               CPID_CTF_PASS,                  XPND2(0, 0), _("^BGRequesting %s^BG to pass you the flag"), "") \
134         MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTED,                     1, 0, XPND2(s1, PASS_KEY),              CPID_CTF_PASS,                  XPND2(0, 0), _("^BG%s^BG requests you to pass the flag%s"), "") \
135         MULTITEAM_CENTER(CENTER_CTF_RETURN_, 2,                                 0, 0, NO_STR_ARG,                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou returned the ^TC^TT^BG flag!"), "") \
136         MULTITEAM_CENTER(CENTER_CTF_CAPTURE_, 2,                                0, 0, NO_STR_ARG,                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou captured the ^TC^TT^BG flag!"), "") \
137         MULTITEAM_CENTER(CENTER_CTF_PICKUP_, 2,                                 0, 0, NO_STR_ARG,                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou got the ^TC^TT^BG flag!"), "") \
138         MSG_CENTER_NOTIF(CENTER_CTF_PICKUP_TEAM,                                1, 0, s1,                                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYour %steam mate^BG got the flag! Protect them!"), "") \
139         MSG_CENTER_NOTIF(CENTER_CTF_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!"), "") \
140         MSG_CENTER_NOTIF(CENTER_CTF_PICKUP_ENEMY,                               1, 0, s1,                                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
141         MSG_CENTER_NOTIF(CENTER_CTF_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!"), "") \
142         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!"), "") \
143         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!"), "") \
144         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."), "") \
145         #undef MSG_CENTER_NOTIF
146
147 #define MSG_WEAPON_NOTIFICATIONS \
148         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"), "") \
149         #undef MSG_WEAPON_NOTIF
150
151
152 // ====================================
153 //  Initialization/Create Declarations
154 // ====================================
155
156 #define NOTIF_FIRST 1
157 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
158 float NOTIF_INFO_COUNT;
159 float NOTIF_CENTER_COUNT;
160 float NOTIF_WEAPON_COUNT;
161 float NOTIF_CPID_COUNT;
162
163 #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
164         ADD_CSQC_AUTOCVAR(name) \
165         float name; \
166         void RegisterNotification_##name() \
167         { \
168                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
169                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_INFO_COUNT, "notifications") \
170         } \
171         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
172
173 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
174         ADD_CSQC_AUTOCVAR(name) \
175         float name; \
176         float cpid; \
177         void RegisterNotification_##name() \
178         { \
179                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
180                 SET_FIELD_COUNT(cpid, NOTIF_FIRST, NOTIF_CPID_COUNT) \
181                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_CENTER_COUNT, "notifications") \
182         } \
183         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
184
185 #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
186         ADD_CSQC_AUTOCVAR(name) \
187         float name; \
188         void RegisterNotification_##name() \
189         { \
190                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_WEAPON_COUNT) \
191                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_WEAPON_COUNT, "notifications") \
192         } \
193         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
194
195 // NOW we actually activate the declarations
196 MSG_INFO_NOTIFICATIONS
197 MSG_CENTER_NOTIFICATIONS
198 MSG_WEAPON_NOTIFICATIONS
199
200
201 // ======================
202 //  Supporting Functions
203 // ======================
204
205 // select between the normal or the gentle message string based on client (or server) settings
206 string normal_or_gentle(string normal, string gentle)
207 {
208         #ifdef CSQC
209         if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
210         #else
211         if(autocvar_sv_gentle)
212         #endif
213                 return ((gentle != "") ? gentle : normal);
214         else
215                 return normal;
216 }
217
218 float notif_stringcount(string s1, string s2)
219 {
220         float stringcount;
221         if(s1 != NO_STR_ARG) ++stringcount;
222         if(s2 != NO_STR_ARG) ++stringcount;
223         return stringcount;
224 }
225
226 float notif_floatcount(float f1, float f2, float f3)
227 {
228         float floatcount;
229         if(f1 != NO_FL_ARG) ++floatcount;
230         if(f2 != NO_FL_ARG) ++floatcount;
231         if(f3 != NO_FL_ARG) ++floatcount;
232         return floatcount;
233 }
234
235 // get the actual name of a notification and return it as a string
236 string Get_Field_Value(float field, float net_type, float net_name)
237 {
238         string output;
239         
240         #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \
241                 if(field == F_NAME) { output = VAR_TO_TEXT(name); } \
242                 else if(field == F_STRNUM) { output = ftos(strnum); } \
243                 else if(field == F_FLNUM) { output = ftos(flnum); }
244         
245         switch(net_type)
246         {
247                 case MSG_INFO:
248                 {
249                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
250                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
251                         MSG_INFO_NOTIFICATIONS
252                         break;
253                 }
254                 case MSG_CENTER:
255                 {
256                         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
257                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
258                         MSG_CENTER_NOTIFICATIONS
259                         break;
260                 }
261                 case MSG_WEAPON:
262                 {
263                         #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
264                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
265                         MSG_WEAPON_NOTIFICATIONS
266                         break;
267                 }
268         }
269
270         #undef GET_FIELD_VALUE_OUTPUT
271         return output;
272 }
273
274 string TEAM_CCR(string input, string teamcolor, string teamtext)
275 {
276         input = strreplace("^TC", teamcolor, input);
277         input = strreplace("^TT", teamtext, input);
278
279         return input;
280 }
281
282 // color code replace, place inside of sprintf and parse the string
283 string CCR(string input)
284 {
285         input = strreplace("^F1", "^2", input); // autocvar_notification_colors_F1 
286         input = strreplace("^F2", "^3", input); // autocvar_notification_colors_F2
287         input = strreplace("^K1", "^1", input); // autocvar_notification_colors_K1
288         input = strreplace("^K2", "^3", input); // autocvar_notification_colors_K2
289         input = strreplace("^BG", "^7", input); // autocvar_notification_colors_BG
290
291         input = strreplace("^N", "^7", input); // "none"-- reset to white
292
293         return input;
294 }
295
296
297 // ===============================
298 //  Frontend Notification Pushing
299 // ===============================
300
301 #ifdef CSQC
302 void Local_Notification(float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
303 {
304         switch(net_type)
305         {
306                 case MSG_INFO:
307                 {
308                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
309                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
310                         MSG_INFO_NOTIFICATIONS
311                         break;
312                 }
313                 case MSG_CENTER:
314                 {
315                         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
316                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); } }
317                         MSG_CENTER_NOTIFICATIONS
318                         break;
319                 }
320                 case MSG_WEAPON:
321                 {
322                         #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
323                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) { print("unhandled\n"); } }
324                         MSG_WEAPON_NOTIFICATIONS
325                         break;
326                 }
327         }
328 }
329 #endif
330
331
332 // =========================
333 //  Notification Networking
334 // =========================
335
336 #ifdef CSQC
337 void Read_Notification(void)
338 {
339         float net_type = ReadByte();
340         float net_name = ReadShort();
341
342         float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
343         float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
344         
345         Local_Notification(net_type, net_name,
346                 ((stringcount >= 1) ? ReadString() : ""),
347                 ((stringcount == 2) ? ReadString() : ""),
348                 ((floatcount >= 1) ? ReadLong() : 0),
349                 ((floatcount >= 2) ? ReadLong() : 0),
350                 ((floatcount == 3) ? ReadLong() : 0));
351 }
352 #endif
353
354 #ifdef SVQC
355 void Send_Notification(entity client, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
356 {
357         if(net_type && net_name)
358         {
359                 print("notification: ", Get_Field_Value(F_NAME, net_type, net_name), ": ", ftos(net_name), ".\n");
360
361                 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
362                 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
363                 
364                 if(notif_stringcount(s1, s2) > stringcount) { backtrace("Too many string arguments for notification!\n"); return; }
365                 if(notif_floatcount(f1, f2, f3) > floatcount) { backtrace("Too many float arguments for notification!\n"); return; }
366                 
367                 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
368                 {
369                         // personal/direct notification sent to ONE person and their spectators
370                         msg_entity = client;
371                         WRITESPECTATABLE_MSG_ONE({
372                                 WriteByte(MSG_ONE, SVC_TEMPENTITY);
373                                 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
374                                 WriteByte(MSG_ONE, net_type);
375                                 WriteShort(MSG_ONE, net_name);
376                                 if(stringcount >= 1) { WriteString(MSG_ONE, s1); }
377                                 if(stringcount == 2) { WriteString(MSG_ONE, s2); }
378                                 if(floatcount >= 1) { WriteLong(MSG_ONE, f1); }
379                                 if(floatcount >= 2) { WriteLong(MSG_ONE, f2); }
380                                 if(floatcount == 3) { WriteLong(MSG_ONE, f3); }
381                         });
382                 }
383                 else
384                 {
385                         // global notification sent to EVERYONE
386                         WriteByte(MSG_ALL, SVC_TEMPENTITY);
387                         WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
388                         WriteByte(MSG_ALL, net_type);
389                         WriteShort(MSG_ALL, net_name);
390                         if(stringcount >= 1) { WriteString(MSG_ALL, s1); }
391                         if(stringcount == 2) { WriteString(MSG_ALL, s2); }
392                         if(floatcount >= 1) { WriteLong(MSG_ALL, f1); }
393                         if(floatcount >= 2) { WriteLong(MSG_ALL, f2); }
394                         if(floatcount == 3) { WriteLong(MSG_ALL, f3); }
395                 }
396
397                 if(!server_is_local && (net_type == MSG_INFO))
398                 {
399                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
400                                 { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
401                         MSG_INFO_NOTIFICATIONS
402                 }
403         }
404         else { backtrace("Incorrect usage of Send_Notification!\n"); }
405 }
406
407 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
408 {
409         entity tmp_entity;
410         FOR_EACH_REALCLIENT(tmp_entity)
411         {
412                 if(tmp_entity.classname == STR_PLAYER)
413                 if(tmp_entity.team == targetteam)
414                 if(tmp_entity != except)
415                 {
416                         Send_Notification(tmp_entity, net_type, net_name, s1, s2, f1, f2, f3);
417                 }
418         }
419 }
420
421 // WARNING: use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(..., world, ...)
422 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
423 {
424         entity tmp_entity;
425         FOR_EACH_REALCLIENT(tmp_entity)
426         {
427                 if((tmp_entity.classname == STR_PLAYER) || spectators)
428                 if(tmp_entity != except)
429                 {
430                         Send_Notification(tmp_entity, net_type, net_name, s1, s2, f1, f2, f3);
431                 }
432         }
433 }
434
435
436 // =============================
437 //  LEGACY NOTIFICATION SYSTEMS
438 // =============================
439
440 void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
441 {
442         WriteByte(MSG_ALL, SVC_TEMPENTITY);
443         WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
444         WriteString(MSG_ALL, s1);
445         WriteString(MSG_ALL, s2);
446         WriteString(MSG_ALL, s3);
447         WriteShort(MSG_ALL, msg);
448         WriteByte(MSG_ALL, type);
449 }
450
451 // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
452 void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
453 {
454         if (clienttype(e) == CLIENTTYPE_REAL)
455         {
456                 msg_entity = e;
457                 WRITESPECTATABLE_MSG_ONE({
458                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
459                         WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
460                         WriteString(MSG_ONE, s1);
461                         WriteString(MSG_ONE, s2);
462                         WriteShort(MSG_ONE, msg);
463                         WriteByte(MSG_ONE, type);
464                 });
465         }
466 }
467
468 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
469 {
470         if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
471         {
472                 msg_entity = e;
473                 WRITESPECTATABLE_MSG_ONE({
474                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
475                         WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
476                         WriteByte(MSG_ONE, id);
477                         WriteString(MSG_ONE, s);
478                         if (id != 0 && s != "")
479                         {
480                                 WriteByte(MSG_ONE, duration);
481                                 WriteByte(MSG_ONE, countdown_num);
482                         }
483                 });
484         }
485 }
486 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
487 {
488         Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
489 }
490 #endif