1 // ================================================
2 // Unified notification system, written by Samual
3 // Last updated: December, 2012
4 // ================================================
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
13 #define NO_FL_ARG -12345
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)
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)
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)
37 Acquire special information to generate for display in the
38 notification from variables networked to the client.
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
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
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
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
75 // do nothing for the other programs, they don't need cvars (those are just for the clients)
76 #define ADD_CSQC_AUTOCVAR(name)
80 // ====================================
81 // Notifications List and Information
82 // ====================================
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:
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)
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)
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
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.
116 Check out the function calls for string CCR(...) and
117 string TCR(...) to better understand how these codes work.
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 ^_^
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))) \
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))) \
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))) \
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_MARBLES_LOST, 2, 1, XPND3(s1, s2, WEAPON_NAME), XPND2("", ""), "", _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "")
193 #define MULTITEAM_CENTER(prefix,teams,strnum,flnum,args,cpid,durcnt,normal,gentle) \
194 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))) \
195 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))) \
197 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))) \
200 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))) \
202 #define MSG_CENTER_NOTIFICATIONS \
203 MSG_CENTER_NOTIF(CENTER_EMPTY, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), "", "") \
204 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."), "") \
205 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."), "") \
206 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"), "") \
207 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"), "") \
208 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"), "") \
209 MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTING, 1, 0, s1, CPID_CTF_PASS, XPND2(0, 0), _("^BGRequesting %s^BG to pass you the flag"), "") \
210 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"), "") \
211 MULTITEAM_CENTER(CENTER_CTF_RETURN_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou returned the ^TC^TT^BG flag!"), "") \
212 MULTITEAM_CENTER(CENTER_CTF_CAPTURE_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou captured the ^TC^TT^BG flag!"), "") \
213 MULTITEAM_CENTER(CENTER_CTF_PICKUP_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou got the ^TC^TT^BG flag!"), "") \
214 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!"), "") \
215 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!"), "") \
216 MSG_CENTER_NOTIF(CENTER_CTF_PICKUP_ENEMY, 1, 0, s1, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
217 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!"), "") \
218 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!"), "") \
219 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!"), "") \
220 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."), "") \
221 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CUSTOM, 2, 0, s2, NO_CPID, XPND2(0, 0), _("^K1You were %s"), "") \
222 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!")) \
223 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_VOID, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1Watch your step!"), "") \
224 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SUICIDE, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You committed suicide!"), _("^K1You ended it all!")) \
225 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...")) \
226 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")) \
227 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CAMP, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1Die camper!"), _("^K1Reconsider your tactics, camper!")) \
228 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!")) \
229 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_TEAMCHANGE, 0, 1, DEATH_TEAM, NO_CPID, XPND2(0, 0), _("^BGYou are now on: %s"), "") \
230 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"), "") \
231 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_FALL, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You hit the ground with a crunch!"), "") \
232 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!"), "") \
233 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!")) \
234 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_LAVA, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You couldn't stand the heat!"), "") \
235 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SLIME, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You melted away in slime!"), "") \
236 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SHOOTING_STAR, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You became a shooting star!"), "") \
237 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SWAMP, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You got stuck in a swamp!"), "") \
238 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CHEAT, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You unfairly eliminated yourself!"), "") \
239 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_TOUCHEXPLODE, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You died in an accident!"), "") \
240 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")) \
241 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")) \
242 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")) \
243 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!")) \
244 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")) \
245 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")) \
246 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")) \
247 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!")) \
248 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")) \
249 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")) \
250 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")) \
251 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")) \
252 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")) \
253 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")) \
254 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")) \
255 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!")) \
256 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!")) \
257 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")) \
258 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!"), "")
260 #define MSG_WEAPON_NOTIFICATIONS \
261 MSG_WEAPON_NOTIF(WEAPON_EMPTY, NO_MSG, NO_MSG) \
262 MSG_WEAPON_NOTIF(WEAPON_MARBLES_LOST, INFO_WEAPON_MARBLES_LOST, CENTER_WEAPON_MARBLES_LOST)
264 #define MSG_DEATH_NOTIFICATIONS \
265 MSG_DEATH_NOTIF(DEATH_EMPTY, NO_MSG, NO_MSG) \
266 MSG_DEATH_NOTIF(DEATH_SELF_CUSTOM, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_CUSTOM) \
267 MSG_DEATH_NOTIF(DEATH_SELF_GENERIC, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_GENERIC) \
268 MSG_DEATH_NOTIF(DEATH_SELF_VOID, INFO_DEATH_SELF_VOID, CENTER_DEATH_SELF_VOID) \
269 MSG_DEATH_NOTIF(DEATH_SELF_SUICIDE, INFO_DEATH_SELF_SUICIDE, CENTER_DEATH_SELF_SUICIDE) \
270 MSG_DEATH_NOTIF(DEATH_SELF_NOAMMO, INFO_DEATH_SELF_NOAMMO, CENTER_DEATH_SELF_NOAMMO) \
271 MSG_DEATH_NOTIF(DEATH_SELF_ROT, INFO_DEATH_SELF_ROT, CENTER_DEATH_SELF_ROT) \
272 MSG_DEATH_NOTIF(DEATH_SELF_CAMP, INFO_DEATH_SELF_CAMP, CENTER_DEATH_SELF_CAMP) \
273 MSG_DEATH_NOTIF(DEATH_SELF_BETRAYAL, INFO_DEATH_SELF_BETRAYAL, CENTER_DEATH_SELF_BETRAYAL) \
274 MSG_DEATH_NOTIF(DEATH_SELF_TEAMCHANGE, INFO_DEATH_SELF_TEAMCHANGE, CENTER_DEATH_SELF_TEAMCHANGE) \
275 MSG_DEATH_NOTIF(DEATH_SELF_AUTOTEAMCHANGE, INFO_DEATH_SELF_AUTOTEAMCHANGE, CENTER_DEATH_SELF_AUTOTEAMCHANGE) \
276 MSG_DEATH_NOTIF(DEATH_SELF_FALL, INFO_DEATH_SELF_FALL, CENTER_DEATH_SELF_FALL) \
277 MSG_DEATH_NOTIF(DEATH_SELF_DROWN, INFO_DEATH_SELF_DROWN, CENTER_DEATH_SELF_DROWN) \
278 MSG_DEATH_NOTIF(DEATH_SELF_FIRE, INFO_DEATH_SELF_FIRE, CENTER_DEATH_SELF_FIRE) \
279 MSG_DEATH_NOTIF(DEATH_SELF_LAVA, INFO_DEATH_SELF_LAVA, CENTER_DEATH_SELF_LAVA) \
280 MSG_DEATH_NOTIF(DEATH_SELF_SLIME, INFO_DEATH_SELF_SLIME, CENTER_DEATH_SELF_SLIME) \
281 MSG_DEATH_NOTIF(DEATH_SELF_SHOOTING_STAR, INFO_DEATH_SELF_SHOOTING_STAR, CENTER_DEATH_SELF_SHOOTING_STAR) \
282 MSG_DEATH_NOTIF(DEATH_SELF_SWAMP, INFO_DEATH_SELF_SWAMP, CENTER_DEATH_SELF_SWAMP) \
283 MSG_DEATH_NOTIF(DEATH_SELF_CHEAT, INFO_DEATH_SELF_CHEAT, CENTER_DEATH_SELF_CHEAT) \
284 MSG_DEATH_NOTIF(DEATH_SELF_TOUCHEXPLODE, INFO_DEATH_SELF_TOUCHEXPLODE, CENTER_DEATH_SELF_TOUCHEXPLODE) \
285 MSG_DEATH_NOTIF(DEATH_MURDER_TELEFRAG, INFO_DEATH_MURDER_TELEFRAG, NO_MSG) \
286 MSG_DEATH_NOTIF(DEATH_MURDER_FALL, INFO_DEATH_MURDER_FALL, NO_MSG) \
287 MSG_DEATH_NOTIF(DEATH_MURDER_DROWN, INFO_DEATH_MURDER_DROWN, NO_MSG) \
288 MSG_DEATH_NOTIF(DEATH_MURDER_LAVA, INFO_DEATH_MURDER_LAVA, NO_MSG) \
289 MSG_DEATH_NOTIF(DEATH_MURDER_SLIME, INFO_DEATH_MURDER_SLIME, NO_MSG) \
290 MSG_DEATH_NOTIF(DEATH_MURDER_SHOOTING_STAR, INFO_DEATH_MURDER_SHOOTING_STAR, NO_MSG) \
291 MSG_DEATH_NOTIF(DEATH_MURDER_SWAMP, INFO_DEATH_MURDER_SWAMP, NO_MSG) \
292 MSG_DEATH_NOTIF(DEATH_MURDER_VOID, INFO_DEATH_MURDER_VOID, NO_MSG) \
293 MSG_DEATH_NOTIF(DEATH_MURDER_TOUCHEXPLODE, INFO_DEATH_MURDER_TOUCHEXPLODE, NO_MSG) \
294 MSG_DEATH_NOTIF(DEATH_MURDER_CHEAT, INFO_DEATH_MURDER_CHEAT, NO_MSG) \
295 MSG_DEATH_NOTIF(DEATH_MURDER_FIRE, INFO_DEATH_MURDER_FIRE, NO_MSG) \
296 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG, NO_MSG, CENTER_DEATH_MURDER_FRAG) \
297 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED, NO_MSG, CENTER_DEATH_MURDER_FRAGGED) \
298 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAG) \
299 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED) \
300 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_FIRST, INFO_DEATH_FIRSTBLOOD, CENTER_DEATH_MURDER_FRAG_FIRST) \
301 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_FIRST, NO_MSG, CENTER_DEATH_MURDER_FRAGGED_FIRST) \
302 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_FIRST, INFO_DEATH_FIRSTBLOOD, CENTER_DEATH_MURDER_TYPEFRAG_FIRST) \
303 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_FIRST, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST) \
304 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_FRAG_VERBOSE) \
305 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_FRAGGED_VERBOSE) \
306 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE) \
307 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE) \
308 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_FIRST_VERBOSE, INFO_DEATH_FIRSTBLOOD, CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE) \
309 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_FIRST_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE) \
310 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE, INFO_DEATH_FIRSTBLOOD, CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE) \
311 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE) \
312 MSG_DEATH_NOTIF(DEATH_TEAMKILL_FRAG, NO_MSG, CENTER_DEATH_TEAMKILL_FRAG) \
313 MSG_DEATH_NOTIF(DEATH_TEAMKILL_FRAGGED, NO_MSG, CENTER_DEATH_TEAMKILL_FRAGGED)
316 // ====================================
317 // Initialization/Create Declarations
318 // ====================================
320 #define NOTIF_FIRST 1
321 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
322 float NOTIF_INFO_COUNT;
323 float NOTIF_CENTER_COUNT;
324 float NOTIF_WEAPON_COUNT;
325 float NOTIF_DEATH_COUNT;
326 float NOTIF_CPID_COUNT;
328 #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
329 ADD_CSQC_AUTOCVAR(name) \
331 void RegisterNotification_##name() \
333 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
334 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_INFO_COUNT, "notifications") \
336 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
338 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
339 ADD_CSQC_AUTOCVAR(name) \
342 void RegisterNotification_##name() \
344 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
345 SET_FIELD_COUNT(cpid, NOTIF_FIRST, NOTIF_CPID_COUNT) \
346 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_CENTER_COUNT, "notifications") \
348 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
350 #define MSG_WEAPON_NOTIF(name,infoname,centername) \
351 ADD_CSQC_AUTOCVAR(name) \
353 void RegisterNotification_##name() \
355 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_WEAPON_COUNT) \
356 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_WEAPON_COUNT, "notifications") \
358 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
360 #define MSG_DEATH_NOTIF(name,infoname,centername) \
361 ADD_CSQC_AUTOCVAR(name) \
363 void RegisterNotification_##name() \
365 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_DEATH_COUNT) \
366 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_DEATH_COUNT, "notifications") \
368 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
370 // NOW we actually activate the declarations
371 MSG_INFO_NOTIFICATIONS
372 MSG_CENTER_NOTIFICATIONS
373 MSG_WEAPON_NOTIFICATIONS
374 MSG_DEATH_NOTIFICATIONS
375 #undef MSG_INFO_NOTIF
376 #undef MSG_CENTER_NOTIF
377 #undef MSG_WEAPON_NOTIF
378 #undef MSG_DEATH_NOTIF
380 // ======================
381 // Supporting Functions
382 // ======================
384 // select between the normal or the gentle message string based on client (or server) settings
385 string normal_or_gentle(string normal, string gentle)
389 if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
391 if(autocvar_sv_gentle)
393 return ((gentle != "") ? gentle : normal);
401 float notif_stringcount(string s1, string s2)
404 if(s1 != NO_STR_ARG) ++stringcount;
405 if(s2 != NO_STR_ARG) ++stringcount;
409 float notif_floatcount(float f1, float f2, float f3)
412 if(f1 != NO_FL_ARG) ++floatcount;
413 if(f2 != NO_FL_ARG) ++floatcount;
414 if(f3 != NO_FL_ARG) ++floatcount;
418 // get the actual name of a notification and return it as a string
419 string Get_Field_Value(float field, float net_type, float net_name)
423 #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \
424 if(field == F_NAME) { output = VAR_TO_TEXT(name); } \
425 else if(field == F_STRNUM) { output = ftos(strnum); } \
426 else if(field == F_FLNUM) { output = ftos(flnum); }
432 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
433 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
434 MSG_INFO_NOTIFICATIONS
435 #undef MSG_INFO_NOTIF
440 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
441 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
442 MSG_CENTER_NOTIFICATIONS
443 #undef MSG_CENTER_NOTIF
448 #define MSG_WEAPON_NOTIF(name,infoname,centername) \
449 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name, \
450 max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \
451 max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } }
452 MSG_WEAPON_NOTIFICATIONS
453 #undef MSG_WEAPON_NOTIF
458 #define MSG_DEATH_NOTIF(name,infoname,centername) \
459 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name, \
460 max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \
461 max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } }
462 MSG_DEATH_NOTIFICATIONS
463 #undef MSG_DEATH_NOTIF
468 #undef GET_FIELD_VALUE_OUTPUT
473 string TCR(string input, string teamcolor, string teamtext)
476 input = strreplace("^TC", teamcolor, input);
477 input = strreplace("^TT", teamtext, input);
481 // color code replace, place inside of sprintf and parse the string
482 string CCR(string input)
484 // foreground/normal colors
485 input = strreplace("^F1", "^2", input); // primary priority (important names, etc)
486 input = strreplace("^F2", "^3", input); // secondary priority (items, locations, numbers, etc)
489 input = strreplace("^K1", "^1", input); // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
490 input = strreplace("^K2", "^3", input); // similar to above, but less important... OR, a highlight out of above message type
491 input = strreplace("^K3", "^4", input); // "good" or "beneficial" text (you fragging someone, etc)
494 input = strreplace("^BG", "^7", input); // neutral/unimportant text
495 input = strreplace("^N", "^7", input); // "none"-- reset to white...
500 // =============================
501 // Debug/Maintenance Functions
502 // =============================
504 #define NOTIF_Write(type,name,text) fputs(fh, (sprintf("seta %s 1 // %s - %s\n", name, type, strreplace("\n", "\\n", text))))
505 void Dump_Notifications(float fh)
507 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) { NOTIF_Write("MSG_INFO", VAR_TO_TEXT(name), normal); }
508 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) { NOTIF_Write("MSG_CENTER", VAR_TO_TEXT(name), normal); }
509 #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))); }
510 #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))); }
511 MSG_INFO_NOTIFICATIONS
512 MSG_CENTER_NOTIFICATIONS
513 MSG_WEAPON_NOTIFICATIONS
514 MSG_DEATH_NOTIFICATIONS
515 #undef MSG_INFO_NOTIF
516 #undef MSG_CENTER_NOTIF
517 #undef MSG_WEAPON_NOTIF
518 #undef MSG_DEATH_NOTIF
523 // ===============================
524 // Frontend Notification Pushing
525 // ===============================
528 #define KN_MAX_ENTRIES 10
530 float killnotify_times[KN_MAX_ENTRIES];
531 string killnotify_icon[KN_MAX_ENTRIES];
532 string killnotify_attackers[KN_MAX_ENTRIES];
533 string killnotify_victims[KN_MAX_ENTRIES];
534 // 0 = "Y [used by] X", 1 = "X [did action to] Y"
535 void HUD_Notify_Push(string icon, string attacker, string victim)
540 if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
541 killnotify_times[kn_index] = time;
544 if(killnotify_icon[kn_index]) { strunzone(killnotify_icon[kn_index]); }
545 killnotify_icon[kn_index] = strzone(icon);
548 if(killnotify_attackers[kn_index]) { strunzone(killnotify_attackers[kn_index]); }
549 killnotify_attackers[kn_index] = strzone(attacker);
552 if(killnotify_victims[kn_index]) { strunzone(killnotify_victims[kn_index]); }
553 killnotify_victims[kn_index] = strzone(victim);
557 void Local_Notification(float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
559 //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")));
564 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
565 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
567 print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); \
568 if(strtolower(icon) != "") { HUD_Notify_Push(icon, hudargs); } \
570 MSG_INFO_NOTIFICATIONS
571 #undef MSG_INFO_NOTIF
576 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
577 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
579 centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); \
581 MSG_CENTER_NOTIFICATIONS
582 #undef MSG_CENTER_NOTIF
587 #define MSG_WEAPON_NOTIF(name,infoname,centername) \
588 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
590 #if infoname != NO_MSG \
591 Local_Notification(MSG_INFO, infoname, s1, s2, f1, f2, f3); \
593 #if centername != NO_MSG \
594 Local_Notification(MSG_CENTER, centername, s1, s2, f1, f2, f3); \
597 MSG_WEAPON_NOTIFICATIONS
598 #undef MSG_WEAPON_NOTIF
603 #define MSG_DEATH_NOTIF(name,infoname,centername) \
604 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
606 #if infoname != NO_MSG \
607 Local_Notification(MSG_INFO, infoname, s1, s2, f1, f2, f3); \
609 #if centername != NO_MSG \
610 Local_Notification(MSG_CENTER, centername, s1, s2, f1, f2, f3); \
613 MSG_DEATH_NOTIFICATIONS
614 #undef MSG_DEATH_NOTIF
622 // =========================
623 // Notification Networking
624 // =========================
627 void Read_Notification(void)
629 float net_type = ReadByte();
630 float net_name = ReadShort();
632 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
633 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
635 //print("stringcount = ", ftos(stringcount), ", floatcount = ", ftos(floatcount), ".\n");
637 Local_Notification(net_type, net_name,
638 ((stringcount >= 1) ? ReadString() : ""),
639 ((stringcount == 2) ? ReadString() : ""),
640 ((floatcount >= 1) ? ReadLong() : 0),
641 ((floatcount >= 2) ? ReadLong() : 0),
642 ((floatcount == 3) ? ReadLong() : 0));
647 void Send_Notification(entity client, float broadcast, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
649 if(net_type && net_name)
651 //print("notification: ", Get_Field_Value(F_NAME, net_type, net_name), ": ", ftos(net_name), ".\n");
652 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")));
654 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
655 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
657 if(notif_stringcount(s1, s2) > stringcount) { backtrace("Too many string arguments for notification!\n"); return; }
658 if(notif_floatcount(f1, f2, f3) > floatcount) { backtrace("Too many float arguments for notification!\n"); return; }
660 if(broadcast == MSG_ONE)
662 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
664 // personal/direct notification sent to ONE person and their spectators
666 WRITESPECTATABLE_MSG_ONE({
667 WriteByte(MSG_ONE, SVC_TEMPENTITY);
668 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
669 WriteByte(MSG_ONE, net_type);
670 WriteShort(MSG_ONE, net_name);
671 if(stringcount >= 1) { WriteString(MSG_ONE, s1); }
672 if(stringcount == 2) { WriteString(MSG_ONE, s2); }
673 if(floatcount >= 1) { WriteLong(MSG_ONE, f1); }
674 if(floatcount >= 2) { WriteLong(MSG_ONE, f2); }
675 if(floatcount == 3) { WriteLong(MSG_ONE, f3); }
679 else if(broadcast == MSG_ALL)
681 // global notification sent to EVERYONE
682 WriteByte(MSG_ALL, SVC_TEMPENTITY);
683 WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
684 WriteByte(MSG_ALL, net_type);
685 WriteShort(MSG_ALL, net_name);
686 if(stringcount >= 1) { WriteString(MSG_ALL, s1); }
687 if(stringcount == 2) { WriteString(MSG_ALL, s2); }
688 if(floatcount >= 1) { WriteLong(MSG_ALL, f1); }
689 if(floatcount >= 2) { WriteLong(MSG_ALL, f2); }
690 if(floatcount == 3) { WriteLong(MSG_ALL, f3); }
692 else { backtrace("Unknown MSG_ type to write with!\n"); }
694 if(!server_is_local && (net_type == MSG_INFO))
696 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
697 { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
698 MSG_INFO_NOTIFICATIONS
699 #undef MSG_INFO_NOTIF
702 else { backtrace("Incorrect usage of Send_Notification!\n"); }
705 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
708 FOR_EACH_REALCLIENT(tmp_entity)
710 if(tmp_entity.classname == STR_PLAYER)
711 if(tmp_entity.team == targetteam)
712 if(tmp_entity != except)
714 Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
719 // WARNING: use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(world, MSG_ALL, ...)
720 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
723 FOR_EACH_REALCLIENT(tmp_entity)
725 if((tmp_entity.classname == STR_PLAYER) || spectators)
726 if(tmp_entity != except)
728 Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
734 // =============================
735 // LEGACY NOTIFICATION SYSTEMS
736 // =============================
738 void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
740 WriteByte(MSG_ALL, SVC_TEMPENTITY);
741 WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
742 WriteString(MSG_ALL, s1);
743 WriteString(MSG_ALL, s2);
744 WriteString(MSG_ALL, s3);
745 WriteShort(MSG_ALL, msg);
746 WriteByte(MSG_ALL, type);
749 // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
750 void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
752 if (clienttype(e) == CLIENTTYPE_REAL)
755 WRITESPECTATABLE_MSG_ONE({
756 WriteByte(MSG_ONE, SVC_TEMPENTITY);
757 WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
758 WriteString(MSG_ONE, s1);
759 WriteString(MSG_ONE, s2);
760 WriteShort(MSG_ONE, msg);
761 WriteByte(MSG_ONE, type);
766 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
768 if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
771 WRITESPECTATABLE_MSG_ONE({
772 WriteByte(MSG_ONE, SVC_TEMPENTITY);
773 WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
774 WriteByte(MSG_ONE, id);
775 WriteString(MSG_ONE, s);
776 if (id != 0 && s != "")
778 WriteByte(MSG_ONE, duration);
779 WriteByte(MSG_ONE, countdown_num);
784 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
786 Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);