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