1 // ================================================
2 // Unified notification system, written by Samual
3 // Last updated: September, 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)
12 #define NO_FL_ARG -12345
18 // allow sending of notifications to also pass through to spectators (specifically for centerprints)
20 #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
21 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
22 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
27 #define NOTIF_MATCH(a,b) if(min(NOTIF_MAX, a) == b)
29 string got_commandkey;
30 #define ADD_CSQC_AUTOCVAR(name) var float autocvar_notification_##name = TRUE;
31 var float autocvar_notification_ctf_capture_verbose = TRUE;
32 var float autocvar_notification_ctf_pickup_team_verbose = TRUE;
33 var float autocvar_notification_ctf_pickup_enemy_verbose = TRUE;
34 #define CHECK_AUTOCVAR(name) if(autocvar_notification_##name)
35 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
36 #define PASS_KEY ((((got_commandkey = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(got_commandkey, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), got_commandkey) : "")
37 #define FRAG_SPREE (((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) : "")
38 #define FRAG_PING ((f2 != BOT_PING) ? sprintf(CCR(_("\n(Ping ^2%d^BG)")), f2) : "")
39 #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) : ""))
40 //#define FRAG_POS ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : "")
42 #define ADD_CSQC_AUTOCVAR(name)
47 If BELOW negative maxplayers, you dropped a place lower
48 If below 0, you are tied for that place
49 If above 0, you are holding that place alone
50 If above positive maxplayers, you moved up a place
52 float Should_Print_Score_Pos
54 string Read_Score_Pos(float num)
59 float Form_Score_Pos(entity player)
64 // ====================================
65 // Notifications List and Information
66 // ====================================
68 List of all notifications (including identifiers and display information)
69 Format: name, strnum, flnum, args, *icon/CPID, *durcnt, normal, gentle
70 Asterisked fields are not present in all notification types.
73 Number of STRING arguments (so that networking knows how many to send/receive)
74 Number of FLOAT arguments (so that networking knows how many to send/receive)
75 Arguments for sprintf(string, args), if no args needed then use ""
77 MSG_INFO: STRING: icon string name for the hud notify panel, "" if no icon is used
78 MSG_CENTER: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
80 MSG_CENTER: XPND2(FLOAT, FLOAT): extra arguments for centerprint messages
81 Normal message (string for sprintf when gentle messages are NOT enabled)
82 Gentle message (string for sprintf when gentle messages ARE enabled)
84 Messages have ^F1, ^F2, and ^BG in them-- these are replaced
85 with colors according to the cvars the user has chosen.
86 ^F1 = highest priority, "primary"
87 ^F2 = next highest priority, "secondary"
88 ^BG = normal/less important priority, "tertiary"
90 Guidlines (please try and follow these):
91 -ALWAYS start the string with a color, preferably background.
92 -ALWAYS reset a color after a name (this way they don't set it for the whole string).
93 -NEVER re-declare an event twice.
94 -NEVER add or remove fields from the format, it SHOULD already work.
95 -MSG_INFO messages must ALWAYS end with a new line: \n
96 -Be clean and simple with your notification naming,
97 nothing too long for the name field... Abbreviations are your friend. :D
98 -Keep the spacing as clean as possible... if the arguments are abnormally long,
99 it's okay to go out of line a bit... but try and keep it clean still.
100 -Keep the notifications in alphabetical order.
101 ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^
104 // weaponorder[f1].netname
106 #define MULTITEAM_INFO(prefix,teams,strnum,flnum,args,hudargs,icon,normal,gentle) \
107 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))) \
108 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))) \
110 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))) \
113 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))) \
115 #define MSG_INFO_NOTIFICATIONS \
116 MSG_INFO_NOTIF(INFO_EMPTY, 0, 0, NO_STR_ARG, XPND2("", ""), "", "", "") \
117 MULTITEAM_INFO(INFO_SCORES_, 4, 0, 0, NO_STR_ARG, XPND2("", ""), "", _("^TC^TT ^BGteam scores!\n"), "") \
118 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"), "") \
119 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"), "") \
120 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"), "") \
121 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"), "") \
122 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"), "") \
123 MULTITEAM_INFO(INFO_CTF_FLAGRETURN_TIMEOUT_, 2, 0, 0, NO_STR_ARG, XPND2("", ""), "", _("^BGThe ^TC^TT^BG flag has returned to the base\n"), "") \
124 MULTITEAM_INFO(INFO_CTF_PICKUP_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_taken", _("^BG%s^BG got the ^TC^TT^BG flag\n"), "") \
125 MULTITEAM_INFO(INFO_CTF_RETURN_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag\n"), "") \
126 MULTITEAM_INFO(INFO_CTF_LOST_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_lost", _("^BG%s^BG lost the ^TC^TT^BG flag\n"), "") \
127 MULTITEAM_INFO(INFO_CTF_CAPTURE_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag\n"), "") \
128 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"), "") \
129 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"), "") \
130 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"), "") \
131 #undef MSG_INFO_NOTIF
133 #define MULTITEAM_CENTER(prefix,teams,strnum,flnum,args,cpid,durcnt,normal,gentle) \
134 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))) \
135 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))) \
137 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))) \
140 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))) \
142 #define MSG_CENTER_NOTIFICATIONS \
143 MSG_CENTER_NOTIF(CENTER_EMPTY, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), "", "") \
144 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."), "") \
145 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."), "") \
146 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"), "") \
147 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"), "") \
148 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"), "") \
149 MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTING, 1, 0, s1, CPID_CTF_PASS, XPND2(0, 0), _("^BGRequesting %s^BG to pass you the flag"), "") \
150 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"), "") \
151 MULTITEAM_CENTER(CENTER_CTF_RETURN_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou returned the ^TC^TT^BG flag!"), "") \
152 MULTITEAM_CENTER(CENTER_CTF_CAPTURE_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou captured the ^TC^TT^BG flag!"), "") \
153 MULTITEAM_CENTER(CENTER_CTF_PICKUP_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou got the ^TC^TT^BG flag!"), "") \
154 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!"), "") \
155 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!"), "") \
156 MSG_CENTER_NOTIF(CENTER_CTF_PICKUP_ENEMY, 1, 0, s1, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
157 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!"), "") \
158 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!"), "") \
159 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!"), "") \
160 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."), "") \
161 MSG_CENTER_NOTIF(CENTER_DEATH_FRAG, 1, 1, XPND2(FRAG_SPREE, s1), NO_CPID, XPND2(0, 0), _("^K3%sYou fragged ^BG%s"), _("^K3%sYou scored against ^BG%s")) \
162 MSG_CENTER_NOTIF(CENTER_DEATH_FRAGGED, 1, 0, s1, NO_CPID, XPND2(0, 0), _("^K1You were fragged by ^BG%s"), _("^K1You were scored against by ^BG%s")) \
163 MSG_CENTER_NOTIF(CENTER_DEATH_TYPEFRAG, 1, 1, XPND2(FRAG_SPREE, s1), NO_CPID, XPND2(0, 0), _("^K1%sYou typefragged ^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing")) \
164 MSG_CENTER_NOTIF(CENTER_DEATH_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!")) \
165 MSG_CENTER_NOTIF(CENTER_DEATH_FRAG_FIRST, 1, 0, s1, NO_CPID, XPND2(0, 0), _("^K3First blood! You fragged ^BG%s"), _("^K3First score! You scored against ^BG%s")) \
166 MSG_CENTER_NOTIF(CENTER_DEATH_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")) \
167 MSG_CENTER_NOTIF(CENTER_DEATH_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")) \
168 MSG_CENTER_NOTIF(CENTER_DEATH_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!")) \
169 MSG_CENTER_NOTIF(CENTER_DEATH_FRAG_VERBOSE, 1, 2, XPND3(FRAG_SPREE, s1, FRAG_PING), NO_CPID, XPND2(0, 0), _("^K3You fragged ^BG%s^BG%s"), _("^K3You scored against ^BG%s^BG%s")) \
170 MSG_CENTER_NOTIF(CENTER_DEATH_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")) \
171 MSG_CENTER_NOTIF(CENTER_DEATH_TYPEFRAG_VERBOSE, 1, 2, XPND3(FRAG_SPREE, 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")) \
172 MSG_CENTER_NOTIF(CENTER_DEATH_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")) \
173 MSG_CENTER_NOTIF(CENTER_DEATH_FRAG_FIRST_VERBOSE, 1, 1, s1, NO_CPID, XPND2(0, 0), _("^K3First blood! You fragged ^BG%s"), _("^K3First score! You scored against ^BG%s")) \
174 MSG_CENTER_NOTIF(CENTER_DEATH_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")) \
175 MSG_CENTER_NOTIF(CENTER_DEATH_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")) \
176 MSG_CENTER_NOTIF(CENTER_DEATH_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!")) \
177 #undef MSG_CENTER_NOTIF
179 #define MSG_WEAPON_NOTIFICATIONS \
180 MSG_WEAPON_NOTIF(DEATH_MARBLES_LOST3, 2, 1, XPND3(s1, s2, f1), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
181 #undef MSG_WEAPON_NOTIF
184 // ====================================
185 // Initialization/Create Declarations
186 // ====================================
188 #define NOTIF_FIRST 1
189 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
190 float NOTIF_INFO_COUNT;
191 float NOTIF_CENTER_COUNT;
192 float NOTIF_WEAPON_COUNT;
193 float NOTIF_CPID_COUNT;
195 #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
196 ADD_CSQC_AUTOCVAR(name) \
198 void RegisterNotification_##name() \
200 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
201 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_INFO_COUNT, "notifications") \
203 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
205 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
206 ADD_CSQC_AUTOCVAR(name) \
209 void RegisterNotification_##name() \
211 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
212 SET_FIELD_COUNT(cpid, NOTIF_FIRST, NOTIF_CPID_COUNT) \
213 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_CENTER_COUNT, "notifications") \
215 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
217 #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
218 ADD_CSQC_AUTOCVAR(name) \
220 void RegisterNotification_##name() \
222 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_WEAPON_COUNT) \
223 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_WEAPON_COUNT, "notifications") \
225 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
227 // NOW we actually activate the declarations
228 MSG_INFO_NOTIFICATIONS
229 MSG_CENTER_NOTIFICATIONS
230 MSG_WEAPON_NOTIFICATIONS
233 // ======================
234 // Supporting Functions
235 // ======================
237 // select between the normal or the gentle message string based on client (or server) settings
238 string normal_or_gentle(string normal, string gentle)
242 if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
244 if(autocvar_sv_gentle)
246 return ((gentle != "") ? gentle : normal);
254 float notif_stringcount(string s1, string s2)
257 if(s1 != NO_STR_ARG) ++stringcount;
258 if(s2 != NO_STR_ARG) ++stringcount;
262 float notif_floatcount(float f1, float f2, float f3)
265 if(f1 != NO_FL_ARG) ++floatcount;
266 if(f2 != NO_FL_ARG) ++floatcount;
267 if(f3 != NO_FL_ARG) ++floatcount;
271 // get the actual name of a notification and return it as a string
272 string Get_Field_Value(float field, float net_type, float net_name)
276 #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \
277 if(field == F_NAME) { output = VAR_TO_TEXT(name); } \
278 else if(field == F_STRNUM) { output = ftos(strnum); } \
279 else if(field == F_FLNUM) { output = ftos(flnum); }
285 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
286 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
287 MSG_INFO_NOTIFICATIONS
292 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
293 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
294 MSG_CENTER_NOTIFICATIONS
299 #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
300 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
301 MSG_WEAPON_NOTIFICATIONS
306 #undef GET_FIELD_VALUE_OUTPUT
311 string TCR(string input, string teamcolor, string teamtext)
313 input = strreplace("^TC", teamcolor, input);
314 input = strreplace("^TT", teamtext, input);
318 // color code replace, place inside of sprintf and parse the string
319 string CCR(string input)
321 // foreground/normal colors
322 input = strreplace("^F1", "^2", input); // primary priority (important names, etc)
323 input = strreplace("^F2", "^3", input); // secondary priority (items, locations, numbers, etc)
326 input = strreplace("^K1", "^1", input); // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
327 input = strreplace("^K2", "^3", input); // similar to above, but less important... OR, a highlight out of above message type
328 input = strreplace("^K3", "^4", input); // "good" or "beneficial" text (you fragging someone, etc)
331 input = strreplace("^BG", "^7", input); // neutral/unimportant text
332 input = strreplace("^N", "^7", input); // "none"-- reset to white...
337 // =============================
338 // Debug/Maintenance Functions
339 // =============================
341 #define NOTIF_Write(type,name,text) fputs(fh, (sprintf("seta %s 1 // %s - %s\n", name, type, strreplace("\n", "\\n", text))))
342 void Dump_Notifications(float fh)
344 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) { NOTIF_Write("MSG_INFO", VAR_TO_TEXT(name), normal); }
345 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) { NOTIF_Write("MSG_CENTER", VAR_TO_TEXT(name), normal); }
346 #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) { NOTIF_Write("MSG_WEAPON", VAR_TO_TEXT(name), normal); }
347 MSG_INFO_NOTIFICATIONS
348 MSG_CENTER_NOTIFICATIONS
349 MSG_WEAPON_NOTIFICATIONS
354 // ===============================
355 // Frontend Notification Pushing
356 // ===============================
359 #define KN_MAX_ENTRIES 10
361 float killnotify_times[KN_MAX_ENTRIES];
362 string killnotify_icon[KN_MAX_ENTRIES];
363 string killnotify_attackers[KN_MAX_ENTRIES];
364 string killnotify_victims[KN_MAX_ENTRIES];
365 // 0 = "Y [used by] X", 1 = "X [did action to] Y"
366 void HUD_Notify_Push(string icon, string attacker, string victim)
371 if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
372 killnotify_times[kn_index] = time;
375 if(killnotify_icon[kn_index]) { strunzone(killnotify_icon[kn_index]); }
376 killnotify_icon[kn_index] = strzone(icon);
379 if(killnotify_attackers[kn_index]) { strunzone(killnotify_attackers[kn_index]); }
380 killnotify_attackers[kn_index] = strzone(attacker);
383 if(killnotify_victims[kn_index]) { strunzone(killnotify_victims[kn_index]); }
384 killnotify_victims[kn_index] = strzone(victim);
388 void Local_Notification(float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
394 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
395 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
397 print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); \
398 if(strtolower(icon) != "") { HUD_Notify_Push(icon, hudargs); } \
400 MSG_INFO_NOTIFICATIONS
405 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
406 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
408 centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); \
410 MSG_CENTER_NOTIFICATIONS
415 #define MSG_WEAPON_NOTIF(name,strnum,flnum,args,normal,gentle) \
416 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
418 print("unhandled\n"); \
420 MSG_WEAPON_NOTIFICATIONS
428 // =========================
429 // Notification Networking
430 // =========================
433 void Read_Notification(void)
435 float net_type = ReadByte();
436 float net_name = ReadShort();
438 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
439 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
441 Local_Notification(net_type, net_name,
442 ((stringcount >= 1) ? ReadString() : ""),
443 ((stringcount == 2) ? ReadString() : ""),
444 ((floatcount >= 1) ? ReadLong() : 0),
445 ((floatcount >= 2) ? ReadLong() : 0),
446 ((floatcount == 3) ? ReadLong() : 0));
451 void Send_Notification(entity client, float broadcast, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
453 if(net_type && net_name)
455 //print("notification: ", Get_Field_Value(F_NAME, net_type, net_name), ": ", ftos(net_name), ".\n");
457 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
458 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
460 if(notif_stringcount(s1, s2) > stringcount) { backtrace("Too many string arguments for notification!\n"); return; }
461 if(notif_floatcount(f1, f2, f3) > floatcount) { backtrace("Too many float arguments for notification!\n"); return; }
463 if(broadcast == MSG_ONE)
465 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
467 // personal/direct notification sent to ONE person and their spectators
469 WRITESPECTATABLE_MSG_ONE({
470 WriteByte(MSG_ONE, SVC_TEMPENTITY);
471 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
472 WriteByte(MSG_ONE, net_type);
473 WriteShort(MSG_ONE, net_name);
474 if(stringcount >= 1) { WriteString(MSG_ONE, s1); }
475 if(stringcount == 2) { WriteString(MSG_ONE, s2); }
476 if(floatcount >= 1) { WriteLong(MSG_ONE, f1); }
477 if(floatcount >= 2) { WriteLong(MSG_ONE, f2); }
478 if(floatcount == 3) { WriteLong(MSG_ONE, f3); }
482 else if(broadcast == MSG_ALL)
484 // global notification sent to EVERYONE
485 WriteByte(MSG_ALL, SVC_TEMPENTITY);
486 WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
487 WriteByte(MSG_ALL, net_type);
488 WriteShort(MSG_ALL, net_name);
489 if(stringcount >= 1) { WriteString(MSG_ALL, s1); }
490 if(stringcount == 2) { WriteString(MSG_ALL, s2); }
491 if(floatcount >= 1) { WriteLong(MSG_ALL, f1); }
492 if(floatcount >= 2) { WriteLong(MSG_ALL, f2); }
493 if(floatcount == 3) { WriteLong(MSG_ALL, f3); }
495 else { backtrace("Unknown MSG_ type to write with!\n"); }
497 if(!server_is_local && (net_type == MSG_INFO))
499 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
500 { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
501 MSG_INFO_NOTIFICATIONS
504 else { backtrace("Incorrect usage of Send_Notification!\n"); }
507 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
510 FOR_EACH_REALCLIENT(tmp_entity)
512 if(tmp_entity.classname == STR_PLAYER)
513 if(tmp_entity.team == targetteam)
514 if(tmp_entity != except)
516 Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
521 // WARNING: use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(..., world, ...)
522 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
525 FOR_EACH_REALCLIENT(tmp_entity)
527 if((tmp_entity.classname == STR_PLAYER) || spectators)
528 if(tmp_entity != except)
530 Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
536 // =============================
537 // LEGACY NOTIFICATION SYSTEMS
538 // =============================
540 void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
542 WriteByte(MSG_ALL, SVC_TEMPENTITY);
543 WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
544 WriteString(MSG_ALL, s1);
545 WriteString(MSG_ALL, s2);
546 WriteString(MSG_ALL, s3);
547 WriteShort(MSG_ALL, msg);
548 WriteByte(MSG_ALL, type);
551 // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
552 void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
554 if (clienttype(e) == CLIENTTYPE_REAL)
557 WRITESPECTATABLE_MSG_ONE({
558 WriteByte(MSG_ONE, SVC_TEMPENTITY);
559 WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
560 WriteString(MSG_ONE, s1);
561 WriteString(MSG_ONE, s2);
562 WriteShort(MSG_ONE, msg);
563 WriteByte(MSG_ONE, type);
568 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
570 if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
573 WRITESPECTATABLE_MSG_ONE({
574 WriteByte(MSG_ONE, SVC_TEMPENTITY);
575 WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
576 WriteByte(MSG_ONE, id);
577 WriteString(MSG_ONE, s);
578 if (id != 0 && s != "")
580 WriteByte(MSG_ONE, duration);
581 WriteByte(MSG_ONE, countdown_num);
586 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
588 Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);