]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/notifications.qc
Death messages are now FULLY FUNCTIONAL (minus some new feature ideas yet)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / notifications.qc
1 // ================================================
2 //  Unified notification system, written by Samual
3 //  Last updated: December, 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 #define MSG_DEATH 4 // "Personal" AND "Global" death messages 
11
12 #define NO_STR_ARG ""
13 #define NO_FL_ARG -12345
14 #define NO_MSG -12345
15
16 #define F_NAME 1
17 #define F_STRNUM 2
18 #define F_FLNUM 3
19
20 #define BOT_PING -1
21
22 // Since this code uses macro processors to list notifications,
23 // the normal compiler sees these checks as "constant" and throws
24 // a warning. We have to get around this by using another function.
25 #define NOTIF_MATCH(a,b) if(min(NOTIF_MAX, a) == b)
26
27 #ifdef CSQC
28 // NO_CPID normally has a variable value, so we need to check and see
29 // whether a notification uses it. If so, cancel out the centerprint ID.
30 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
31
32 // client-side handling of cvars
33 #define ADD_CSQC_AUTOCVAR(name) var float autocvar_notification_##name = TRUE;
34 #define CHECK_AUTOCVAR(name) if(autocvar_notification_##name)
35
36 /*
37  Acquire special information to generate for display in the
38  notification from variables networked to the client.
39  Macro descriptions:
40     PASS_KEY: find the keybind for "passing" or "dropping" in CTF game mode
41     FRAG_PING: show the ping of a player
42     FRAG_STATS: show health/armor/ping of a player
43     FRAG_POS: show score status and position in the match of a player
44     SPREE_FRAG: find out if the player is on a kill spree/how many kills they have
45     SPREE_END: placed at the end of murder messages to show ending of sprees
46     SPREE_LOST: placed at the end of suicide messages to show losing of sprees
47     DEATH_TEAM: show the full name of the team a player is switching from
48     WEAPON_NAME: return the full name of a weapon from a weaponid
49 */
50 // CSQC replacements
51 string got_commandkey;
52 #define PASS_KEY ((((got_commandkey = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(got_commandkey, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), got_commandkey) : "")
53 #define FRAG_PING ((f2 != BOT_PING) ? sprintf(CCR(_("\n(Ping ^2%d^BG)")), f2) : "")
54 #define FRAG_STATS sprintf(CCR(_("\n(Health ^1%d^BG / Armor ^2%d^BG)%s")), f1, f2, ((f3 != BOT_PING) ? sprintf(CCR(_(" (Ping ^2%d^BG)")), f3) : ""))
55 #define FRAG_POS ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : "")
56 #define SPREE_FRAG (((f1 == 3) || (f1 == 5) || (f1 == 10) || (f1 == 15) || (f1 == 20) || (f1 == 25) || (f1 == 30)) ? sprintf(normal_or_gentle(_("%d kill spree! "), _("%d score spree! ")), f1) : "")
57 #define SPREE_END ((f1 >= 3) ? sprintf(normal_or_gentle(_(", ending their %d kill spree"), _(", ending their %d score spree")), f1) : "")
58 #define SPREE_LOST ((f1 >= 3) ? sprintf(normal_or_gentle(_(", losing their %d kill spree"), _(", losing their %d score spree")), f1) : "")
59 #define DEATH_TEAM Team_ColoredFullName(TEAM_SV_TO_CL(f1))
60 #define WEAPON_NAME f1 // weaponorder[f1].netname
61 #else
62 #ifdef SVQC
63 // SVQC replacements
64 #define SPREE_END ((f1 >= 3) ? sprintf(normal_or_gentle(_(", ending their %d kill spree"), _(", ending their %d score spree")), f1) : "")
65 #define SPREE_LOST ((f1 >= 3) ? sprintf(normal_or_gentle(_(", losing their %d kill spree"), _(", losing their %d score spree")), f1) : "")
66 #define DEATH_TEAM Team_ColoredFullName(f1)
67 #define WEAPON_NAME f1 // weaponorder[f1].netname
68
69 // allow sending of notifications to also pass through to spectators (specifically for centerprints)
70 #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
71 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
72 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
73 #endif
74
75 // do nothing for the other programs, they don't need cvars (those are just for the clients)
76 #define ADD_CSQC_AUTOCVAR(name)
77 #endif
78
79
80 // ====================================
81 //  Notifications List and Information
82 // ====================================
83 /*
84  List of all notifications (including identifiers and display information)
85  Possible Tokens: name, infoname, centername, strnum, flnum, args, hudargs, icon, cpid, durcnt, normal, gentle
86  Format Specifications:
87     MSG_INFO:
88       name: VAR: Name of notification
89       strnum: FLOAT: Number of STRING arguments (so that networking knows how many to send/receive)
90       flnum: FLOAT: Number of FLOAT arguments (so that networking knows how many to send/receive)
91       args: MISC: Arguments for sprintf(string, args), if no args needed then use ""
92       hudargs: XPND2(STRING, STRING): arguments for names in notify messages 
93       icon: STRING: icon string name for the hud notify panel, "" if no icon is used
94       normal: STRING: Normal message (string for sprintf when gentle messages are NOT enabled)
95       gentle: STRING: Gentle message (string for sprintf when gentle messages ARE enabled)
96     MSG_CENTER:
97       name: VAR: Name of notification
98       strnum: FLOAT: Number of STRING arguments (so that networking knows how many to send/receive)
99       flnum: FLOAT: Number of FLOAT arguments (so that networking knows how many to send/receive)
100       args: MISC: Arguments for sprintf(string, args), if no args needed then use ""
101       cpid: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
102       durcnt: XPND2(FLOAT, FLOAT): Duration/Countdown: extra arguments for centerprint messages
103       normal: STRING: Normal message (string for sprintf when gentle messages are NOT enabled)
104       gentle: STRING: Gentle message (string for sprintf when gentle messages ARE enabled)
105     MSG_WEAPON:
106     MSG_DEATH:
107       name: VAR: Name of chaining notification
108       infoname: VAR: Name of info notification for reference
109       centername: VAR: Name of centerprint notification for reference
110
111  Messages with ^F1, ^BG, ^TC, etc etc in them will replace those strings
112  with colors according to the cvars the user has chosen. This allows for
113  users to create unique color profiles for their HUD, giving more customization
114  options to HUD designers and end users who want such a feature.
115
116  Check out the function calls for string CCR(...) and
117  string TCR(...) to better understand how these codes work.
118
119  Guidlines (please try and follow these):
120     -ALWAYS start the string with a color, preferably background.
121     -ALWAYS reset a color after a name (this way they don't set it for the whole string).
122     -NEVER re-declare an event twice.
123     -NEVER add or remove fields from the format, it SHOULD already work.
124     -MSG_INFO messages must ALWAYS end with a new line: \n
125     -Be clean and simple with your notification naming,
126      nothing too long for the name field... Abbreviations are your friend. :D
127     -Keep the spacing as clean as possible... if the arguments are abnormally long,
128       it's okay to go out of line a bit... but try and keep it clean still.
129     -Sort the notifications in the most appropriate order for their tasks.
130       TODO: ? centerprint IDs are given priority based on their order (first being highest priority going downwards)
131     -ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^
132 */
133
134 #define MULTITEAM_INFO(prefix,teams,strnum,flnum,args,hudargs,icon,normal,gentle) \
135         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))) \
136         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))) \
137         #if teams >= 3 \
138                 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))) \
139         #endif \
140         #if teams >= 4 \
141                 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))) \
142         #endif
143 #define MSG_INFO_NOTIFICATIONS \
144         MSG_INFO_NOTIF(INFO_EMPTY,                                                      0, 0, NO_STR_ARG, XPND2("", ""),                                        "",                                             "", "") \
145         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"), "") \
146         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"), "") \
147         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"), "") \
148         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"), "") \
149         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"), "") \
150         MULTITEAM_INFO(INFO_CTF_FLAGRETURN_TIMEOUT_, 2,         0, 0, NO_STR_ARG, XPND2("", ""),                                        "",                                             _("^BGThe ^TC^TT^BG flag has returned to the base\n"), "") \
151         MULTITEAM_INFO(INFO_CTF_PICKUP_, 2,                                     1, 0, s1, XPND2(s1, ""),                                                        "notify_%s_taken",              _("^BG%s^BG got the ^TC^TT^BG flag\n"), "") \
152         MULTITEAM_INFO(INFO_CTF_RETURN_, 2,                                     1, 0, s1, XPND2(s1, ""),                                                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag\n"), "") \
153         MULTITEAM_INFO(INFO_CTF_LOST_, 2,                                       1, 0, s1, XPND2(s1, ""),                                                        "notify_%s_lost",               _("^BG%s^BG lost the ^TC^TT^BG flag\n"), "") \
154         MULTITEAM_INFO(INFO_CTF_CAPTURE_, 2,                            1, 0, s1, XPND2(s1, ""),                                                        "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag\n"), "") \
155         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"), "") \
156         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"), "") \
157         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"), "") \
158         MULTITEAM_INFO(INFO_DEATH_TEAMKILL_, 4,                         2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_teamkill_%s",   _("^BG%s^K1 was betrayed by ^BG%s^K1%s\n"), "") \
159         MSG_INFO_NOTIF(INFO_DEATH_FIRSTBLOOD,                           2, 0, s2, XPND2("", ""),                                                        "",                                             _("^BG%s^K1 drew first blood\n"), _("^F1%s^K1 got the first score\n")) \
160         MSG_INFO_NOTIF(INFO_DEATH_SELF_CUSTOM,                          2, 1, XPND3(s1, s2, SPREE_LOST), XPND2(s1, ""),         "notify_void",                  _("^BG%s^K1 %s^K1%s\n"), "") \
161         MSG_INFO_NOTIF(INFO_DEATH_SELF_GENERIC,                         1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_selfkill",              _("^BG%s^K1 died%s\n"), "") \
162         MSG_INFO_NOTIF(INFO_DEATH_SELF_VOID,                            1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_void",                  _("^BG%s^K1 was in the wrong place%s\n"), "") \
163         MSG_INFO_NOTIF(INFO_DEATH_SELF_SUICIDE,                         1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_selfkill",              _("^BG%s^K1 couldn't take it anymore%s\n"), "") \
164         MSG_INFO_NOTIF(INFO_DEATH_SELF_NOAMMO,                          1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_outofammo",             _("^BG%s^K1 died%s. What's the point of living without ammo?\n"), _("^F1%s^K1 ran out of ammo%s\n")) \
165         MSG_INFO_NOTIF(INFO_DEATH_SELF_ROT,                                     1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_death",                 _("^BG%s^K1 rotted away%s\n"), "") \
166         MSG_INFO_NOTIF(INFO_DEATH_SELF_CAMP,                            1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_camping",               _("^BG%s^K1 thought they found a nice camping ground%s\n"), "") \
167         MSG_INFO_NOTIF(INFO_DEATH_SELF_BETRAYAL,                        1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_teamkill_red",  _("^BG%s^K1 became enemies with the Lord of Teamplay%s\n"), "") \
168         MSG_INFO_NOTIF(INFO_DEATH_SELF_TEAMCHANGE,                      1, 1, XPND2(s1, DEATH_TEAM), XPND2("", ""),                     "",                                             _("^BG%s^K1 switched to the %s\n"), "") \
169         MSG_INFO_NOTIF(INFO_DEATH_SELF_AUTOTEAMCHANGE,          1, 1, XPND2(s1, DEATH_TEAM), XPND2("", ""),                     "",                                             _("^BG%s^K1 was moved into the %s\n"), "") \
170         MSG_INFO_NOTIF(INFO_DEATH_SELF_FALL,                            1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_fall",                  _("^BG%s^K1 hit the ground with a crunch%s\n"), _("^F1%s^K1 hit the ground with a bit too much force%s\n")) \
171         MSG_INFO_NOTIF(INFO_DEATH_SELF_DROWN,                           1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_water",                 _("^BG%s^K1 couldn't catch their breath%s\n"), _("^F1%s^K1 was in the water for too long%s\n")) \
172         MSG_INFO_NOTIF(INFO_DEATH_SELF_FIRE,                            1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_death",                 _("^BG%s^K1 became a bit too crispy%s\n"), _("^F1%s^K1 felt a little hot%s\n")) \
173         MSG_INFO_NOTIF(INFO_DEATH_SELF_LAVA,                            1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_lava",                  _("^BG%s^K1 turned into hot slag%s\n"), _("^F1%s^K1 found a hot place%s\n")) \
174         MSG_INFO_NOTIF(INFO_DEATH_SELF_SLIME,                           1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_slime",                 _("^BG%s^K1 was slimed%s\n"), "") \
175         MSG_INFO_NOTIF(INFO_DEATH_SELF_SHOOTING_STAR,           1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_shootingstar",  _("^BG%s^K1 became a shooting star%s\n"), "") \
176         MSG_INFO_NOTIF(INFO_DEATH_SELF_SWAMP,                           1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_slime",                 _("^BG%s^K1 is now preserved for centuries to come%s\n"), "") \
177         MSG_INFO_NOTIF(INFO_DEATH_SELF_CHEAT,                           1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_selfkill",              _("^BG%s^K1 unfairly eliminated themself%s\n"), "") \
178         MSG_INFO_NOTIF(INFO_DEATH_SELF_TOUCHEXPLODE,            1, 1, XPND2(s1, SPREE_LOST), XPND2(s1, ""),                     "notify_death",                 _("^BG%s^K1 died in an accident%s\n"), "") \
179         MSG_INFO_NOTIF(INFO_DEATH_MURDER_TELEFRAG,                      2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_telefrag",              _("^BG%s^K1 was telefragged by ^BG%s^K1%s\n"), _("^F1%s^K1 tried to occupy ^BG%s^K1's teleport destination space\n")) \
180         MSG_INFO_NOTIF(INFO_DEATH_MURDER_FALL,                          2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_fall",                  _("^BG%s^K1 was grounded by ^BG%s^K1%s\n"), "") \
181         MSG_INFO_NOTIF(INFO_DEATH_MURDER_DROWN,                         2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_water",                 _("^BG%s^K1 was drowned by ^BG%s^K1%s\n"), "") \
182         MSG_INFO_NOTIF(INFO_DEATH_MURDER_LAVA,                          2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_lava",                  _("^BG%s^K1 was cooked by ^BG%s^K1%s\n"), "") \
183         MSG_INFO_NOTIF(INFO_DEATH_MURDER_SLIME,                         2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_slime",                 _("^BG%s^K1 was slimed by ^BG%s^K1%s\n"), "") \
184         MSG_INFO_NOTIF(INFO_DEATH_MURDER_SHOOTING_STAR,         2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_shootingstar",  _("^BG%s^K1 was shot into space by ^BG%s^K1%s\n"), "") \
185         MSG_INFO_NOTIF(INFO_DEATH_MURDER_SWAMP,                         2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_slime",                 _("^BG%s^K1 was preserved by ^BG%s^K1%s\n"), "") \
186         MSG_INFO_NOTIF(INFO_DEATH_MURDER_VOID,                          2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_void",                  _("^BG%s^K1 was thrown into a world of hurt by ^BG%s^K1%s\n"), "") \
187         MSG_INFO_NOTIF(INFO_DEATH_MURDER_TOUCHEXPLODE,          2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_death",                 _("^BG%s^K1 died in an accident with ^BG%s^K1%s\n"), "") \
188         MSG_INFO_NOTIF(INFO_DEATH_MURDER_CHEAT,                         2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_death",                 _("^BG%s^K1 was unfairly eliminated by ^BG%s^K1%s\n"), "") \
189         MSG_INFO_NOTIF(INFO_DEATH_MURDER_FIRE,                          2, 1, XPND3(s1, s2, SPREE_END), XPND2(s1, s2),          "notify_death",                 _("^BG%s^K1 was burnt up into a crisp by ^BG%s^K1%s\n"), _("^F1%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s\n")) \
190         MULTITEAM_INFO(INFO_SCORES_, 4,                                         0, 0, NO_STR_ARG, XPND2("", ""),                                        "",                                             _("^TC^TT ^BGteam scores!\n"), "") \
191         MSG_INFO_NOTIF(INFO_WEAPON_THINKING_WITH_PORTALS,                       1, 0, s1, XPND2(s1, ""),                                "notify_selfkill", _("^BG%s^K1 is now thinking with portals...\n"), "") \
192         MSG_INFO_NOTIF(INFO_WEAPON_CRYLINK_SUICIDE,                             1, 0, s1, XPND2(s1, ""),                                "weaponcrylink", _("^BG%s^K1 felt the strong pull of their Crylink\n"), "") \
193         MSG_INFO_NOTIF(INFO_WEAPON_CRYLINK_MURDER,                                      2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponcrylink", _("^BG%s^K1 felt the strong pull of ^BG%s^K1's Crylink\n"), "") \
194         MSG_INFO_NOTIF(INFO_WEAPON_ELECTRO_SUICIDE_ORBS,                        1, 0, s1, XPND2(s1, ""),                                "weaponelectro", _("^BG%s^K1 could not remember where they put their Electro plasma\n"), "") \
195         MSG_INFO_NOTIF(INFO_WEAPON_ELECTRO_SUICIDE_BOLT,                        1, 0, s1, XPND2(s1, ""),                                "weaponelectro", _("^BG%s^K1 played with Electro plasma\n"), "") \
196         MSG_INFO_NOTIF(INFO_WEAPON_ELECTRO_MURDER_BOLT,                         2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponelectro", _("^BG%s^K1 was blasted by ^BG%s^K1's Electro bolt\n"), "") \
197         MSG_INFO_NOTIF(INFO_WEAPON_ELECTRO_MURDER_ORBS,                         2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponelectro", _("^BG%s^K1 got too close to ^BG%s^K1's Electro plasma\n"), "") \
198         MSG_INFO_NOTIF(INFO_WEAPON_ELECTRO_MURDER_COMBO,                        2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponelectro", _("^BG%s^K1 felt the electrifying air of ^BG%s^K1's Electro combo\n"), "") \
199         MSG_INFO_NOTIF(INFO_WEAPON_FIREBALL_SUICIDE_FIREMINE,           1, 0, s1, XPND2(s1, ""),                                "weaponfireball", _("^BG%s^K1 forgot about their firemine\n"), "") \
200         MSG_INFO_NOTIF(INFO_WEAPON_FIREBALL_SUICIDE_BLAST,                      1, 0, s1, XPND2(s1, ""),                                "weaponfireball", _("^BG%s^K1 should have used a smaller gun\n"), "") \
201         MSG_INFO_NOTIF(INFO_WEAPON_FIREBALL_MURDER_FIREMINE,            2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponfireball", _("^BG%s^K1 got burnt by ^BG%s^K1's firemine\n"), "") \
202         MSG_INFO_NOTIF(INFO_WEAPON_FIREBALL_MURDER_BLAST,                       2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponfireball", _("^BG%s^K1 got too close to ^BG%s^K1's fireball\n"), "") \
203         MSG_INFO_NOTIF(INFO_WEAPON_MORTAR_SUICIDE_EXPLODE,                      1, 0, s1, XPND2(s1, ""),                                "weapongrenadelauncher", _("^BG%s^K1 blew themself up with their own Mortar\n"), "") \
204         MSG_INFO_NOTIF(INFO_WEAPON_MORTAR_SUICIDE_BOUNCE,                       1, 0, s1, XPND2(s1, ""),                                "weapongrenadelauncher", _("^BG%s^K1 didn't see their own Mortar grenade\n"), "") \
205         MSG_INFO_NOTIF(INFO_WEAPON_MORTAR_MURDER_EXPLODE,                       2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weapongrenadelauncher", _("^BG%s^K1 ate ^BG%s^K1's Mortar grenade\n"), "") \
206         MSG_INFO_NOTIF(INFO_WEAPON_MORTAR_MURDER_BOUNCE,                        2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weapongrenadelauncher", _("^BG%s^K1 got too close to ^BG%s^K1's Mortar grenade\n"), "") \
207         MSG_INFO_NOTIF(INFO_WEAPON_HAGAR_SUICIDE,                                       1, 0, s1, XPND2(s1, ""),                                "weaponhagar", _("^BG%s^K1 played with tiny Hagar rockets\n"), "") \
208         MSG_INFO_NOTIF(INFO_WEAPON_HAGAR_MURDER_BURST,                          2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponhagar", _("^BG%s^K1 was pummeled by a burst of ^BG%s^K1's Hagar rockets\n"), "") \
209         MSG_INFO_NOTIF(INFO_WEAPON_HAGAR_MURDER_SPRAY,                          2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponhagar", _("^BG%s^K1 was pummeled by ^BG%s^K1's Hagar rockets\n"), "") \
210         MSG_INFO_NOTIF(INFO_WEAPON_HLAC_SUICIDE,                                        1, 0, s1, XPND2(s1, ""),                                "weaponhlac", _("^BG%s^K1 got a little jumpy with their HLAC\n"), "") \
211         MSG_INFO_NOTIF(INFO_WEAPON_HLAC_MURDER,                                         2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponhlac", _("^BG%s^K1 was cut down with ^BG%s^K1's HLAC\n"), "") \
212         MSG_INFO_NOTIF(INFO_WEAPON_HOOK_MURDER,                                         2, 0, XPND2(s1, s2), XPND2(s1, s2),             "weaponhook", _("^BG%s^K1 was caught in ^BG%s^K1's Hook gravity bomb\n"), "") \
213         MSG_INFO_NOTIF(INFO_WEAPON_LASER_SUICIDE,                                       1, 0, s1, XPND2(s1, ""),                                "weaponlaser", _("^BG%s^K1 shot themself to hell with their Laser\n"), "") \
214         MSG_INFO_NOTIF(INFO_WEAPON_LASER_MURDER,                                        2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponlaser", _("^BG%s^K1 was shot to death by ^BG%s^K1's Laser\n"), "") \
215         MSG_INFO_NOTIF(INFO_WEAPON_MINELAYER_SUICIDE,                           1, 0, s1, XPND2(s1, ""),                                "weaponminelayer", _("^BG%s^K1 forgot about their mine\n"), "") \
216         MSG_INFO_NOTIF(INFO_WEAPON_MINELAYER_MURDER,                            2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponminelayer", _("^BG%s^K1 got too close to ^BG%s^K1's mine\n"), "") \
217         MSG_INFO_NOTIF(INFO_WEAPON_MINSTANEX_MURDER,                            2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponminstanex", _("^BG%s^K1 has been vaporized by ^BG%s^K1's Minstanex\n"), "") \
218         MSG_INFO_NOTIF(INFO_WEAPON_NEX_MURDER,                                          2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponnex", _("^BG%s^K1 has been vaporized by ^BG%s^K1's Nex\n"), "") \
219         MSG_INFO_NOTIF(INFO_WEAPON_RIFLE_MURDER_HAIL_PIERCING,          2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponrifle", _("^BG%s^K1 failed to hide from ^BG%s^K1's Rifle bullet hail\n"), "") \
220         MSG_INFO_NOTIF(INFO_WEAPON_RIFLE_MURDER_HAIL,                           2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponrifle", _("^BG%s^K1 died in ^BG%s^K1's Rifle bullet hail\n"), "") \
221         MSG_INFO_NOTIF(INFO_WEAPON_RIFLE_MURDER_PIERCING,                       2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponrifle", _("^BG%s^K1 failed to hide from ^BG%s^K1's Rifle\n"), "") \
222         MSG_INFO_NOTIF(INFO_WEAPON_RIFLE_MURDER,                                        2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponrifle", _("^BG%s^K1 was sniped with a Rifle by ^BG%s\n"), "") \
223         MSG_INFO_NOTIF(INFO_WEAPON_RIFLE_MURDER_HEADSHOT,                       2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponrifle", _("^BG%s^K1 was shot in the head with a Rifle by ^BG%s\n"), "") \
224         MSG_INFO_NOTIF(INFO_WEAPON_ROCKETLAUNCHER_SUICIDE,                      1, 0, s1, XPND2(s1, ""),                                "weaponrocketlauncher", _("^BG%s^K1 blew themself up with their Rocketlauncher\n"), "") \
225         MSG_INFO_NOTIF(INFO_WEAPON_ROCKETLAUNCHER_MURDER_DIRECT,        2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponrocketlauncher", _("^BG%s^K1 ate ^BG%s^K1's rocket\n"), "") \
226         MSG_INFO_NOTIF(INFO_WEAPON_ROCKETLAUNCHER_MURDER_SPLASH,        2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponrocketlauncher", _("^BG%s^K1 got too close ^BG%s^K1's rocket\n"), "") \
227         MSG_INFO_NOTIF(INFO_WEAPON_SEEKER_SUICIDE,                                      1, 0, s1, XPND2(s1, ""),                                "weaponseeker", _("^BG%s^K1 played with tiny Seeker rockets\n"), "") \
228         MSG_INFO_NOTIF(INFO_WEAPON_SEEKER_MURDER_TAG,                           2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponseeker", _("^BG%s^K1 was tagged by ^BG%s^K1's Seeker\n"), "") \
229         MSG_INFO_NOTIF(INFO_WEAPON_SEEKER_MURDER_SPRAY,                         2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponseeker", _("^BG%s^K1 was pummeled by ^BG%s^K1's Seeker rockets\n"), "") \
230         MSG_INFO_NOTIF(INFO_WEAPON_SHOTGUN_MURDER_SLAP,                         2, 0, XPND2(s2, s1), XPND2(s1, s2),     "notify_melee_shotgun", _("^BG%s^K1 slapped ^BG%s^K1 around a bit with a large Shotgun\n"), "") \
231         MSG_INFO_NOTIF(INFO_WEAPON_SHOTGUN_MURDER,                                      2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponshotgun", _("^BG%s^K1 was gunned down by ^BG%s^K1's Shotgun\n"), "") \
232         MSG_INFO_NOTIF(INFO_WEAPON_TUBA_SUICIDE,                                        1, 0, s1, XPND2(s1, ""),                                "weapontuba", _("^BG%s^K1 hurt their own ears with the @!#%%'n Tuba\n"), "") \
233         MSG_INFO_NOTIF(INFO_WEAPON_TUBA_MURDER,                                         2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weapontuba", _("^BG%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Tuba\n"), "") \
234         MSG_INFO_NOTIF(INFO_WEAPON_ACCORDEON_SUICIDE,                           1, 0, s1, XPND2(s1, ""),                                "weapontuba", _("^BG%s^K1 hurt their own ears with the @!#%%'n Accordeon\n"), "") \
235         MSG_INFO_NOTIF(INFO_WEAPON_ACCORDEON_MURDER,                            2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weapontuba", _("^BG%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Accordeon\n"), "") \
236         MSG_INFO_NOTIF(INFO_WEAPON_KLEINBOTTLE_SUICIDE,                         1, 0, s1, XPND2(s1, ""),                                "weapontuba", _("^BG%s^K1 hurt their own ears with the @!#%%'n Klein Bottle\n"), "") \
237         MSG_INFO_NOTIF(INFO_WEAPON_KLEINBOTTLE_MURDER,                          2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weapontuba", _("^BG%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Klein Bottle\n"), "") \
238         MSG_INFO_NOTIF(INFO_WEAPON_UZI_MURDER_SNIPE,                            2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponuzi", _("^BG%s^K1 was sniped by ^BG%s^K1's Machine Gun\n"), "") \
239         MSG_INFO_NOTIF(INFO_WEAPON_UZI_MURDER_SPRAY,                            2, 0, XPND2(s1, s2), XPND2(s1, s2),     "weaponuzi", _("^BG%s^K1 was riddled full of holes by ^BG%s^K1's Machine Gun\n"), "") 
240
241 #define MULTITEAM_CENTER(prefix,teams,strnum,flnum,args,cpid,durcnt,normal,gentle) \
242         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))) \
243         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))) \
244         #if teams >= 3 \
245                 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))) \
246         #endif \
247         #if teams >= 4 \
248                 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))) \
249         #endif
250 #define MSG_CENTER_NOTIFICATIONS \
251         MSG_CENTER_NOTIF(CENTER_EMPTY,                                                  0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), "", "") \
252         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."), "") \
253         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."), "") \
254         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"), "") \
255         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"), "") \
256         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"), "") \
257         MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTING,                    1, 0, s1,                                               CPID_CTF_PASS,                  XPND2(0, 0), _("^BGRequesting %s^BG to pass you the flag"), "") \
258         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"), "") \
259         MULTITEAM_CENTER(CENTER_CTF_RETURN_, 2,                                 0, 0, NO_STR_ARG,                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou returned the ^TC^TT^BG flag!"), "") \
260         MULTITEAM_CENTER(CENTER_CTF_CAPTURE_, 2,                                0, 0, NO_STR_ARG,                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou captured the ^TC^TT^BG flag!"), "") \
261         MULTITEAM_CENTER(CENTER_CTF_PICKUP_, 2,                                 0, 0, NO_STR_ARG,                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGYou got the ^TC^TT^BG flag!"), "") \
262         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!"), "") \
263         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!"), "") \
264         MSG_CENTER_NOTIF(CENTER_CTF_PICKUP_ENEMY,                               1, 0, s1,                                               CPID_CTF_LOWPRIO,               XPND2(0, 0), _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
265         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!"), "") \
266         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!"), "") \
267         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!"), "") \
268         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."), "") \
269         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CUSTOM,                              2, 0, s2,                                               NO_CPID,                                XPND2(0, 0), _("^K1You were %s"), "") \
270         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_GENERIC,                             0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You killed your own dumb self!"), _("^K1You need to be more careful!")) \
271         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_VOID,                                0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1Watch your step!"), "") \
272         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SUICIDE,                             0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You committed suicide!"), _("^K1You ended it all!")) \
273         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_NOAMMO,                              0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You were killed for running out of ammo..."), _("^K1You are respawning for running out of ammo...")) \
274         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_ROT,                                 0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You grew too old without taking your medicine"), _("^K1You need to preserve your health")) \
275         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CAMP,                                0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1Die camper!"), _("^K1Reconsider your tactics, camper!")) \
276         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_BETRAYAL,                    0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1Don't shoot your team mates!"), _("^K1Don't go against your team mates!")) \
277         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_TEAMCHANGE,                  0, 1, DEATH_TEAM,                               NO_CPID,                                XPND2(0, 0), _("^BGYou are now on: %s"), "") \
278         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_AUTOTEAMCHANGE,              0, 1, DEATH_TEAM,                               NO_CPID,                                XPND2(0, 0), _("^BGYou have been moved into a different team\nYou are now on: %s"), "") \
279         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_FALL,                                0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You hit the ground with a crunch!"), "") \
280         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_DROWN,                               0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You couldn't catch your breath in time!"), "") \
281         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_FIRE,                                0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You got a little bit too crispy!"), _("^K1You felt a little too hot!")) \
282         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_LAVA,                                0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You couldn't stand the heat!"), "") \
283         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SLIME,                               0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You melted away in slime!"), "") \
284         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SHOOTING_STAR,               0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You became a shooting star!"), "") \
285         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SWAMP,                               0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You got stuck in a swamp!"), "") \
286         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CHEAT,                               0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You unfairly eliminated yourself!"), "") \
287         MSG_CENTER_NOTIF(CENTER_DEATH_SELF_TOUCHEXPLODE,                0, 0, NO_STR_ARG,                               NO_CPID,                                XPND2(0, 0), _("^K1You died in an accident!"), "") \
288         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAG,                                              1, 1, XPND2(SPREE_FRAG, s1),                                                    NO_CPID, XPND2(0, 0), _("^K3%sYou fragged ^BG%s"), _("^K3%sYou scored against ^BG%s")) \
289         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAGGED,                                   1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1You were fragged by ^BG%s"), _("^K1You were scored against by ^BG%s")) \
290         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAG,                                  1, 1, XPND2(SPREE_FRAG, s1),                                                    NO_CPID, XPND2(0, 0), _("^K1%sYou typefragged ^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing")) \
291         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAGGED,                               1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1You were typefragged by ^BG%s"), _("^K1You were scored against by ^BG%s^K1 while typing!")) \
292         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAG_FIRST,                                1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K3First blood! You fragged ^BG%s"), _("^K3First score! You scored against ^BG%s")) \
293         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAGGED_FIRST,                             1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1First victim! You were fragged by ^BG%s"), _("^K1First casualty! You were scored against by ^BG%s")) \
294         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAG_FIRST,                    1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1First blood! You typefragged ^BG%s"), _("^K1First score! You scored against ^BG%s^K1 while they were typing")) \
295         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST,                 1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1First victim! You were typefragged by ^BG%s"), _("^K1First casualty! You were scored against by ^BG%s^K1 while typing!")) \
296         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAG_VERBOSE,                              1, 2, XPND3(SPREE_FRAG, s1, FRAG_PING),                                 NO_CPID, XPND2(0, 0), _("^K3You fragged ^BG%s^BG%s"), _("^K3You scored against ^BG%s^BG%s")) \
297         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAGGED_VERBOSE,                   1, 3, XPND2(s1, FRAG_STATS),                                                    NO_CPID, XPND2(0, 0), _("^K1You were fragged by ^BG%s^BG%s"), _("^K1You were scored against by ^BG%s^BG%s")) \
298         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE,                  1, 2, XPND3(SPREE_FRAG, s1, FRAG_PING),                                 NO_CPID, XPND2(0, 0), _("^K1You typefragged ^BG%s^BG%s"), _("^K1You scored against ^BG%s^K1 while they were typing^BG%s")) \
299         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE,               1, 3, XPND2(s1, FRAG_STATS),                                                    NO_CPID, XPND2(0, 0), _("^K1You were typefragged by ^BG%s^BG%s"), _("^K1You were scored against by ^BG%s^K1 while typing^BG%s")) \
300         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE,                1, 1, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K3First blood! You fragged ^BG%s"), _("^K3First score! You scored against ^BG%s")) \
301         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE,             1, 3, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1First victim! You were fragged by ^BG%s"), _("^K1First casualty! You were scored against by ^BG%s")) \
302         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE,    1, 1, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1First blood! You typefragged ^BG%s"), _("^K1First score! You scored against ^BG%s^K1 while they were typing")) \
303         MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE, 1, 3, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1First victim! You were typefragged by ^BG%s"), _("^K1First casualty! You were scored against by ^BG%s^K1 while typing!")) \
304         MSG_CENTER_NOTIF(CENTER_DEATH_TEAMKILL_FRAG,                                    1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1Moron! You fragged ^BG%s^K1, a team mate!"), _("^K1Moron! You went against ^BG%sK1, a team mate!")) \
305         MSG_CENTER_NOTIF(CENTER_DEATH_TEAMKILL_FRAGGED,                                 1, 0, s1,                                                                                               NO_CPID, XPND2(0, 0), _("^K1You were fragged by ^BG%s^K1, a team mate"), _("^K1You were scored against by ^BG%s^K1, a team mate")) \
306         MSG_CENTER_NOTIF(CENTER_WEAPON_MARBLES_LOST,                    1, 1, XPND2(s1, WEAPON_NAME),   NO_CPID,                                XPND2(0, 0), _("^K1You lost your marbles against ^BG%s^K1 using the ^BG%s!"), "")
307
308 /*#define ADD_TO_LIST(list,newitem) \
309         #define MSG_WEAPON_NOTIFICATIONS \
310                 MSG_WEAPON_NOTIFICATIONS \
311                 item \
312                  nothing */
313
314 #define MSG_WEAPON_NOTIFICATIONS \
315         MSG_WEAPON_NOTIF(WEAPON_EMPTY,                                                  NO_MSG,                                                                         NO_MSG) \
316         MSG_WEAPON_NOTIF(WEAPON_THINKING_WITH_PORTALS,                  INFO_WEAPON_THINKING_WITH_PORTALS,                      NO_MSG) \
317         MSG_WEAPON_NOTIF(WEAPON_CRYLINK_SUICIDE,                                INFO_WEAPON_CRYLINK_SUICIDE,                            NO_MSG) \
318         MSG_WEAPON_NOTIF(WEAPON_CRYLINK_MURDER,                                 INFO_WEAPON_CRYLINK_MURDER,                             NO_MSG) \
319         MSG_WEAPON_NOTIF(WEAPON_ELECTRO_SUICIDE_ORBS,                   INFO_WEAPON_ELECTRO_SUICIDE_ORBS,                       NO_MSG) \
320         MSG_WEAPON_NOTIF(WEAPON_ELECTRO_SUICIDE_BOLT,                   INFO_WEAPON_ELECTRO_SUICIDE_BOLT,                       NO_MSG) \
321         MSG_WEAPON_NOTIF(WEAPON_ELECTRO_MURDER_BOLT,                    INFO_WEAPON_ELECTRO_MURDER_BOLT,                        NO_MSG) \
322         MSG_WEAPON_NOTIF(WEAPON_ELECTRO_MURDER_ORBS,                    INFO_WEAPON_ELECTRO_MURDER_ORBS,                        NO_MSG) \
323         MSG_WEAPON_NOTIF(WEAPON_ELECTRO_MURDER_COMBO,                   INFO_WEAPON_ELECTRO_MURDER_COMBO,                       NO_MSG) \
324         MSG_WEAPON_NOTIF(WEAPON_FIREBALL_SUICIDE_FIREMINE,              INFO_WEAPON_FIREBALL_SUICIDE_FIREMINE,          NO_MSG) \
325         MSG_WEAPON_NOTIF(WEAPON_FIREBALL_SUICIDE_BLAST,                 INFO_WEAPON_FIREBALL_SUICIDE_BLAST,             NO_MSG) \
326         MSG_WEAPON_NOTIF(WEAPON_FIREBALL_MURDER_FIREMINE,               INFO_WEAPON_FIREBALL_MURDER_FIREMINE,           NO_MSG) \
327         MSG_WEAPON_NOTIF(WEAPON_FIREBALL_MURDER_BLAST,                  INFO_WEAPON_FIREBALL_MURDER_BLAST,                      NO_MSG) \
328         MSG_WEAPON_NOTIF(WEAPON_MORTAR_SUICIDE_EXPLODE,                 INFO_WEAPON_MORTAR_SUICIDE_EXPLODE,             NO_MSG) \
329         MSG_WEAPON_NOTIF(WEAPON_MORTAR_SUICIDE_BOUNCE,                  INFO_WEAPON_MORTAR_SUICIDE_BOUNCE,                      NO_MSG) \
330         MSG_WEAPON_NOTIF(WEAPON_MORTAR_MURDER_EXPLODE,                  INFO_WEAPON_MORTAR_MURDER_EXPLODE,                      NO_MSG) \
331         MSG_WEAPON_NOTIF(WEAPON_MORTAR_MURDER_BOUNCE,                   INFO_WEAPON_MORTAR_MURDER_BOUNCE,                       NO_MSG) \
332         MSG_WEAPON_NOTIF(WEAPON_HAGAR_SUICIDE,                                  INFO_WEAPON_HAGAR_SUICIDE,                                      NO_MSG) \
333         MSG_WEAPON_NOTIF(WEAPON_HAGAR_MURDER_BURST,                     INFO_WEAPON_HAGAR_MURDER_BURST,                         NO_MSG) \
334         MSG_WEAPON_NOTIF(WEAPON_HAGAR_MURDER_SPRAY,                     INFO_WEAPON_HAGAR_MURDER_SPRAY,                         NO_MSG) \
335         MSG_WEAPON_NOTIF(WEAPON_HLAC_SUICIDE,                                   INFO_WEAPON_HLAC_SUICIDE,                                       NO_MSG) \
336         MSG_WEAPON_NOTIF(WEAPON_HLAC_MURDER,                                    INFO_WEAPON_HLAC_MURDER,                                        NO_MSG) \
337         MSG_WEAPON_NOTIF(WEAPON_HOOK_MURDER,                                    INFO_WEAPON_HOOK_MURDER,                                        NO_MSG) \
338         MSG_WEAPON_NOTIF(WEAPON_LASER_SUICIDE,                                  INFO_WEAPON_LASER_SUICIDE,                                      NO_MSG) \
339         MSG_WEAPON_NOTIF(WEAPON_LASER_MURDER,                                   INFO_WEAPON_LASER_MURDER,                                       NO_MSG) \
340         MSG_WEAPON_NOTIF(WEAPON_MINELAYER_SUICIDE,                              INFO_WEAPON_MINELAYER_SUICIDE,                          NO_MSG) \
341         MSG_WEAPON_NOTIF(WEAPON_MINELAYER_MURDER,                               INFO_WEAPON_MINELAYER_MURDER,                           NO_MSG) \
342         MSG_WEAPON_NOTIF(WEAPON_MINSTANEX_MURDER,                               INFO_WEAPON_MINSTANEX_MURDER,                           NO_MSG) \
343         MSG_WEAPON_NOTIF(WEAPON_NEX_MURDER,                                     INFO_WEAPON_NEX_MURDER,                                         NO_MSG) \
344         MSG_WEAPON_NOTIF(WEAPON_RIFLE_MURDER_HAIL_PIERCING,             INFO_WEAPON_RIFLE_MURDER_HAIL_PIERCING,         NO_MSG) \
345         MSG_WEAPON_NOTIF(WEAPON_RIFLE_MURDER_HAIL,                              INFO_WEAPON_RIFLE_MURDER_HAIL,                          NO_MSG) \
346         MSG_WEAPON_NOTIF(WEAPON_RIFLE_MURDER_PIERCING,                  INFO_WEAPON_RIFLE_MURDER_PIERCING,                      NO_MSG) \
347         MSG_WEAPON_NOTIF(WEAPON_RIFLE_MURDER,                                   INFO_WEAPON_RIFLE_MURDER,                                       NO_MSG) \
348         MSG_WEAPON_NOTIF(WEAPON_RIFLE_MURDER_HEADSHOT,                  INFO_WEAPON_RIFLE_MURDER_HEADSHOT,                      NO_MSG) \
349         MSG_WEAPON_NOTIF(WEAPON_ROCKETLAUNCHER_SUICIDE,                 INFO_WEAPON_ROCKETLAUNCHER_SUICIDE,             NO_MSG) \
350         MSG_WEAPON_NOTIF(WEAPON_ROCKETLAUNCHER_MURDER_DIRECT,   INFO_WEAPON_ROCKETLAUNCHER_MURDER_DIRECT,       NO_MSG) \
351         MSG_WEAPON_NOTIF(WEAPON_ROCKETLAUNCHER_MURDER_SPLASH,   INFO_WEAPON_ROCKETLAUNCHER_MURDER_SPLASH,       NO_MSG) \
352         MSG_WEAPON_NOTIF(WEAPON_SEEKER_SUICIDE,                                 INFO_WEAPON_SEEKER_SUICIDE,                             NO_MSG) \
353         MSG_WEAPON_NOTIF(WEAPON_SEEKER_MURDER_TAG,                              INFO_WEAPON_SEEKER_MURDER_TAG,                          NO_MSG) \
354         MSG_WEAPON_NOTIF(WEAPON_SEEKER_MURDER_SPRAY,                    INFO_WEAPON_SEEKER_MURDER_SPRAY,                        NO_MSG) \
355         MSG_WEAPON_NOTIF(WEAPON_SHOTGUN_MURDER_SLAP,                    INFO_WEAPON_SHOTGUN_MURDER_SLAP,                        NO_MSG) \
356         MSG_WEAPON_NOTIF(WEAPON_SHOTGUN_MURDER,                                 INFO_WEAPON_SHOTGUN_MURDER,                             NO_MSG) \
357         MSG_WEAPON_NOTIF(WEAPON_TUBA_SUICIDE,                                   INFO_WEAPON_TUBA_SUICIDE,                                       NO_MSG) \
358         MSG_WEAPON_NOTIF(WEAPON_TUBA_MURDER,                                    INFO_WEAPON_TUBA_MURDER,                                        NO_MSG) \
359         MSG_WEAPON_NOTIF(WEAPON_ACCORDEON_SUICIDE,                              INFO_WEAPON_ACCORDEON_SUICIDE,                          NO_MSG) \
360         MSG_WEAPON_NOTIF(WEAPON_ACCORDEON_MURDER,                               INFO_WEAPON_ACCORDEON_MURDER,                           NO_MSG) \
361         MSG_WEAPON_NOTIF(WEAPON_KLEINBOTTLE_SUICIDE,                    INFO_WEAPON_KLEINBOTTLE_SUICIDE,                        NO_MSG) \
362         MSG_WEAPON_NOTIF(WEAPON_KLEINBOTTLE_MURDER,                     INFO_WEAPON_KLEINBOTTLE_MURDER,                         NO_MSG) \
363         MSG_WEAPON_NOTIF(WEAPON_UZI_MURDER_SNIPE,                               INFO_WEAPON_UZI_MURDER_SNIPE,                           NO_MSG) \
364         MSG_WEAPON_NOTIF(WEAPON_UZI_MURDER_SPRAY,                               INFO_WEAPON_UZI_MURDER_SPRAY,                           NO_MSG) 
365
366
367 #define MSG_DEATH_NOTIFICATIONS \
368         MSG_DEATH_NOTIF(DEATH_EMPTY,                                            NO_MSG,                                                                 NO_MSG) \
369         MSG_DEATH_NOTIF(DEATH_SELF_CUSTOM,                                      INFO_DEATH_SELF_GENERIC,                                CENTER_DEATH_SELF_CUSTOM) \
370         MSG_DEATH_NOTIF(DEATH_SELF_GENERIC,                                     INFO_DEATH_SELF_GENERIC,                                CENTER_DEATH_SELF_GENERIC) \
371         MSG_DEATH_NOTIF(DEATH_SELF_VOID,                                        INFO_DEATH_SELF_VOID,                                   CENTER_DEATH_SELF_VOID) \
372         MSG_DEATH_NOTIF(DEATH_SELF_SUICIDE,                                     INFO_DEATH_SELF_SUICIDE,                                CENTER_DEATH_SELF_SUICIDE) \
373         MSG_DEATH_NOTIF(DEATH_SELF_NOAMMO,                                      INFO_DEATH_SELF_NOAMMO,                                 CENTER_DEATH_SELF_NOAMMO) \
374         MSG_DEATH_NOTIF(DEATH_SELF_ROT,                                         INFO_DEATH_SELF_ROT,                                    CENTER_DEATH_SELF_ROT) \
375         MSG_DEATH_NOTIF(DEATH_SELF_CAMP,                                        INFO_DEATH_SELF_CAMP,                                   CENTER_DEATH_SELF_CAMP) \
376         MSG_DEATH_NOTIF(DEATH_SELF_BETRAYAL,                            INFO_DEATH_SELF_BETRAYAL,                               CENTER_DEATH_SELF_BETRAYAL) \
377         MSG_DEATH_NOTIF(DEATH_SELF_TEAMCHANGE,                          INFO_DEATH_SELF_TEAMCHANGE,                             CENTER_DEATH_SELF_TEAMCHANGE) \
378         MSG_DEATH_NOTIF(DEATH_SELF_AUTOTEAMCHANGE,                      INFO_DEATH_SELF_AUTOTEAMCHANGE,                 CENTER_DEATH_SELF_AUTOTEAMCHANGE) \
379         MSG_DEATH_NOTIF(DEATH_SELF_FALL,                                        INFO_DEATH_SELF_FALL,                                   CENTER_DEATH_SELF_FALL) \
380         MSG_DEATH_NOTIF(DEATH_SELF_DROWN,                                       INFO_DEATH_SELF_DROWN,                                  CENTER_DEATH_SELF_DROWN) \
381         MSG_DEATH_NOTIF(DEATH_SELF_FIRE,                                        INFO_DEATH_SELF_FIRE,                                   CENTER_DEATH_SELF_FIRE) \
382         MSG_DEATH_NOTIF(DEATH_SELF_LAVA,                                        INFO_DEATH_SELF_LAVA,                                   CENTER_DEATH_SELF_LAVA) \
383         MSG_DEATH_NOTIF(DEATH_SELF_SLIME,                                       INFO_DEATH_SELF_SLIME,                                  CENTER_DEATH_SELF_SLIME) \
384         MSG_DEATH_NOTIF(DEATH_SELF_SHOOTING_STAR,                       INFO_DEATH_SELF_SHOOTING_STAR,                  CENTER_DEATH_SELF_SHOOTING_STAR) \
385         MSG_DEATH_NOTIF(DEATH_SELF_SWAMP,                                       INFO_DEATH_SELF_SWAMP,                                  CENTER_DEATH_SELF_SWAMP) \
386         MSG_DEATH_NOTIF(DEATH_SELF_CHEAT,                                       INFO_DEATH_SELF_CHEAT,                                  CENTER_DEATH_SELF_CHEAT) \
387         MSG_DEATH_NOTIF(DEATH_SELF_TOUCHEXPLODE,                        INFO_DEATH_SELF_TOUCHEXPLODE,                   CENTER_DEATH_SELF_TOUCHEXPLODE) \
388         MSG_DEATH_NOTIF(DEATH_MURDER_TELEFRAG,                                  INFO_DEATH_MURDER_TELEFRAG,                                     NO_MSG) \
389         MSG_DEATH_NOTIF(DEATH_MURDER_FALL,                                              INFO_DEATH_MURDER_FALL,                                         NO_MSG) \
390         MSG_DEATH_NOTIF(DEATH_MURDER_DROWN,                                             INFO_DEATH_MURDER_DROWN,                                        NO_MSG) \
391         MSG_DEATH_NOTIF(DEATH_MURDER_LAVA,                                              INFO_DEATH_MURDER_LAVA,                                         NO_MSG) \
392         MSG_DEATH_NOTIF(DEATH_MURDER_SLIME,                                             INFO_DEATH_MURDER_SLIME,                                        NO_MSG) \
393         MSG_DEATH_NOTIF(DEATH_MURDER_SHOOTING_STAR,                             INFO_DEATH_MURDER_SHOOTING_STAR,                        NO_MSG) \
394         MSG_DEATH_NOTIF(DEATH_MURDER_SWAMP,                                             INFO_DEATH_MURDER_SWAMP,                                        NO_MSG) \
395         MSG_DEATH_NOTIF(DEATH_MURDER_VOID,                                              INFO_DEATH_MURDER_VOID,                                         NO_MSG) \
396         MSG_DEATH_NOTIF(DEATH_MURDER_TOUCHEXPLODE,                              INFO_DEATH_MURDER_TOUCHEXPLODE,                         NO_MSG) \
397         MSG_DEATH_NOTIF(DEATH_MURDER_CHEAT,                                             INFO_DEATH_MURDER_CHEAT,                                        NO_MSG) \
398         MSG_DEATH_NOTIF(DEATH_MURDER_FIRE,                                              INFO_DEATH_MURDER_FIRE,                                         NO_MSG) \
399         MSG_DEATH_NOTIF(DEATH_MURDER_FRAG,                                                      NO_MSG,                                         CENTER_DEATH_MURDER_FRAG) \
400         MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED,                                           NO_MSG,                                         CENTER_DEATH_MURDER_FRAGGED) \
401         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG,                                          NO_MSG,                                         CENTER_DEATH_MURDER_TYPEFRAG) \
402         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED,                                       NO_MSG,                                         CENTER_DEATH_MURDER_TYPEFRAGGED) \
403         MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_FIRST,                                        INFO_DEATH_FIRSTBLOOD,          CENTER_DEATH_MURDER_FRAG_FIRST) \
404         MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_FIRST,                                     NO_MSG,                                         CENTER_DEATH_MURDER_FRAGGED_FIRST) \
405         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_FIRST,                            INFO_DEATH_FIRSTBLOOD,          CENTER_DEATH_MURDER_TYPEFRAG_FIRST) \
406         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_FIRST,                         NO_MSG,                                         CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST) \
407         MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_VERBOSE,                                      NO_MSG,                                         CENTER_DEATH_MURDER_FRAG_VERBOSE) \
408         MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_VERBOSE,                           NO_MSG,                                         CENTER_DEATH_MURDER_FRAGGED_VERBOSE) \
409         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_VERBOSE,                          NO_MSG,                                         CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE) \
410         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_VERBOSE,                       NO_MSG,                                         CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE) \
411         MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_FIRST_VERBOSE,                        INFO_DEATH_FIRSTBLOOD,          CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE) \
412         MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_FIRST_VERBOSE,                     NO_MSG,                                         CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE) \
413         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE,            INFO_DEATH_FIRSTBLOOD,          CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE) \
414         MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE,         NO_MSG,                                         CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE) \
415         MSG_DEATH_NOTIF(DEATH_TEAMKILL_FRAG,                                            NO_MSG,                                         CENTER_DEATH_TEAMKILL_FRAG) \
416         MSG_DEATH_NOTIF(DEATH_TEAMKILL_FRAGGED,                                         NO_MSG,                                         CENTER_DEATH_TEAMKILL_FRAGGED)
417
418         
419 // ====================================
420 //  Initialization/Create Declarations
421 // ====================================
422
423 #define NOTIF_FIRST 1
424 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
425 float NOTIF_INFO_COUNT;
426 float NOTIF_CENTER_COUNT;
427 float NOTIF_WEAPON_COUNT;
428 float NOTIF_DEATH_COUNT;
429 float NOTIF_CPID_COUNT;
430
431 #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
432         ADD_CSQC_AUTOCVAR(name) \
433         float name; \
434         void RegisterNotification_##name() \
435         { \
436                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
437                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_INFO_COUNT, "notifications") \
438         } \
439         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
440
441 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
442         ADD_CSQC_AUTOCVAR(name) \
443         float name; \
444         float cpid; \
445         void RegisterNotification_##name() \
446         { \
447                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
448                 SET_FIELD_COUNT(cpid, NOTIF_FIRST, NOTIF_CPID_COUNT) \
449                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_CENTER_COUNT, "notifications") \
450         } \
451         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
452
453 #define MSG_WEAPON_NOTIF(name,infoname,centername) \
454         ADD_CSQC_AUTOCVAR(name) \
455         float name; \
456         void RegisterNotification_##name() \
457         { \
458                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_WEAPON_COUNT) \
459                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_WEAPON_COUNT, "notifications") \
460         } \
461         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
462
463 #define MSG_DEATH_NOTIF(name,infoname,centername) \
464         ADD_CSQC_AUTOCVAR(name) \
465         float name; \
466         void RegisterNotification_##name() \
467         { \
468                 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_DEATH_COUNT) \
469                 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_DEATH_COUNT, "notifications") \
470         } \
471         ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
472
473 // NOW we actually activate the declarations
474 MSG_INFO_NOTIFICATIONS
475 MSG_CENTER_NOTIFICATIONS
476 MSG_WEAPON_NOTIFICATIONS
477 MSG_DEATH_NOTIFICATIONS
478 #undef MSG_INFO_NOTIF
479 #undef MSG_CENTER_NOTIF
480 #undef MSG_WEAPON_NOTIF
481 #undef MSG_DEATH_NOTIF
482
483 // ======================
484 //  Supporting Functions
485 // ======================
486
487 // select between the normal or the gentle message string based on client (or server) settings
488 string normal_or_gentle(string normal, string gentle)
489 {
490         #ifndef MENUQC
491                 #ifdef CSQC
492                 if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
493                 #else
494                 if(autocvar_sv_gentle)
495                 #endif
496                         return ((gentle != "") ? gentle : normal);
497                 else
498                         return normal;
499         #else
500                 return normal;
501         #endif
502 }
503
504 float notif_stringcount(string s1, string s2)
505 {
506         float stringcount;
507         if(s1 != NO_STR_ARG) ++stringcount;
508         if(s2 != NO_STR_ARG) ++stringcount;
509         return stringcount;
510 }
511
512 float notif_floatcount(float f1, float f2, float f3)
513 {
514         float floatcount;
515         if(f1 != NO_FL_ARG) ++floatcount;
516         if(f2 != NO_FL_ARG) ++floatcount;
517         if(f3 != NO_FL_ARG) ++floatcount;
518         return floatcount;
519 }
520
521 // get the actual name of a notification and return it as a string
522 string Get_Field_Value(float field, float net_type, float net_name)
523 {
524         string output;
525         
526         #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \
527                 if(field == F_NAME) { output = VAR_TO_TEXT(name); } \
528                 else if(field == F_STRNUM) { output = ftos(strnum); } \
529                 else if(field == F_FLNUM) { output = ftos(flnum); }
530         
531         switch(net_type)
532         {
533                 case MSG_INFO:
534                 {
535                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
536                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
537                         MSG_INFO_NOTIFICATIONS
538                         #undef MSG_INFO_NOTIF
539                         break;
540                 }
541                 case MSG_CENTER:
542                 {
543                         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
544                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
545                         MSG_CENTER_NOTIFICATIONS
546                         #undef MSG_CENTER_NOTIF
547                         break;
548                 }
549                 case MSG_WEAPON:
550                 {
551                         #define MSG_WEAPON_NOTIF(name,infoname,centername) \
552                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name, \
553                                 max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \
554                                 max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } }
555                         MSG_WEAPON_NOTIFICATIONS
556                         #undef MSG_WEAPON_NOTIF
557                         break;
558                 }
559                 case MSG_DEATH:
560                 {
561                         #define MSG_DEATH_NOTIF(name,infoname,centername) \
562                                 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name, \
563                                 max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \
564                                 max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } }
565                         MSG_DEATH_NOTIFICATIONS
566                         #undef MSG_DEATH_NOTIF
567                         break;
568                 }
569         }
570
571         #undef GET_FIELD_VALUE_OUTPUT
572         return output;
573 }
574
575 // team code replace
576 string TCR(string input, string teamcolor, string teamtext)
577
578 {
579         input = strreplace("^TC", teamcolor, input);
580         input = strreplace("^TT", teamtext, input);
581         return input;
582 }
583
584 // color code replace, place inside of sprintf and parse the string
585 string CCR(string input)
586 {
587         // foreground/normal colors
588         input = strreplace("^F1", "^2", input); // primary priority (important names, etc)
589         input = strreplace("^F2", "^3", input); // secondary priority (items, locations, numbers, etc)
590
591         // "kill" colors
592         input = strreplace("^K1", "^1", input); // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
593         input = strreplace("^K2", "^3", input); // similar to above, but less important... OR, a highlight out of above message type
594         input = strreplace("^K3", "^4", input); // "good" or "beneficial" text (you fragging someone, etc)
595
596         // background colors
597         input = strreplace("^BG", "^7", input); // neutral/unimportant text
598         input = strreplace("^N", "^7", input); // "none"-- reset to white...
599         return input;
600 }
601
602
603 // =============================
604 //  Debug/Maintenance Functions
605 // =============================
606
607 #define NOTIF_Write(type,name,text) fputs(fh, (sprintf("seta %s 1 // %s - %s\n", name, type, strreplace("\n", "\\n", text))))
608 void Dump_Notifications(float fh)
609 {
610         #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) { NOTIF_Write("MSG_INFO", VAR_TO_TEXT(name), normal); }
611         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) { NOTIF_Write("MSG_CENTER", VAR_TO_TEXT(name), normal); }
612         #define MSG_WEAPON_NOTIF(name,infoname,centername) { NOTIF_Write("MSG_WEAPON", VAR_TO_TEXT(name),sprintf("infoname: %s, centername: %s", VAR_TO_TEXT(infoname), VAR_TO_TEXT(centername))); }
613         #define MSG_DEATH_NOTIF(name,infoname,centername) { NOTIF_Write("MSG_DEATH", VAR_TO_TEXT(name), sprintf("infoname: %s, centername: %s", VAR_TO_TEXT(infoname), VAR_TO_TEXT(centername))); }
614         MSG_INFO_NOTIFICATIONS
615         MSG_CENTER_NOTIFICATIONS
616         MSG_WEAPON_NOTIFICATIONS
617         MSG_DEATH_NOTIFICATIONS
618         #undef MSG_INFO_NOTIF
619         #undef MSG_CENTER_NOTIF
620         #undef MSG_WEAPON_NOTIF
621         #undef MSG_DEATH_NOTIF
622         return;
623 }
624
625
626 // ===============================
627 //  Frontend Notification Pushing
628 // ===============================
629
630 #ifdef CSQC
631 #define KN_MAX_ENTRIES 10
632 float kn_index;
633 float killnotify_times[KN_MAX_ENTRIES];
634 string killnotify_icon[KN_MAX_ENTRIES];
635 string killnotify_attackers[KN_MAX_ENTRIES];
636 string killnotify_victims[KN_MAX_ENTRIES];
637 // 0 = "Y [used by] X", 1 = "X [did action to] Y"
638 void HUD_Notify_Push(string icon, string attacker, string victim)
639 {
640         if(icon != "")
641         {
642                 --kn_index;
643                 if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
644                 killnotify_times[kn_index] = time;
645
646                 // icon
647                 if(killnotify_icon[kn_index]) { strunzone(killnotify_icon[kn_index]); }
648                 killnotify_icon[kn_index] = strzone(icon);
649
650                 // attacker
651                 if(killnotify_attackers[kn_index]) { strunzone(killnotify_attackers[kn_index]); }
652                 killnotify_attackers[kn_index] = strzone(attacker);
653
654                 // victim
655                 if(killnotify_victims[kn_index]) { strunzone(killnotify_victims[kn_index]); }
656                 killnotify_victims[kn_index] = strzone(victim);
657         }
658 }
659
660 void Local_Notification(float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
661 {
662         //print("Local_Notification(", ftos(net_type), ", ", Get_Field_Value(F_NAME, net_type, net_name), strcat(", ", s1, ", ", s2, ", ", ftos(f1), strcat(", ", ftos(f2), ", ", ftos(f3), ");\n")));
663         switch(net_type)
664         {
665                 case MSG_INFO:
666                 {
667                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
668                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
669                                 { \
670                                         print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); \
671                                         if(strtolower(icon) != "") { HUD_Notify_Push(icon, hudargs); } \
672                                 } }
673                         MSG_INFO_NOTIFICATIONS
674                         #undef MSG_INFO_NOTIF
675                         break;
676                 }
677                 case MSG_CENTER:
678                 {
679                         #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
680                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
681                                 { \
682                                         centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); \
683                                 } }
684                         MSG_CENTER_NOTIFICATIONS
685                         #undef MSG_CENTER_NOTIF
686                         break;
687                 }
688                 case MSG_WEAPON:
689                 {
690                         #define MSG_WEAPON_NOTIF(name,infoname,centername) \
691                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
692                                 { \
693                                         #if infoname != NO_MSG \
694                                                 Local_Notification(MSG_INFO, infoname, s1, s2, f1, f2, f3); \
695                                         #endif \
696                                         #if centername != NO_MSG \
697                                                 Local_Notification(MSG_CENTER, centername, s1, s2, f1, f2, f3); \
698                                         #endif \
699                                 } }
700                         MSG_WEAPON_NOTIFICATIONS
701                         #undef MSG_WEAPON_NOTIF
702                         break;
703                 }
704                 case MSG_DEATH:
705                 {
706                         #define MSG_DEATH_NOTIF(name,infoname,centername) \
707                                 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
708                                 { \
709                                         #if infoname != NO_MSG \
710                                                 Local_Notification(MSG_INFO, infoname, s1, s2, f1, f2, f3); \
711                                         #endif \
712                                         #if centername != NO_MSG \
713                                                 Local_Notification(MSG_CENTER, centername, s1, s2, f1, f2, f3); \
714                                         #endif \
715                                 } }
716                         MSG_DEATH_NOTIFICATIONS
717                         #undef MSG_DEATH_NOTIF
718                         break;
719                 }
720         }
721 }
722 #endif
723
724
725 // =========================
726 //  Notification Networking
727 // =========================
728
729 #ifdef CSQC
730 void Read_Notification(void)
731 {
732         float net_type = ReadByte();
733         float net_name = ReadShort();
734
735         float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
736         float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
737
738         //print("stringcount = ", ftos(stringcount), ", floatcount = ", ftos(floatcount), ".\n");
739         
740         Local_Notification(net_type, net_name,
741                 ((stringcount >= 1) ? ReadString() : ""),
742                 ((stringcount == 2) ? ReadString() : ""),
743                 ((floatcount >= 1) ? ReadLong() : 0),
744                 ((floatcount >= 2) ? ReadLong() : 0),
745                 ((floatcount == 3) ? ReadLong() : 0));
746 }
747 #endif
748
749 #ifdef SVQC
750 void Send_Notification(entity client, float broadcast, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
751 {
752         if(net_type && net_name)
753         {
754                 //print("notification: ", Get_Field_Value(F_NAME, net_type, net_name), ": ", ftos(net_name), ".\n");
755                 dprint("Send_Notification(", ftos(net_type), ", ", Get_Field_Value(F_NAME, net_type, net_name), strcat(", ", s1, ", ", s2, ", ", ftos(f1), strcat(", ", ftos(f2), ", ", ftos(f3), ");\n")));
756
757                 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
758                 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
759                 
760                 if(notif_stringcount(s1, s2) > stringcount) { backtrace("Too many string arguments for notification!\n"); return; }
761                 if(notif_floatcount(f1, f2, f3) > floatcount) { backtrace("Too many float arguments for notification!\n"); return; }
762
763                 if(broadcast == MSG_ONE)
764                 {
765                         if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
766                         {
767                                 // personal/direct notification sent to ONE person and their spectators
768                                 msg_entity = client;
769                                 WRITESPECTATABLE_MSG_ONE({
770                                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
771                                         WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
772                                         WriteByte(MSG_ONE, net_type);
773                                         WriteShort(MSG_ONE, net_name);
774                                         if(stringcount >= 1) { WriteString(MSG_ONE, s1); }
775                                         if(stringcount == 2) { WriteString(MSG_ONE, s2); }
776                                         if(floatcount >= 1) { WriteLong(MSG_ONE, f1); }
777                                         if(floatcount >= 2) { WriteLong(MSG_ONE, f2); }
778                                         if(floatcount == 3) { WriteLong(MSG_ONE, f3); }
779                                 });
780                         }
781                 }
782                 else if(broadcast == MSG_ALL)
783                 {
784                         // global notification sent to EVERYONE
785                         WriteByte(MSG_ALL, SVC_TEMPENTITY);
786                         WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
787                         WriteByte(MSG_ALL, net_type);
788                         WriteShort(MSG_ALL, net_name);
789                         if(stringcount >= 1) { WriteString(MSG_ALL, s1); }
790                         if(stringcount == 2) { WriteString(MSG_ALL, s2); }
791                         if(floatcount >= 1) { WriteLong(MSG_ALL, f1); }
792                         if(floatcount >= 2) { WriteLong(MSG_ALL, f2); }
793                         if(floatcount == 3) { WriteLong(MSG_ALL, f3); }
794                 }
795                 else { backtrace("Unknown MSG_ type to write with!\n"); }
796
797                 if(!server_is_local && (net_type == MSG_INFO))
798                 {
799                         #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
800                                 { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
801                         MSG_INFO_NOTIFICATIONS
802                         #undef MSG_INFO_NOTIF
803                 }
804         }
805         else { backtrace("Incorrect usage of Send_Notification!\n"); }
806 }
807
808 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
809 {
810         entity tmp_entity;
811         FOR_EACH_REALCLIENT(tmp_entity)
812         {
813                 if(tmp_entity.classname == STR_PLAYER)
814                 if(tmp_entity.team == targetteam)
815                 if(tmp_entity != except)
816                 {
817                         Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
818                 }
819         }
820 }
821
822 // WARNING: use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(world, MSG_ALL, ...)
823 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
824 {
825         entity tmp_entity;
826         FOR_EACH_REALCLIENT(tmp_entity)
827         {
828                 if((tmp_entity.classname == STR_PLAYER) || spectators)
829                 if(tmp_entity != except)
830                 {
831                         Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
832                 }
833         }
834 }
835
836
837 // =============================
838 //  LEGACY NOTIFICATION SYSTEMS
839 // =============================
840
841 void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
842 {
843         WriteByte(MSG_ALL, SVC_TEMPENTITY);
844         WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
845         WriteString(MSG_ALL, s1);
846         WriteString(MSG_ALL, s2);
847         WriteString(MSG_ALL, s3);
848         WriteShort(MSG_ALL, msg);
849         WriteByte(MSG_ALL, type);
850 }
851
852 // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
853 void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
854 {
855         if (clienttype(e) == CLIENTTYPE_REAL)
856         {
857                 msg_entity = e;
858                 WRITESPECTATABLE_MSG_ONE({
859                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
860                         WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
861                         WriteString(MSG_ONE, s1);
862                         WriteString(MSG_ONE, s2);
863                         WriteShort(MSG_ONE, msg);
864                         WriteByte(MSG_ONE, type);
865                 });
866         }
867 }
868
869 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
870 {
871         if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
872         {
873                 msg_entity = e;
874                 WRITESPECTATABLE_MSG_ONE({
875                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
876                         WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
877                         WriteByte(MSG_ONE, id);
878                         WriteString(MSG_ONE, s);
879                         if (id != 0 && s != "")
880                         {
881                                 WriteByte(MSG_ONE, duration);
882                                 WriteByte(MSG_ONE, countdown_num);
883                         }
884                 });
885         }
886 }
887 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
888 {
889         Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
890 }
891 #endif