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)
8 #define MSG_NOTIFY 2 // "Global" events to be sent to the notification panel
9 #define MSG_CENTER 3 // "Personal" centerprint messages
10 #define MSG_WEAPON 4 // "Personal" weapon messages (like "You got the Nex", sent to weapon notify panel)
12 // expand multiple arguments into one argument
13 #define XPND4(a,b,c,d) a, b, c, d
14 #define XPND3(a,b,c) a, b, c
15 #define XPND2(a,b) a, b
17 // allow sending of notifications to also pass through to spectators (specifically for centerprints)
19 #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
20 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
21 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
24 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
26 // select between the normal or the gentle message string based on client (or server) settings
27 string normal_or_gentle(string normal, string gentle)
30 if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
32 if(autocvar_sv_gentle)
34 return ((gentle != "") ? gentle : normal);
39 // color code replace, place inside of sprintf and parse the string
40 string CCR(string input)
42 input = strreplace("^F1", "^3", input);
43 input = strreplace("^F2", "^2", input);
44 input = strreplace("^BG", "^7", input);
46 input = strreplace("^N", "^7", input); // "none"-- reset to white
52 // ====================================
53 // Notifications List and Information
54 // ====================================
56 List of all notifications (including identifiers and display information)
57 Format: name, args, *icon/CPID, *durcnt, normal, gentle
58 Asterisked fields are not present in all notification types.
61 Arguments for sprintf(string, args), if no args needed then use ""
63 MSG_NOTIFY: STRING: icon string name for the hud notify panel, "" if no icon is used
64 MSG_CENTER: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
66 MSG_CENTER: XPND2(FLOAT, FLOAT): extra arguments for centerprint messages
67 Normal message (string for sprintf when gentle messages are NOT enabled)
68 Gentle message (string for sprintf when gentle messages ARE enabled)
70 Messages have ^F1, ^F2, and ^BG in them-- these are replaced
71 with colors according to the cvars the user has chosen.
72 ^F1 = highest priority, "primary"
73 ^F2 = next highest priority, "secondary"
74 ^BG = normal/less important priority, "tertiary"
76 Guidlines (please try and follow these):
77 ALWAYS start the string with a color, preferably background.
78 ALWAYS end messages with a new line.
79 ALWAYS properly use tab spacing to even out the notifications.
80 NEVER re-declare an event twice.
81 NEVER add or remove fields from the format, it SHOULD already work.
82 ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^
83 Be clean and simple with your notification naming, nothing too long.
84 Keep the notifications in alphabetical order.
86 #define MSG_INFO_NOTIFICATIONS \
87 MSG_INFO_NOTIF(DEATH_MARBLES_LOST, XPND3(s1, s2, s3), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
90 #define MSG_NOTIFY_NOTIFICATIONS \
91 MSG_NOTIFY_NOTIF(DEATH_MARBLES_LOST2, XPND3(s1, s2, s3), "notify_death", _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
92 #undef MSG_NOTIFY_NOTIF
94 #define MSG_CENTER_NOTIFICATIONS \
95 MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_SHIELDED, "", CPID_CTF_CAPTURESHIELD, 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."), "") \
96 MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_FREE, "", CPID_CTF_CAPTURESHIELD, 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."), "") \
97 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS, XPND2(s1, s2, s3), CPID_CTF_PASS, XPND2(0, 0), _("^BG%s passed the ^F1%s^BG to %s"), "") \
98 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_SENT, XPND2(s1, s2), CPID_CTF_PASS, XPND2(0, 0), _("^BGYou passed the ^F1%s^BG to %s"), "") \
99 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_RECEIVED, XPND2(s1, s2), CPID_CTF_PASS, XPND2(0, 0), _("^BGYou received the ^F1%s^BG from %s"), "") \
100 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_RETURN, s1, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou returned the ^F1%s"), "") \
101 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_CAPTURE, s1, NO_CPID, XPND2(0, 0), _("^BGYou captured the ^F1%s"), "") \
102 #undef MSG_CENTER_NOTIF
104 #define MSG_WEAPON_NOTIFICATIONS \
105 MSG_WEAPON_NOTIF(DEATH_MARBLES_LOST3, XPND3(s1, s2, s3), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
106 #undef MSG_WEAPON_NOTIF
109 // ====================================
110 // Initialization/Create Declarations
111 // ====================================
113 #define NOTIF_FIRST 1
114 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
115 float NOTIF_INFO_COUNT;
116 float NOTIF_NOTIFY_COUNT;
117 float NOTIF_CENTER_COUNT;
118 float NOTIF_WEAPON_COUNT;
119 float NOTIF_CPID_COUNT;
121 #define CHECK_FIELD_AND_COUNT(field,count) if(!field) { field = (NOTIF_FIRST + count); ++count; }
122 #define CHECK_MAX_NOTIFICATIONS(count) if(count == NOTIF_MAX) { error("Maximum notifications hit!\n"); }
124 #define MSG_INFO_NOTIF(name,args,normal,gentle) \
126 void DecNotif_##name() \
128 CHECK_FIELD_AND_COUNT(name, NOTIF_INFO_COUNT) \
129 CHECK_MAX_NOTIFICATIONS(NOTIF_INFO_COUNT) \
131 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
133 #define MSG_NOTIFY_NOTIF(name,args,icon,normal,gentle) \
135 void DecNotif_##name() \
137 CHECK_FIELD_AND_COUNT(name, NOTIF_NOTIFY_COUNT) \
138 CHECK_MAX_NOTIFICATIONS(NOTIF_NOTIFY_COUNT) \
140 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
142 #define MSG_CENTER_NOTIF(name,args,cpid,durcnt,normal,gentle) \
145 void DecNotif_##name() \
147 CHECK_FIELD_AND_COUNT(name, NOTIF_CENTER_COUNT) \
148 CHECK_FIELD_AND_COUNT(cpid, NOTIF_CPID_COUNT) \
149 CHECK_MAX_NOTIFICATIONS(NOTIF_CENTER_COUNT) \
151 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
153 #define MSG_WEAPON_NOTIF(name,args,normal,gentle) \
155 void DecNotif_##name() \
157 CHECK_FIELD_AND_COUNT(name, NOTIF_WEAPON_COUNT) \
158 CHECK_MAX_NOTIFICATIONS(NOTIF_WEAPON_COUNT) \
160 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
162 // NOW we actually activate the declarations
163 MSG_INFO_NOTIFICATIONS
164 MSG_NOTIFY_NOTIFICATIONS
165 MSG_CENTER_NOTIFICATIONS
166 MSG_WEAPON_NOTIFICATIONS
169 // ===============================
170 // Frontend Notification Pushing
171 // ===============================
174 void Local_Notification(float net_type, float net_name, string s1, string s2, string s3)
180 #define MSG_INFO_NOTIF(name,args,normal,gentle) \
181 { if(min(NOTIF_MAX, name) == net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
183 MSG_INFO_NOTIFICATIONS
194 #define MSG_CENTER_NOTIF(name,args,cpid,durcnt,normal,gentle) \
195 { if(min(NOTIF_MAX, name) == net_name) { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); } }
197 MSG_CENTER_NOTIFICATIONS
210 // =========================
211 // Notification Networking
212 // =========================
215 void Send_Notification(float net_type, entity client, float net_name, string s1, string s2, string s3)
217 if(net_type && net_name)
219 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
222 WRITESPECTATABLE_MSG_ONE({
223 WriteByte(MSG_ONE, SVC_TEMPENTITY);
224 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
225 WriteByte(MSG_ONE, net_type);
226 WriteCoord(MSG_ONE, net_name);
227 WriteString(MSG_ONE, s1);
228 WriteString(MSG_ONE, s2);
229 WriteString(MSG_ONE, s3);
233 if(!server_is_local && ((net_type == MSG_INFO || net_type == MSG_NOTIFY) || client == world))
239 #define MSG_INFO_NOTIF(name,args,normal,gentle) \
240 { if(min(NOTIF_MAX, name) == net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
242 MSG_INFO_NOTIFICATIONS
253 else { backtrace("Incorrect usage of Send_Notification!\n"); }
256 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, string s3)
259 FOR_EACH_REALCLIENT(tmp_entity)
261 if(tmp_entity.classname == STR_PLAYER)
262 if(tmp_entity.team == targetteam)
263 if(tmp_entity != except)
265 Send_Notification(net_type, tmp_entity, net_name, s1, s2, s3);
270 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, string s3)
273 FOR_EACH_REALCLIENT(tmp_entity)
275 if((tmp_entity.classname == STR_PLAYER) || spectators)
276 if(tmp_entity != except)
278 Send_Notification(net_type, tmp_entity, net_name, s1, s2, s3);
283 // LEGACY NOTIFICATION SYSTEMS
284 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
286 if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
289 WRITESPECTATABLE_MSG_ONE({
290 WriteByte(MSG_ONE, SVC_TEMPENTITY);
291 WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
292 WriteByte(MSG_ONE, id);
293 WriteString(MSG_ONE, s);
294 if (id != 0 && s != "")
296 WriteByte(MSG_ONE, duration);
297 WriteByte(MSG_ONE, countdown_num);
302 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
304 Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);