1 #ifndef NOTIFICATIONS_H
2 #define NOTIFICATIONS_H
4 #include <common/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(entity notif,
60 void Create_Notification_Entity_Annce(entity notif,
69 void Create_Notification_Entity_InfoCenter(entity notif,
74 /* MSG_INFO & MSG_CENTER */
83 void Create_Notification_Entity_Multi(entity notif,
91 void Create_Notification_Entity_Choice(entity notif,
101 void Dump_Notifications(float fh, float alsoprint);
104 GENERIC_COMMAND(dumpnotifs, "Dump all notifications into notifications_dump.txt")
108 case CMD_REQUEST_COMMAND:
111 float fh, alsoprint = false;
112 string filename = argv(1);
116 filename = "notifications_dump.cfg";
119 else if(filename == "-")
121 filename = "notifications_dump.cfg";
124 fh = fopen(filename, FILE_WRITE);
128 Dump_Notifications(fh, alsoprint);
129 LOG_INFOF("Dumping notifications... File located in ^2data/data/%s^7.\n", filename);
134 LOG_INFOF("^1Error: ^7Could not open file '%s'!\n", filename);
137 LOG_INFO(_("Notification dump command only works with cl_cmd and sv_cmd.\n"));
143 case CMD_REQUEST_USAGE:
145 LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpnotifs [filename]"));
146 LOG_INFO(" Where 'filename' is the file to write (default is notifications_dump.cfg),\n");
147 LOG_INFO(" if supplied with '-' output to console as well as default,\n");
148 LOG_INFO(" if left blank, it will only write to default.\n");
154 #ifdef NOTIFICATIONS_DEBUG
155 void Debug_Notification(string input);
158 void Local_Notification(int net_type, int net_name, ...count);
159 void Local_Notification_WOVA(
160 float net_type, float net_name,
161 float stringcount, float floatcount,
162 string s1, string s2, string s3, string s4,
163 float f1, float f2, float f3, float f4);
165 #ifdef CSQC // CLIENT ONLY
166 string prev_soundfile;
167 float prev_soundtime;
170 #ifdef SVQC // SERVER ONLY
171 const float NOTIF_ONE = 1;
172 const float NOTIF_ONE_ONLY = 2;
173 const float NOTIF_TEAM = 3;
174 const float NOTIF_TEAM_EXCEPT = 4;
175 const float NOTIF_ALL = 5;
176 const float NOTIF_ALL_EXCEPT = 6;
178 void Kill_Notification(
179 float broadcast, entity client,
180 float net_type, float net_name);
181 void Send_Notification(
182 float broadcast, entity client,
183 float net_type, float net_name,
185 void Send_Notification_WOVA(
186 float broadcast, entity client,
187 float net_type, float net_name,
188 float stringcount, float floatcount,
189 string s1, string s2, string s3, string s4,
190 float f1, float f2, float f3, float f4);
191 void Send_Notification_WOCOVA(
192 float broadcast, entity client,
193 float net_type, float net_name,
194 string s1, string s2, string s3, string s4,
195 float f1, float f2, float f3, float f4);
198 // ===========================
199 // Special CVAR Declarations
200 // ===========================
202 // MAKE SURE THIS IS ALWAYS SYNCHRONIZED WITH THE DUMP
203 // NOTIFICATIONS FUNCTION IN THE .QC FILE!
205 #define NOTIF_ADD_AUTOCVAR(name,default) float autocvar_notification_##name = default;
207 float autocvar_notification_show_location = false;
208 string autocvar_notification_show_location_string = ""; //_(" at the %s");
209 float autocvar_notification_show_sprees = true;
210 float autocvar_notification_show_sprees_info = 3; // 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker
211 float autocvar_notification_show_sprees_info_newline = true;
212 float autocvar_notification_show_sprees_info_specialonly = true;
213 float autocvar_notification_errors_are_fatal = true;
214 float autocvar_notification_lifetime_runtime = 0.5;
215 float autocvar_notification_lifetime_mapload = 10;
216 float autocvar_notification_debug = false;
220 void Notification_GetCvars();
221 float autocvar_notification_server_allows_location = 1; // 0 = no, 1 = yes
223 float autocvar_notification_item_centerprinttime = 1.5;
225 // 0 = no, 1 = yes, 2 = forced on for all MSG_INFO notifs
226 // DISABLED IN CODE, BUT ENABLED IN CONFIG FOR COMPATIBILITY WITH OLD CLIENTS
227 float autocvar_notification_allow_chatboxprint = 0;
229 float autocvar_notification_show_sprees_center = true;
230 float autocvar_notification_show_sprees_center_specialonly = true;
234 // ============================
235 // Notification Argument List
236 // ============================
238 These arguments get replaced with the Local_Notification_sprintf
239 and other such functions found in notifications.qc to supply data
240 from networked notifications to their usage in sprintf... It
241 allows for more dynamic data to be inferred by the local
242 notification parser, so that the server does not have to network
243 anything too crazy on a per-client/per-situation basis.
245 Pay attention to the CSQC/SVQC relations, some of these are redefined
246 in slightly different ways for different programs, this is because the
247 server does a more conservative approach to the notifs than the client.
249 All arguments are swapped into strings, so be sure that your
250 sprintf usage matches with proper %s placement.
252 Argument descriptions:
253 s1-s4: string arguments to be literally swapped into sprintf
254 s2loc: s2 string of locations of deaths or other events
255 s3loc: s3 string of locations of deaths or other events
256 f1-f4: float arguments expanded into strings to be swapped into sprintf
257 f1p2dec: f1 float to string with 2 decimal places
258 f2p2dec: f2 float to string with 2 decimal places
259 f2primsec: f2 float primary or secondary selection for weapons
260 f3primsec: f3 float primary or secondary selection for weapons
261 f1secs: count_seconds of f1
262 f1points: point or points depending on f1
263 f1ord: count_ordinal of f1
264 f1time: process_time of f1
265 f1race_time: mmssss of f1
266 f2race_time: mmssss of f2
267 race_col: color of race time/position (i.e. good or bad)
268 race_diff: show time difference between f2 and f3
269 missing_teams: show which teams still need players
270 pass_key: find the keybind for "passing" or "dropping" in CTF game mode
271 frag_ping: show the ping of a player
272 frag_stats: show health/armor/ping of a player
273 frag_pos: show score status and position in the match of a player
274 spree_cen: centerprint notif for kill spree/how many kills they have
275 spree_inf: info notif for kill spree/how many kills they have
276 spree_end: placed at the end of murder messages to show ending of sprees
277 spree_lost: placed at the end of suicide messages to show losing of sprees
278 item_wepname: return full name of a weapon from weaponid
279 item_wepammo: ammo display for weapon from string
280 item_centime: amount of time to display weapon message in centerprint
281 item_buffname: return full name of a buff from buffid
282 death_team: show the full name of the team a player is switching from
283 minigame1_name: return human readable name of a minigame from its id(s1)
284 minigame1_d: return descriptor name of a minigame from its id(s1)
287 const float NOTIF_MAX_ARGS = 7;
288 const float NOTIF_MAX_HUDARGS = 2;
289 const float NOTIF_MAX_DURCNT = 2;
291 string arg_slot[NOTIF_MAX_ARGS];
293 const float ARG_CS_SV_HA = 1; // enabled on CSQC, SVQC, and Hudargs
294 const float ARG_CS_SV_DC = 2; // enabled on CSQC, SVQC, and durcnt centerprint
295 const float ARG_CS_SV = 3; // enabled on CSQC and SVQC
296 const float ARG_CS = 4; // unique result to CSQC
297 const float ARG_SV = 5; // unique result to SVQC
298 const float ARG_DC = 6; // unique result to durcnt/centerprint
300 // todo possible idea.... declare how many floats/strings each arg needs, and then dynamically increment the input
301 // this way, we don't need to have duplicates like i.e. s2loc and s3loc?
303 string BUFF_NAME(int i);
305 #define NOTIF_ARGUMENT_LIST \
306 ARG_CASE(ARG_CS_SV_HA, "s1", s1) \
307 ARG_CASE(ARG_CS_SV_HA, "s2", s2) \
308 ARG_CASE(ARG_CS_SV_HA, "s3", s3) \
309 ARG_CASE(ARG_CS_SV_HA, "s4", s4) \
310 ARG_CASE(ARG_CS_SV, "s2loc", ((autocvar_notification_show_location && (s2 != "")) ? sprintf(( ((tmp_s = autocvar_notification_show_location_string) != "") ? tmp_s : _(" (near %s)") ), s2) : "")) \
311 ARG_CASE(ARG_CS_SV, "s3loc", ((autocvar_notification_show_location && (s3 != "")) ? sprintf(( ((tmp_s = autocvar_notification_show_location_string) != "") ? tmp_s : _(" (near %s)") ), s3) : "")) \
312 ARG_CASE(ARG_CS_SV_DC, "f1", ftos(f1)) \
313 ARG_CASE(ARG_CS_SV_DC, "f2", ftos(f2)) \
314 ARG_CASE(ARG_CS_SV, "f3", ftos(f3)) \
315 ARG_CASE(ARG_CS_SV, "f4", ftos(f4)) \
316 ARG_CASE(ARG_CS_SV, "f1p2dec", ftos_decimals(f1/100, 2)) \
317 ARG_CASE(ARG_CS_SV, "f2p2dec", ftos_decimals(f2/100, 2)) \
318 ARG_CASE(ARG_CS, "f2primsec", (f2 ? _("secondary") : _("primary"))) \
319 ARG_CASE(ARG_CS, "f3primsec", (f3 ? _("secondary") : _("primary"))) \
320 ARG_CASE(ARG_CS, "f1secs", count_seconds(f1)) \
321 ARG_CASE(ARG_CS, "f1points", (f1 == 1 ? _("point") : _("points"))) \
322 ARG_CASE(ARG_CS_SV, "f1ord", count_ordinal(f1)) \
323 ARG_CASE(ARG_CS, "f1time", process_time(2, f1)) \
324 ARG_CASE(ARG_CS_SV_HA, "f1race_time", mmssss(f1)) \
325 ARG_CASE(ARG_CS_SV_HA, "f2race_time", mmssss(f2)) \
326 ARG_CASE(ARG_CS_SV_HA, "f3race_time", mmssss(f3)) \
327 ARG_CASE(ARG_CS_SV, "race_col", CCR(((f1 == 1) ? "^F1" : "^F2"))) \
328 ARG_CASE(ARG_CS_SV, "race_diff", ((f2 > f3) ? sprintf(CCR("^1[+%s]"), mmssss(f2 - f3)) : sprintf(CCR("^2[-%s]"), mmssss(f3 - f2)))) \
329 ARG_CASE(ARG_CS, "missing_teams", notif_arg_missing_teams(f1)) \
330 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) : "")) \
331 ARG_CASE(ARG_CS, "frag_ping", notif_arg_frag_ping(true, f2)) \
332 ARG_CASE(ARG_CS, "frag_stats", notif_arg_frag_stats(f2, f3, f4)) \
333 /*ARG_CASE(ARG_CS, "frag_pos", ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))*/ \
334 ARG_CASE(ARG_CS, "spree_cen", (autocvar_notification_show_sprees ? notif_arg_spree_cen(f1) : "")) \
335 ARG_CASE(ARG_CS_SV, "spree_inf", (autocvar_notification_show_sprees ? notif_arg_spree_inf(1, input, s2, f2) : "")) \
336 ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
337 ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \
338 ARG_CASE(ARG_CS_SV, "item_wepname", Weapons_from(f1).m_name) \
339 ARG_CASE(ARG_CS_SV, "item_buffname", BUFF_NAME(f1)) \
340 ARG_CASE(ARG_CS_SV, "f3buffname", BUFF_NAME(f3)) \
341 ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
342 ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \
343 ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \
344 ARG_CASE(ARG_CS, "death_team", Team_ColoredFullName(f1 - 1)) \
345 ARG_CASE(ARG_CS_SV_HA, "minigame1_name",find(world,netname,s1).descriptor.message) \
346 ARG_CASE(ARG_CS_SV_HA, "minigame1_d", find(world,netname,s1).descriptor.netname)
348 #define NOTIF_HIT_MAX(count,funcname) MACRO_BEGIN { \
349 if(sel_num == count) { backtrace(sprintf("%s: Hit maximum arguments!\n", funcname)); break; } \
351 #define NOTIF_HIT_UNKNOWN(token,funcname) { backtrace(sprintf("%s: Hit unknown token in selected string! '%s'\n", funcname, selected)); break; }
353 #define KILL_SPREE_LIST \
354 SPREE_ITEM(3, 03, _("TRIPLE FRAG! "), _("%s^K1 made a TRIPLE FRAG! %s^BG"), _("%s^K1 made a TRIPLE SCORE! %s^BG")) \
355 SPREE_ITEM(5, 05, _("RAGE! "), _("%s^K1 unlocked RAGE! %s^BG"), _("%s^K1 made FIVE SCORES IN A ROW! %s^BG")) \
356 SPREE_ITEM(10, 10, _("MASSACRE! "), _("%s^K1 started a MASSACRE! %s^BG"), _("%s^K1 made TEN SCORES IN A ROW! %s^BG")) \
357 SPREE_ITEM(15, 15, _("MAYHEM! "), _("%s^K1 executed MAYHEM! %s^BG"), _("%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG")) \
358 SPREE_ITEM(20, 20, _("BERSERKER! "), _("%s^K1 is a BERSERKER! %s^BG"), _("%s^K1 made TWENTY SCORES IN A ROW! %s^BG")) \
359 SPREE_ITEM(25, 25, _("CARNAGE! "), _("%s^K1 inflicts CARNAGE! %s^BG"), _("%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG")) \
360 SPREE_ITEM(30, 30, _("ARMAGEDDON! "), _("%s^K1 unleashes ARMAGEDDON! %s^BG"), _("%s^K1 made THIRTY SCORES IN A ROW! %s^BG"))
363 string notif_arg_frag_ping(float newline, float fping)
366 return sprintf(CCR(_("%s(^F1Bot^BG)")), (newline ? "\n" : " "));
368 return sprintf(CCR(_("%s(Ping ^F1%d^BG)")), (newline ? "\n" : " "), fping);
371 string notif_arg_frag_stats(float fhealth, float farmor, float fping)
374 return sprintf(CCR(_("\n(Health ^1%d^BG / Armor ^2%d^BG)%s")), fhealth, farmor, notif_arg_frag_ping(false, fping));
376 return sprintf(CCR(_("\n(^F4Dead^BG)%s")), notif_arg_frag_ping(false, fping));
379 string notif_arg_missing_teams(float f1)
381 return sprintf("%s%s%s%s",
383 sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_1), ((f1 & (2 + 4 + 8)) ? ", " : ""))
388 sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_2), ((f1 & (4 + 8)) ? ", " : ""))
393 sprintf("%s%s", Team_ColoredFullName(NUM_TEAM_3), ((f1 & 8) ? ", " : ""))
398 Team_ColoredFullName(NUM_TEAM_4)
405 string notif_arg_spree_cen(float spree)
407 // 0 = off, 1 = target (but only for first victim) and attacker
408 if(autocvar_notification_show_sprees_center)
412 #define SPREE_ITEM(counta,countb,center,normal,gentle) \
413 case counta: { return normal_or_gentle(center, sprintf(_("%d score spree! "), spree)); }
420 if (!autocvar_notification_show_sprees_center_specialonly)
425 _("%d frag spree! "),
426 _("%d score spree! ")
430 else { return ""; } // don't show spree information if it isn't an achievement
436 else if(spree == -1) // first blood
438 return normal_or_gentle(_("First blood! "), _("First score! "));
440 else if(spree == -2) // first victim
442 return normal_or_gentle(_("First victim! "), _("First casualty! "));
449 string notif_arg_spree_inf(float type, string input, string player, float spree)
453 case 1: // attacker kill spree
455 // 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker
456 // this conditional (& 2) is true for 2 and 3
457 if(autocvar_notification_show_sprees_info & 2)
460 string spree_newline =
461 ( autocvar_notification_show_sprees_info_newline ?
462 ((substring(input, 0, 1) == "\{3}") ? "\n\{3}" : "\n") : "" );
464 string spree_newline =
465 (autocvar_notification_show_sprees_info_newline ? "\n" : "");
470 #define SPREE_ITEM(counta,countb,center,normal,gentle) \
471 case counta: { return sprintf(CCR(normal_or_gentle(normal, gentle)), player, spree_newline); }
478 if (!autocvar_notification_show_sprees_info_specialonly)
482 CCR(normal_or_gentle(
483 _("%s^K1 has %d frags in a row! %s^BG"),
484 _("%s^K1 made %d scores in a row! %s^BG")
491 else { return ""; } // don't show spree information if it isn't an achievement
497 else if(spree == -1) // firstblood
501 CCR(normal_or_gentle(
502 _("%s^K1 drew first blood! %s^BG"),
503 _("%s^K1 got the first score! %s^BG")
513 case -1: // kill spree ended
515 if((spree > 1) && (autocvar_notification_show_sprees_info & 1))
518 sprintf(normal_or_gentle(
519 _(", ending their %d frag spree"),
520 _(", ending their %d score spree")
528 case -2: // kill spree lost
530 if((spree > 1) && (autocvar_notification_show_sprees_info & 1))
533 sprintf(normal_or_gentle(
534 _(", losing their %d frag spree"),
535 _(", losing their %d score spree")
547 // ====================================
548 // Initialization/Create Declarations
549 // ====================================
570 , CPID_MISSING_PLAYERS
571 , CPID_INSTAGIB_FINDAMMO
578 , CPID_RACE_FINISHLAP
582 , CPID_VEHICLES_OTHER
586 // notification counts
587 const float NOTIF_FIRST = 1;
588 float NOTIF_ANNCE_COUNT;
589 float NOTIF_INFO_COUNT;
590 float NOTIF_CENTER_COUNT;
591 float NOTIF_MULTI_COUNT;
592 float NOTIF_CHOICE_COUNT;
594 // notification limits -- INCREASE AS NECESSARY
595 const float NOTIF_ANNCE_MAX = 400;
596 const float NOTIF_INFO_MAX = 450;
597 const float NOTIF_CENTER_MAX = 350;
598 const float NOTIF_MULTI_MAX = 300;
599 const float NOTIF_CHOICE_MAX = 50;
601 // notification entities
602 entity msg_annce_notifs[NOTIF_ANNCE_MAX];
603 entity msg_info_notifs[NOTIF_INFO_MAX];
604 entity msg_center_notifs[NOTIF_CENTER_MAX];
605 entity msg_multi_notifs[NOTIF_MULTI_MAX];
606 entity msg_choice_notifs[NOTIF_CHOICE_MAX];
608 // common notification entity values
614 .int nent_stringcount;
615 .int nent_floatcount;
617 // MSG_ANNCE entity values
621 .float nent_position;
623 // MSG_INFO and MSG_CENTER entity values
624 .string nent_args; // used by both
625 .string nent_hudargs; // used by info
626 .string nent_icon; // used by info
627 .float nent_cpid; // used by center
628 .string nent_durcnt; // used by center
629 .string nent_string; // used by both
631 // MSG_MULTI entity values
632 .entity nent_msgannce;
633 .entity nent_msginfo;
634 .entity nent_msgcenter;
636 // MSG_CHOICE entity values
637 .float nent_challow_def;
638 .float nent_challow_var;
639 .entity nent_optiona;
640 .entity nent_optionb;
642 // networked notification entity values
643 .float nent_broadcast;
645 .float nent_net_type;
646 .float nent_net_name;
647 .string nent_strings[4];
648 .float nent_floats[4];
650 // other notification properties
651 .float msg_choice_choices[NOTIF_CHOICE_MAX]; // set on each player containing MSG_CHOICE choices
653 #define ACVNN(name) autocvar_notification_##name
655 // initialization error detection
657 float notif_global_error;
659 #define MSG_ANNCE_NOTIF(name, default, sound, channel, volume, position) \
660 MSG_ANNCE_NOTIF_(ANNCE_##name, default, sound, channel, volume, position)
661 #define MSG_ANNCE_NOTIF_(name, default, sound, channel, volume, position) \
662 NOTIF_ADD_AUTOCVAR(name, default) \
664 void RegisterNotification_##name() \
666 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_ANNCE_COUNT) \
667 CHECK_MAX_COUNT(name, NOTIF_ANNCE_MAX, NOTIF_ANNCE_COUNT, "MSG_ANNCE") \
668 entity this = msg_annce_notifs[name - 1] = new_pure(msg_annce_notification); \
669 Create_Notification_Entity (this, default, ACVNN(name), MSG_ANNCE, name, strtoupper(#name)); \
670 Create_Notification_Entity_Annce(this, ACVNN(name), strtoupper(#name), \
671 channel, /* channel */ \
674 position); /* position */ \
676 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
678 #define MSG_INFO_NOTIF(name, default, strnum, flnum, args, hudargs, icon, normal, gentle) \
679 MSG_INFO_NOTIF_(INFO_##name, default, strnum, flnum, args, hudargs, icon, normal, gentle)
680 #define MSG_INFO_NOTIF_(name, default, strnum, flnum, args, hudargs, icon, normal, gentle) \
681 NOTIF_ADD_AUTOCVAR(name, default) \
683 void RegisterNotification_##name() \
685 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
686 CHECK_MAX_COUNT(name, NOTIF_INFO_MAX, NOTIF_INFO_COUNT, "MSG_INFO") \
687 entity this = msg_info_notifs[name - 1] = new_pure(msg_info_notification); \
688 Create_Notification_Entity (this, default, ACVNN(name), MSG_INFO, name, strtoupper(#name)); \
689 Create_Notification_Entity_InfoCenter(this, ACVNN(name), strtoupper(#name), strnum, flnum, \
691 hudargs, /* hudargs */ \
695 normal, /* normal */ \
696 gentle); /* gentle */ \
698 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
700 .string nent_iconargs;
701 #define MULTIICON_INFO(name, default, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle) \
702 MULTIICON_INFO_(INFO_##name, default, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle)
703 #define MULTIICON_INFO_(name, default, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle) \
704 NOTIF_ADD_AUTOCVAR(name, default) \
706 void RegisterNotification_##name() \
708 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
709 CHECK_MAX_COUNT(name, NOTIF_INFO_MAX, NOTIF_INFO_COUNT, "MSG_INFO") \
710 entity this = msg_info_notifs[name - 1] = new_pure(msg_info_notification); \
711 Create_Notification_Entity (this, default, ACVNN(name), MSG_INFO, name, strtoupper(#name)); \
712 Create_Notification_Entity_InfoCenter(this, ACVNN(name), strtoupper(#name), strnum, flnum, \
714 hudargs, /* hudargs */ \
718 normal, /* normal */ \
719 gentle); /* gentle */ \
720 msg_info_notifs[name - 1].nent_iconargs = iconargs; \
722 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
724 #define MSG_CENTER_NOTIF(name, default, strnum, flnum, args, cpid, durcnt, normal, gentle) \
725 MSG_CENTER_NOTIF_(CENTER_##name, default, strnum, flnum, args, cpid, durcnt, normal, gentle)
726 #define MSG_CENTER_NOTIF_(name, default, strnum, flnum, args, cpid, durcnt, normal, gentle) \
727 NOTIF_ADD_AUTOCVAR(name, default) \
729 void RegisterNotification_##name() \
731 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
732 CHECK_MAX_COUNT(name, NOTIF_CENTER_MAX, NOTIF_CENTER_COUNT, "MSG_CENTER") \
733 entity this = msg_center_notifs[name - 1] = new_pure(msg_center_notification); \
734 Create_Notification_Entity (this, default, ACVNN(name), MSG_CENTER, name, strtoupper(#name)); \
735 Create_Notification_Entity_InfoCenter(this, ACVNN(name), strtoupper(#name), strnum, flnum, \
740 durcnt, /* durcnt */ \
741 normal, /* normal */ \
742 gentle); /* gentle */ \
744 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
746 #define MSG_MULTI_NOTIF(name, default, anncename, infoname, centername) \
747 NOTIF_ADD_AUTOCVAR(name, default) \
749 void RegisterNotification_##name() \
751 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_MULTI_COUNT) \
752 CHECK_MAX_COUNT(name, NOTIF_MULTI_MAX, NOTIF_MULTI_COUNT, "MSG_MULTI") \
753 entity this = msg_multi_notifs[name - 1] = new_pure(msg_multi_notification); \
754 Create_Notification_Entity (this, default, ACVNN(name), MSG_MULTI, name, strtoupper(#name)); \
755 Create_Notification_Entity_Multi(this, ACVNN(name), strtoupper(#name), \
756 anncename, /* anncename */ \
757 infoname, /* infoname */ \
758 centername); /* centername */ \
760 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
762 #define MSG_CHOICE_NOTIF(name, default, challow, chtype, optiona, optionb) \
763 MSG_CHOICE_NOTIF_(CHOICE_##name, default, challow, chtype, optiona, optionb)
764 #define MSG_CHOICE_NOTIF_(name, default, challow, chtype, optiona, optionb) \
765 NOTIF_ADD_AUTOCVAR(name, default) \
766 NOTIF_ADD_AUTOCVAR(name##_ALLOWED, challow) \
768 void RegisterNotification_##name() \
770 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CHOICE_COUNT) \
771 CHECK_MAX_COUNT(name, NOTIF_CHOICE_MAX, NOTIF_CHOICE_COUNT, "MSG_CHOICE") \
772 entity this = msg_choice_notifs[name - 1] = new_pure(msg_choice_notification); \
773 Create_Notification_Entity (this, default, ACVNN(name), MSG_CHOICE, name, strtoupper(#name)); \
774 Create_Notification_Entity_Choice(this, ACVNN(name), strtoupper(#name), \
775 challow, /* challow_def */ \
776 autocvar_notification_##name##_ALLOWED, /* challow_var */ \
777 chtype, /* chtype */ \
778 optiona, /* optiona */ \
779 optionb); /* optionb */ \
781 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
783 void RegisterNotifications_First()
785 notif_global_error = false;
788 void RegisterNotifications_Done()
790 if(notif_global_error)
792 // shit happened... stop the loading of the program now if this is unacceptable
793 if(autocvar_notification_errors_are_fatal)
794 LOG_FATAL("Notification initialization failed! Read above and fix the errors!\n");
796 LOG_SEVERE("Notification initialization failed! Read above and fix the errors!\n");
800 // NOW we actually activate the declarations
801 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotifications_First)
802 #include "notifications.inc"
803 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotifications_Done)
805 STATIC_INIT(RegisterNotifications) { CALL_ACCUMULATED_FUNCTION(RegisterNotifications); }