1 #ifndef NOTIFICATIONS_H
2 #define NOTIFICATIONS_H
4 #include "command/all.qh"
6 #include "constants.qh"
10 // ================================================
11 // Unified notification system, written by Samual
12 // Last updated: March, 2013
13 // ================================================
15 // main types/groups of notifications
16 const int MSG_ANNCE = 1; // "Global" AND "personal" announcer messages
17 const int MSG_INFO = 2; // "Global" information messages
18 const int MSG_CENTER = 3; // "Personal" centerprint messages
19 const int MSG_CENTER_CPID = 4; // Kill centerprint message
20 const int MSG_MULTI = 5; // Subcall MSG_INFO and/or MSG_CENTER notifications
21 const int MSG_CHOICE = 6; // Choose which subcall wrapper to activate
23 // negative confirmations
24 const int NO_MSG = -12345; // allows various things to know when no information is added
25 const int NOTIF_ABORT = -1234; // allows Send_Notification to safely abort sending
27 #define EIGHT_VARS_TO_VARARGS_VARLIST \
29 VARITEM(2, 0, XPD(s1, s2)) \
30 VARITEM(3, 0, XPD(s1, s2, s3)) \
31 VARITEM(4, 0, XPD(s1, s2, s3, s4)) \
33 VARITEM(1, 1, XPD(s1, f1)) \
34 VARITEM(2, 1, XPD(s1, s2, f1)) \
35 VARITEM(3, 1, XPD(s1, s2, s3, f1)) \
36 VARITEM(4, 1, XPD(s1, s2, s3, s4, f1)) \
37 VARITEM(0, 2, XPD(f1, f2)) \
38 VARITEM(1, 2, XPD(s1, f1, f2)) \
39 VARITEM(2, 2, XPD(s1, s2, f1, f2)) \
40 VARITEM(3, 2, XPD(s1, s2, s3, f1, f2)) \
41 VARITEM(4, 2, XPD(s1, s2, s3, s4, f1, f2)) \
42 VARITEM(0, 3, XPD(f1, f2, f3)) \
43 VARITEM(1, 3, XPD(s1, f1, f2, f3)) \
44 VARITEM(2, 3, XPD(s1, s2, f1, f2, f3)) \
45 VARITEM(3, 3, XPD(s1, s2, s3, f1, f2, f3)) \
46 VARITEM(4, 3, XPD(s1, s2, s3, s4, f1, f2, f3)) \
47 VARITEM(0, 4, XPD(f1, f2, f3, f4)) \
48 VARITEM(1, 4, XPD(s1, f1, f2, f3, f4)) \
49 VARITEM(2, 4, XPD(s1, s2, f1, f2, f3, f4)) \
50 VARITEM(3, 4, XPD(s1, s2, s3, f1, f2, f3, f4)) \
51 VARITEM(4, 4, XPD(s1, s2, s3, s4, f1, f2, f3, f4))
53 void Destroy_All_Notifications();
54 void Create_Notification_Entity(
67 /* MSG_INFO & MSG_CENTER */
86 void Dump_Notifications(float fh, float alsoprint);
89 GENERIC_COMMAND(dumpnotifs, "Dump all notifications into notifications_dump.txt")
93 case CMD_REQUEST_COMMAND:
96 float fh, alsoprint = false;
97 string filename = argv(1);
101 filename = "notifications_dump.cfg";
104 else if(filename == "-")
106 filename = "notifications_dump.cfg";
109 fh = fopen(filename, FILE_WRITE);
113 Dump_Notifications(fh, alsoprint);
114 LOG_INFOF("Dumping notifications... File located in ^2data/data/%s^7.\n", filename);
119 LOG_INFOF("^1Error: ^7Could not open file '%s'!\n", filename);
122 LOG_INFO(_("Notification dump command only works with cl_cmd and sv_cmd.\n"));
128 case CMD_REQUEST_USAGE:
130 LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpnotifs [filename]"));
131 LOG_INFO(" Where 'filename' is the file to write (default is notifications_dump.cfg),\n");
132 LOG_INFO(" if supplied with '-' output to console as well as default,\n");
133 LOG_INFO(" if left blank, it will only write to default.\n");
139 #ifdef NOTIFICATIONS_DEBUG
140 void Debug_Notification(string input);
143 void Local_Notification(int net_type, int net_name, ...count);
144 void Local_Notification_WOVA(
145 float net_type, float net_name,
146 float stringcount, float floatcount,
147 string s1, string s2, string s3, string s4,
148 float f1, float f2, float f3, float f4);
150 #ifdef CSQC // CLIENT ONLY
151 void Read_Notification(float is_new);
152 string prev_soundfile;
153 float prev_soundtime;
156 #ifdef SVQC // SERVER ONLY
157 const float NOTIF_ONE = 1;
158 const float NOTIF_ONE_ONLY = 2;
159 const float NOTIF_TEAM = 3;
160 const float NOTIF_TEAM_EXCEPT = 4;
161 const float NOTIF_ALL = 5;
162 const float NOTIF_ALL_EXCEPT = 6;
164 void Kill_Notification(
165 float broadcast, entity client,
166 float net_type, float net_name);
167 void Send_Notification(
168 float broadcast, entity client,
169 float net_type, float net_name,
171 void Send_Notification_WOVA(
172 float broadcast, entity client,
173 float net_type, float net_name,
174 float stringcount, float floatcount,
175 string s1, string s2, string s3, string s4,
176 float f1, float f2, float f3, float f4);
177 void Send_Notification_WOCOVA(
178 float broadcast, entity client,
179 float net_type, float net_name,
180 string s1, string s2, string s3, string s4,
181 float f1, float f2, float f3, float f4);
184 // ===========================
185 // Special CVAR Declarations
186 // ===========================
188 // MAKE SURE THIS IS ALWAYS SYNCHRONIZED WITH THE DUMP
189 // NOTIFICATIONS FUNCTION IN THE .QC FILE!
191 #define NOTIF_ADD_AUTOCVAR(name,default) float autocvar_notification_##name = default;
193 float autocvar_notification_show_location = false;
194 string autocvar_notification_show_location_string = ""; //_(" at the %s");
195 float autocvar_notification_show_sprees = true;
196 float autocvar_notification_show_sprees_info = 3; // 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker
197 float autocvar_notification_show_sprees_info_newline = true;
198 float autocvar_notification_show_sprees_info_specialonly = true;
199 float autocvar_notification_errors_are_fatal = true;
200 float autocvar_notification_lifetime_runtime = 0.5;
201 float autocvar_notification_lifetime_mapload = 10;
202 float autocvar_notification_debug = false;
206 void Notification_GetCvars();
207 float autocvar_notification_server_allows_location = 1; // 0 = no, 1 = yes
209 float autocvar_notification_item_centerprinttime = 1.5;
211 // 0 = no, 1 = yes, 2 = forced on for all MSG_INFO notifs
212 // DISABLED IN CODE, BUT ENABLED IN CONFIG FOR COMPATIBILITY WITH OLD CLIENTS
213 float autocvar_notification_allow_chatboxprint = 0;
215 float autocvar_notification_show_sprees_center = true;
216 float autocvar_notification_show_sprees_center_specialonly = true;
220 // ============================
221 // Notification Argument List
222 // ============================
224 These arguments get replaced with the Local_Notification_sprintf
225 and other such functions found in notifications.qc to supply data
226 from networked notifications to their usage in sprintf... It
227 allows for more dynamic data to be inferred by the local
228 notification parser, so that the server does not have to network
229 anything too crazy on a per-client/per-situation basis.
231 Pay attention to the CSQC/SVQC relations, some of these are redefined
232 in slightly different ways for different programs, this is because the
233 server does a more conservative approach to the notifs than the client.
235 All arguments are swapped into strings, so be sure that your
236 sprintf usage matches with proper %s placement.
238 Argument descriptions:
239 s1-s4: string arguments to be literally swapped into sprintf
240 s2loc: s2 string of locations of deaths or other events
241 s3loc: s3 string of locations of deaths or other events
242 f1-f4: float arguments expanded into strings to be swapped into sprintf
243 f1p2dec: f1 float to string with 2 decimal places
244 f2p2dec: f2 float to string with 2 decimal places
245 f2primsec: f2 float primary or secondary selection for weapons
246 f3primsec: f3 float primary or secondary selection for weapons
247 f1secs: count_seconds of f1
248 f1ord: count_ordinal of f1
249 f1time: process_time of f1
250 f1race_time: mmssss of f1
251 f2race_time: mmssss of f2
252 race_col: color of race time/position (i.e. good or bad)
253 race_diff: show time difference between f2 and f3
254 missing_teams: show which teams still need players
255 pass_key: find the keybind for "passing" or "dropping" in CTF game mode
256 frag_ping: show the ping of a player
257 frag_stats: show health/armor/ping of a player
258 frag_pos: show score status and position in the match of a player
259 spree_cen: centerprint notif for kill spree/how many kills they have
260 spree_inf: info notif for kill spree/how many kills they have
261 spree_end: placed at the end of murder messages to show ending of sprees
262 spree_lost: placed at the end of suicide messages to show losing of sprees
263 item_wepname: return full name of a weapon from weaponid
264 item_wepammo: ammo display for weapon from string
265 item_centime: amount of time to display weapon message in centerprint
266 item_buffname: return full name of a buff from buffid
267 death_team: show the full name of the team a player is switching from
268 minigame1_name: return human readable name of a minigame from its id(s1)
269 minigame1_d: return descriptor name of a minigame from its id(s1)
272 const float NOTIF_MAX_ARGS = 7;
273 const float NOTIF_MAX_HUDARGS = 2;
274 const float NOTIF_MAX_DURCNT = 2;
276 string arg_slot[NOTIF_MAX_ARGS];
278 const float ARG_CS_SV_HA = 1; // enabled on CSQC, SVQC, and Hudargs
279 const float ARG_CS_SV_DC = 2; // enabled on CSQC, SVQC, and durcnt centerprint
280 const float ARG_CS_SV = 3; // enabled on CSQC and SVQC
281 const float ARG_CS = 4; // unique result to CSQC
282 const float ARG_SV = 5; // unique result to SVQC
283 const float ARG_DC = 6; // unique result to durcnt/centerprint
285 // todo possible idea.... declare how many floats/strings each arg needs, and then dynamically increment the input
286 // this way, we don't need to have duplicates like i.e. s2loc and s3loc?
288 #define NOTIF_ARGUMENT_LIST \
289 ARG_CASE(ARG_CS_SV_HA, "s1", s1) \
290 ARG_CASE(ARG_CS_SV_HA, "s2", s2) \
291 ARG_CASE(ARG_CS_SV_HA, "s3", s3) \
292 ARG_CASE(ARG_CS_SV_HA, "s4", s4) \
293 ARG_CASE(ARG_CS_SV, "s2loc", ((autocvar_notification_show_location && (s2 != "")) ? sprintf(( ((tmp_s = autocvar_notification_show_location_string) != "") ? tmp_s : _(" (near %s)") ), s2) : "")) \
294 ARG_CASE(ARG_CS_SV, "s3loc", ((autocvar_notification_show_location && (s3 != "")) ? sprintf(( ((tmp_s = autocvar_notification_show_location_string) != "") ? tmp_s : _(" (near %s)") ), s3) : "")) \
295 ARG_CASE(ARG_CS_SV_DC, "f1", ftos(f1)) \
296 ARG_CASE(ARG_CS_SV_DC, "f2", ftos(f2)) \
297 ARG_CASE(ARG_CS_SV, "f3", ftos(f3)) \
298 ARG_CASE(ARG_CS_SV, "f4", ftos(f4)) \
299 ARG_CASE(ARG_CS_SV, "f1p2dec", ftos_decimals(f1/100, 2)) \
300 ARG_CASE(ARG_CS_SV, "f2p2dec", ftos_decimals(f2/100, 2)) \
301 ARG_CASE(ARG_CS, "f2primsec", (f2 ? _("secondary") : _("primary"))) \
302 ARG_CASE(ARG_CS, "f3primsec", (f3 ? _("secondary") : _("primary"))) \
303 ARG_CASE(ARG_CS, "f1secs", count_seconds(f1)) \
304 ARG_CASE(ARG_CS_SV, "f1ord", count_ordinal(f1)) \
305 ARG_CASE(ARG_CS, "f1time", process_time(2, f1)) \
306 ARG_CASE(ARG_CS_SV_HA, "f1race_time", mmssss(f1)) \
307 ARG_CASE(ARG_CS_SV_HA, "f2race_time", mmssss(f2)) \
308 ARG_CASE(ARG_CS_SV_HA, "f3race_time", mmssss(f3)) \
309 ARG_CASE(ARG_CS_SV, "race_col", CCR(((f1 == 1) ? "^F1" : "^F2"))) \
310 ARG_CASE(ARG_CS_SV, "race_diff", ((f2 > f3) ? sprintf(CCR("^1[+%s]"), mmssss(f2 - f3)) : sprintf(CCR("^2[-%s]"), mmssss(f3 - f2)))) \
311 ARG_CASE(ARG_CS, "missing_teams", notif_arg_missing_teams(f1)) \
312 ARG_CASE(ARG_CS, "pass_key", ((((tmp_s = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(tmp_s, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), tmp_s) : "")) \
313 ARG_CASE(ARG_CS, "frag_ping", notif_arg_frag_ping(true, f2)) \
314 ARG_CASE(ARG_CS, "frag_stats", notif_arg_frag_stats(f2, f3, f4)) \
315 /*ARG_CASE(ARG_CS, "frag_pos", ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))*/ \
316 ARG_CASE(ARG_CS, "spree_cen", (autocvar_notification_show_sprees ? notif_arg_spree_cen(f1) : "")) \
317 ARG_CASE(ARG_CS_SV, "spree_inf", (autocvar_notification_show_sprees ? notif_arg_spree_inf(1, input, s2, f2) : "")) \
318 ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
319 ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \
320 ARG_CASE(ARG_CS_SV, "item_wepname", WEP_NAME(f1)) \
321 ARG_CASE(ARG_CS_SV, "item_buffname", sprintf("%s%s", rgb_to_hexcolor(Buffs_from(f1).m_color), Buffs_from(f1).m_prettyName)) \
322 ARG_CASE(ARG_CS_SV, "f3buffname", sprintf("%s%s", rgb_to_hexcolor(Buffs_from(f3).m_color), Buffs_from(f3).m_prettyName)) \
323 ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
324 ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \
325 ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \
326 ARG_CASE(ARG_CS, "death_team", Team_ColoredFullName(f1 - 1)) \
327 ARG_CASE(ARG_CS_SV_HA, "minigame1_name",find(world,netname,s1).descriptor.message) \
328 ARG_CASE(ARG_CS_SV_HA, "minigame1_d", find(world,netname,s1).descriptor.netname)
330 #define NOTIF_HIT_MAX(count,funcname) do { \
331 if(sel_num == count) { backtrace(sprintf("%s: Hit maximum arguments!\n", funcname)); break; } \
333 #define NOTIF_HIT_UNKNOWN(token,funcname) { backtrace(sprintf("%s: Hit unknown token in selected string! '%s'\n", funcname, selected)); break; }
335 #define KILL_SPREE_LIST \
336 SPREE_ITEM(3, 03, _("TRIPLE FRAG! "), _("%s^K1 made a TRIPLE FRAG! %s^BG"), _("%s^K1 made a TRIPLE SCORE! %s^BG")) \
337 SPREE_ITEM(5, 05, _("RAGE! "), _("%s^K1 unlocked RAGE! %s^BG"), _("%s^K1 made FIVE SCORES IN A ROW! %s^BG")) \
338 SPREE_ITEM(10, 10, _("MASSACRE! "), _("%s^K1 started a MASSACRE! %s^BG"), _("%s^K1 made TEN SCORES IN A ROW! %s^BG")) \
339 SPREE_ITEM(15, 15, _("MAYHEM! "), _("%s^K1 executed MAYHEM! %s^BG"), _("%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG")) \
340 SPREE_ITEM(20, 20, _("BERSERKER! "), _("%s^K1 is a BERSERKER! %s^BG"), _("%s^K1 made TWENTY SCORES IN A ROW! %s^BG")) \
341 SPREE_ITEM(25, 25, _("CARNAGE! "), _("%s^K1 inflicts CARNAGE! %s^BG"), _("%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG")) \
342 SPREE_ITEM(30, 30, _("ARMAGEDDON! "), _("%s^K1 unleashes ARMAGEDDON! %s^BG"), _("%s^K1 made THIRTY SCORES IN A ROW! %s^BG"))
345 string notif_arg_frag_ping(float newline, float fping)
348 return sprintf(CCR(_("%s(^F1Bot^BG)")), (newline ? "\n" : " "));
350 return sprintf(CCR(_("%s(Ping ^F1%d^BG)")), (newline ? "\n" : " "), fping);
353 string notif_arg_frag_stats(float fhealth, float farmor, float fping)
356 return sprintf(CCR(_("\n(Health ^1%d^BG / Armor ^2%d^BG)%s")), fhealth, farmor, notif_arg_frag_ping(false, fping));
358 return sprintf(CCR(_("\n(^F4Dead^BG)%s")), notif_arg_frag_ping(false, fping));
361 string notif_arg_missing_teams(float f1)
363 return sprintf("%s%s%s%s",
365 sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_1), ((f1 & (2 + 4 + 8)) ? ", " : ""))
370 sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_2), ((f1 & (4 + 8)) ? ", " : ""))
375 sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_3), ((f1 & 8) ? ", " : ""))
380 Team_ColoredFullName(NUM_TEAM_4)
387 string notif_arg_spree_cen(float spree)
389 // 0 = off, 1 = target (but only for first victim) and attacker
390 if(autocvar_notification_show_sprees_center)
394 #define SPREE_ITEM(counta,countb,center,normal,gentle) \
395 case counta: { return normal_or_gentle(center, sprintf(_("%d score spree! "), spree)); }
402 if (!autocvar_notification_show_sprees_center_specialonly)
407 _("%d frag spree! "),
408 _("%d score spree! ")
412 else { return ""; } // don't show spree information if it isn't an achievement
418 else if(spree == -1) // first blood
420 return normal_or_gentle(_("First blood! "), _("First score! "));
422 else if(spree == -2) // first victim
424 return normal_or_gentle(_("First victim! "), _("First casualty! "));
431 string notif_arg_spree_inf(float type, string input, string player, float spree)
435 case 1: // attacker kill spree
437 // 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker
438 // this conditional (& 2) is true for 2 and 3
439 if(autocvar_notification_show_sprees_info & 2)
442 string spree_newline =
443 ( autocvar_notification_show_sprees_info_newline ?
444 ((substring(input, 0, 1) == "\{3}") ? "\n\{3}" : "\n") : "" );
446 string spree_newline =
447 (autocvar_notification_show_sprees_info_newline ? "\n" : "");
452 #define SPREE_ITEM(counta,countb,center,normal,gentle) \
453 case counta: { return sprintf(CCR(normal_or_gentle(normal, gentle)), player, spree_newline); }
460 if (!autocvar_notification_show_sprees_info_specialonly)
464 CCR(normal_or_gentle(
465 _("%s^K1 has %d frags in a row! %s^BG"),
466 _("%s^K1 made %d scores in a row! %s^BG")
473 else { return ""; } // don't show spree information if it isn't an achievement
479 else if(spree == -1) // firstblood
483 CCR(normal_or_gentle(
484 _("%s^K1 drew first blood! %s^BG"),
485 _("%s^K1 got the first score! %s^BG")
495 case -1: // kill spree ended
497 if((spree > 1) && (autocvar_notification_show_sprees_info & 1))
500 sprintf(normal_or_gentle(
501 _(", ending their %d frag spree"),
502 _(", ending their %d score spree")
510 case -2: // kill spree lost
512 if((spree > 1) && (autocvar_notification_show_sprees_info & 1))
515 sprintf(normal_or_gentle(
516 _(", losing their %d frag spree"),
517 _(", losing their %d score spree")
529 // ====================================
530 // Initialization/Create Declarations
531 // ====================================
552 , CPID_MISSING_PLAYERS
553 , CPID_INSTAGIB_FINDAMMO
560 , CPID_RACE_FINISHLAP
564 , CPID_VEHICLES_OTHER
568 // notification counts
569 const float NOTIF_FIRST = 1;
570 float NOTIF_ANNCE_COUNT;
571 float NOTIF_INFO_COUNT;
572 float NOTIF_CENTER_COUNT;
573 float NOTIF_MULTI_COUNT;
574 float NOTIF_CHOICE_COUNT;
576 // notification limits -- INCREASE AS NECESSARY
577 const float NOTIF_ANNCE_MAX = 400;
578 const float NOTIF_INFO_MAX = 450;
579 const float NOTIF_CENTER_MAX = 350;
580 const float NOTIF_MULTI_MAX = 300;
581 const float NOTIF_CHOICE_MAX = 50;
583 // notification entities
584 entity msg_annce_notifs[NOTIF_ANNCE_MAX];
585 entity msg_info_notifs[NOTIF_INFO_MAX];
586 entity msg_center_notifs[NOTIF_CENTER_MAX];
587 entity msg_multi_notifs[NOTIF_MULTI_MAX];
588 entity msg_choice_notifs[NOTIF_CHOICE_MAX];
590 // common notification entity values
596 .int nent_stringcount;
597 .int nent_floatcount;
599 // MSG_ANNCE entity values
603 .float nent_position;
605 // MSG_INFO and MSG_CENTER entity values
606 .string nent_args; // used by both
607 .string nent_hudargs; // used by info
608 .string nent_icon; // used by info
609 .float nent_cpid; // used by center
610 .string nent_durcnt; // used by center
611 .string nent_string; // used by both
613 // MSG_MULTI entity values
614 .entity nent_msgannce;
615 .entity nent_msginfo;
616 .entity nent_msgcenter;
618 // MSG_CHOICE entity values
619 .float nent_challow_def;
620 .float nent_challow_var;
621 .entity nent_optiona;
622 .entity nent_optionb;
624 // networked notification entity values
625 .float nent_broadcast;
627 .float nent_net_type;
628 .float nent_net_name;
629 .string nent_strings[4];
630 .float nent_floats[4];
632 // other notification properties
633 .float msg_choice_choices[NOTIF_CHOICE_MAX]; // set on each player containing MSG_CHOICE choices
635 // initialization error detection
637 float notif_global_error;
639 #define MSG_ANNCE_NOTIF(default,name,channel,sound,volume,position) \
640 NOTIF_ADD_AUTOCVAR(name, default) \
642 void RegisterNotification_##name() \
644 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_ANNCE_COUNT) \
645 CHECK_MAX_COUNT(name, NOTIF_ANNCE_MAX, NOTIF_ANNCE_COUNT, "MSG_ANNCE") \
646 Create_Notification_Entity( \
647 /* COMMON ======================== */ \
648 default, /* var_default */ \
649 ACVNN(name), /* var_cvar */ \
650 MSG_ANNCE, /* typeId */ \
652 strtoupper(#name), /* namestring */ \
653 NO_MSG, /* strnum */ \
654 NO_MSG, /* flnum */ \
655 /* ANNCE ============= */ \
656 channel, /* channel */ \
659 position, /* position */ \
660 /* INFO & CENTER == */ \
668 /* MULTI ============= */ \
669 NO_MSG, /* anncename */ \
670 NO_MSG, /* infoname */ \
671 NO_MSG, /* centername */ \
672 /* MSG_CHOICE ========== */ \
673 NO_MSG, /* challow_def */ \
674 NO_MSG, /* challow_var */ \
675 NO_MSG, /* chtype */ \
676 NO_MSG, /* optiona */ \
677 NO_MSG); /* optionb */ \
679 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
681 #define MSG_INFO_NOTIF(default,name,strnum,flnum,args,hudargs,icon,normal,gentle) \
682 NOTIF_ADD_AUTOCVAR(name, default) \
684 void RegisterNotification_##name() \
686 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
687 CHECK_MAX_COUNT(name, NOTIF_INFO_MAX, NOTIF_INFO_COUNT, "MSG_INFO") \
688 Create_Notification_Entity( \
689 /* COMMON ======================== */ \
690 default, /* var_default */ \
691 ACVNN(name), /* var_cvar */ \
692 MSG_INFO, /* typeId */ \
694 strtoupper(#name), /* namestring */ \
695 strnum, /* strnum */ \
697 /* ANNCE =========== */ \
698 NO_MSG, /* channel */ \
701 NO_MSG, /* position */ \
702 /* INFO & CENTER === */ \
704 hudargs, /* hudargs */ \
708 normal, /* normal */ \
709 gentle, /* gentle */ \
710 /* MULTI ============= */ \
711 NO_MSG, /* anncename */ \
712 NO_MSG, /* infoname */ \
713 NO_MSG, /* centername */ \
714 /* CHOICE ============== */ \
715 NO_MSG, /* challow_def */ \
716 NO_MSG, /* challow_var */ \
717 NO_MSG, /* chtype */ \
718 NO_MSG, /* optiona */ \
719 NO_MSG); /* optionb */ \
721 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
723 .string nent_iconargs;
724 #define MULTIICON_INFO(default,name,strnum,flnum,args,hudargs,iconargs,icon,normal,gentle) \
725 NOTIF_ADD_AUTOCVAR(name, default) \
727 void RegisterNotification_##name() \
729 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
730 CHECK_MAX_COUNT(name, NOTIF_INFO_MAX, NOTIF_INFO_COUNT, "MSG_INFO") \
731 Create_Notification_Entity( \
732 /* COMMON ======================== */ \
733 default, /* var_default */ \
734 ACVNN(name), /* var_cvar */ \
735 MSG_INFO, /* typeid */ \
737 strtoupper(#name), /* namestring */ \
738 strnum, /* strnum */ \
740 /* ANNCE =========== */ \
741 NO_MSG, /* channel */ \
744 NO_MSG, /* position */ \
745 /* INFO & CENTER === */ \
747 hudargs, /* hudargs */ \
751 normal, /* normal */ \
752 gentle, /* gentle */ \
753 /* MULTI ============= */ \
754 NO_MSG, /* anncename */ \
755 NO_MSG, /* infoname */ \
756 NO_MSG, /* centername */ \
757 /* CHOICE ============== */ \
758 NO_MSG, /* challow_def */ \
759 NO_MSG, /* challow_var */ \
760 NO_MSG, /* chtype */ \
761 NO_MSG, /* optiona */ \
762 NO_MSG); /* optionb */ \
763 msg_info_notifs[name - 1].nent_iconargs = iconargs; \
765 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
767 #define MSG_CENTER_NOTIF(default,name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
768 NOTIF_ADD_AUTOCVAR(name, default) \
770 void RegisterNotification_##name() \
772 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
773 CHECK_MAX_COUNT(name, NOTIF_CENTER_MAX, NOTIF_CENTER_COUNT, "MSG_CENTER") \
774 Create_Notification_Entity( \
775 /* COMMON ======================== */ \
776 default, /* var_default */ \
777 ACVNN(name), /* var_cvar */ \
778 MSG_CENTER, /* typeId */ \
780 strtoupper(#name), /* namestring */ \
781 strnum, /* strnum */ \
783 /* ANNCE =========== */ \
784 NO_MSG, /* channel */ \
787 NO_MSG, /* position */ \
788 /* INFO & CENTER == */ \
793 durcnt, /* durcnt */ \
794 normal, /* normal */ \
795 gentle, /* gentle */ \
796 /* MULTI ============= */ \
797 NO_MSG, /* anncename */ \
798 NO_MSG, /* infoname */ \
799 NO_MSG, /* centername */ \
800 /* CHOICE ============== */ \
801 NO_MSG, /* challow_def */ \
802 NO_MSG, /* challow_var */ \
803 NO_MSG, /* chtype */ \
804 NO_MSG, /* optiona */ \
805 NO_MSG); /* optionb */ \
807 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
809 #define MSG_MULTI_NOTIF(default,name,anncename,infoname,centername) \
810 NOTIF_ADD_AUTOCVAR(name, default) \
812 void RegisterNotification_##name() \
814 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_MULTI_COUNT) \
815 CHECK_MAX_COUNT(name, NOTIF_MULTI_MAX, NOTIF_MULTI_COUNT, "MSG_MULTI") \
816 Create_Notification_Entity( \
817 /* COMMON ======================== */ \
818 default, /* var_default */ \
819 ACVNN(name), /* var_cvar */ \
820 MSG_MULTI, /* typeId */ \
822 strtoupper(#name), /* namestring */ \
823 NO_MSG, /* strnum */ \
824 NO_MSG, /* flnum */ \
825 /* ANNCE =========== */ \
826 NO_MSG, /* channel */ \
829 NO_MSG, /* position */ \
830 /* INFO & CENTER == */ \
838 /* MULTI ================= */ \
839 anncename, /* anncename */ \
840 infoname, /* infoname */ \
841 centername, /* centername */ \
842 /* CHOICE ============== */ \
843 NO_MSG, /* challow_def */ \
844 NO_MSG, /* challow_var */ \
845 NO_MSG, /* chtype */ \
846 NO_MSG, /* optiona */ \
847 NO_MSG); /* optionb */ \
849 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
851 #define ACVNN(name) autocvar_notification_##name
853 #define MSG_CHOICE_NOTIF(default,challow,name,chtype,optiona,optionb) \
854 NOTIF_ADD_AUTOCVAR(name, default) \
855 NOTIF_ADD_AUTOCVAR(name##_ALLOWED, challow) \
857 void RegisterNotification_##name() \
859 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CHOICE_COUNT) \
860 CHECK_MAX_COUNT(name, NOTIF_CHOICE_MAX, NOTIF_CHOICE_COUNT, "MSG_CHOICE") \
861 Create_Notification_Entity( \
862 /* COMMON ======================== */ \
863 default, /* var_default */ \
864 ACVNN(name), /* var_cvar */ \
865 MSG_CHOICE, /* typeId */ \
867 strtoupper(#name), /* namestring */ \
868 NO_MSG, /* strnum */ \
869 NO_MSG, /* flnum */ \
870 /* ANNCE =========== */ \
871 NO_MSG, /* channel */ \
874 NO_MSG, /* position */ \
875 /* INFO & CENTER == */ \
883 /* MULTI ============= */ \
884 NO_MSG, /* anncename */ \
885 NO_MSG, /* infoname */ \
886 NO_MSG, /* centername */ \
887 /* CHOICE ============================================= */ \
888 challow, /* challow_def */ \
889 autocvar_notification_##name##_ALLOWED, /* challow_var */ \
890 chtype, /* chtype */ \
891 optiona, /* optiona */ \
892 optionb); /* optionb */ \
894 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
896 void RegisterNotifications_First()
898 notif_global_error = false;
901 #define dedi (server_is_dedicated ? "a dedicated " : "")
906 LOG_INFOF("Beginning notification initialization on %s%s program...\n", dedi, PROGNAME);
909 // maybe do another implementation of this with checksums? for now, we don't need versioning
910 /*if(autocvar_notification_version != NOTIF_VERSION)
913 if(autocvar_notification_version_mismatch_client_error)
915 if(autocvar_notification_version_mismatch_server_error)
917 notif_global_error = true;
919 printf("^1NOTIFICATION VERSION MISMATCH: ^7program = %s, config = %d, code = %d.\n",
920 PROGNAME, autocvar_notification_version, NOTIF_VERSION);
924 void RegisterNotifications_Done()
926 if(notif_global_error)
928 // shit happened... stop the loading of the program now if this is unacceptable
929 if(autocvar_notification_errors_are_fatal)
930 error("Notification initialization failed! Read above and fix the errors!\n");
932 LOG_INFO("Notification initialization failed! Read above and fix the errors!\n");
934 else { LOG_INFO("Notification initialization successful!\n"); }
937 // NOW we actually activate the declarations
938 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotifications_First)
939 #include "notifications.inc"
940 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotifications_Done)
942 STATIC_INIT(RegisterNotifications) { CALL_ACCUMULATED_FUNCTION(RegisterNotifications); }