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 // collapse multiple arguments into one argument
13 #define CLPS4(s1,s2,s3,s4) s1, s2, s3, s4
14 #define CLPS3(s1,s2,s3) s1, s2, s3
15 #define CLPS2(s1,s2) s1, s2
17 // accumulate functions for declarations
19 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
20 float NOTIF_INFO_COUNT;
21 float NOTIF_NOTIFY_COUNT;
22 float NOTIF_CENTER_COUNT;
23 float NOTIF_WEAPON_COUNT;
24 float NOTIF_CPID_COUNT;
26 #define CHECK_MAX_NOTIFICATIONS(count) if(count == NOTIF_MAX) { error("Maximum notifications hit!\n"); }
28 #define MSG_INFO_NOTIF(name,args,normal,gentle) \
30 void DecNotif_##name() { \
32 name = (NOTIF_FIRST + NOTIF_INFO_COUNT); \
33 ++NOTIF_INFO_COUNT; } \
34 CHECK_MAX_NOTIFICATIONS(NOTIF_INFO_COUNT) } \
35 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
37 #define MSG_NOTIFY_NOTIF(name,args,icon,normal,gentle) \
39 void DecNotif_##name() { \
41 name = (NOTIF_FIRST + NOTIF_NOTIFY_COUNT); \
42 ++NOTIF_NOTIFY_COUNT; } \
43 CHECK_MAX_NOTIFICATIONS(NOTIF_NOTIFY_COUNT) } \
44 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
46 #define MSG_CENTER_NOTIF(name,args,cpid,normal,gentle) \
49 void DecNotif_##name() { \
51 name = (NOTIF_FIRST + NOTIF_CENTER_COUNT); \
52 ++NOTIF_CENTER_COUNT; } \
54 cpid = (NOTIF_FIRST + NOTIF_CPID_COUNT); \
55 ++NOTIF_CPID_COUNT; } \
56 CHECK_MAX_NOTIFICATIONS(NOTIF_CENTER_COUNT) } \
57 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
59 #define MSG_WEAPON_NOTIF(name,args,normal,gentle) \
61 void DecNotif_##name() { \
63 name = (NOTIF_FIRST + NOTIF_WEAPON_COUNT); \
64 ++NOTIF_WEAPON_COUNT; } \
65 CHECK_MAX_NOTIFICATIONS(NOTIF_WEAPON_COUNT) } \
66 ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
69 // ====================================
70 // Notifications List and Information
71 // ====================================
73 List of all notifications (including identifiers and display information)
74 Format: name, number, args, icon/CPID, normal, gentle
77 ID number of notification
78 Arguments for sprintf(string, args), if no args needed then use ""
80 MSG_NOTIFY: STRING: icon string name for the hud notify panel, "" if no icon is used
81 MSG_CENTER: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
82 Normal message (string for sprintf when gentle messages are NOT enabled)
83 Gentle message (string for sprintf when gentle messages ARE enabled)
85 Messages have ^F1, ^F2, and ^BG in them-- these are replaced
86 with colors according to the cvars the user has chosen.
87 ^F1 = highest priority, "primary"
88 ^F2 = next highest priority, "secondary"
89 ^BG = normal/less important priority, "tertiary"
92 ALWAYS start the string with a color, preferably background
93 ALWAYS end messages with a new line
94 ARIRE unir frk jvgu lbhe bja zbgure (gvc sbe zvxrrhfn)
96 #define MSG_INFO_NOTIFICATIONS \
97 MSG_INFO_NOTIF(DEATH_MARBLES_LOST, CLPS3(s1, s2, s3), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
100 #define MSG_NOTIFY_NOTIFICATIONS \
101 MSG_NOTIFY_NOTIF(DEATH_MARBLES_LOST2, CLPS3(s1, s2, s3), "notify_death", _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
102 #undef MSG_NOTIFY_NOTIF
104 #define MSG_CENTER_NOTIFICATIONS \
105 MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_SHIELDED, "", CPID_CTF_CAPTURESHIELD, _("^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."), "") \
106 MSG_CENTER_NOTIF(CENTER_CTF_CAPTURESHIELD_FREE, "", CPID_CTF_CAPTURESHIELD, _("^BGYou are now free.\n^BGFeel free to ^F2try to capture^BG the flag again\n^BGif you think you will succeed."), "") \
107 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS, CLPS2(s1, s2, s3), CPID_CTF_PASS, _("^BG%s passed the ^F1%s^BG to %s"), "") \
108 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_SENT, CLPS2(s1, s2), CPID_CTF_PASS, _("^BGYou passed the ^F1%s^BG to %s"), "") \
109 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_RECEIVED, CLPS2(s1, s2), CPID_CTF_PASS, _("^BGYou received the ^F1%s^BG from %s"), "") \
110 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_RETURN, s1, CPID_CTF_LOWPRIO, _("^BGYou returned the ^F1%s"), "") \
111 MSG_CENTER_NOTIF(CENTER_CTF_EVENT_CAPTURE, s1, NO_CPID, _("^BGYou captured the ^F1%s"), "") \
112 #undef MSG_CENTER_NOTIF
114 #define MSG_WEAPON_NOTIFICATIONS \
115 MSG_WEAPON_NOTIF(DEATH_MARBLES_LOST3, CLPS3(s1, s2, s3), _("^F1%s^BG lost their marbles against ^F1%s^BG using the ^F2%s^BG\n"), "") \
116 #undef MSG_WEAPON_NOTIF
118 // NOW we actually activate the declarations
119 MSG_INFO_NOTIFICATIONS
120 MSG_NOTIFY_NOTIFICATIONS
121 MSG_CENTER_NOTIFICATIONS
122 MSG_WEAPON_NOTIFICATIONS
125 // ======================
126 // Supporting Functions
127 // ======================
130 #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
131 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
132 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
135 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
137 string normal_or_gentle(string normal, string gentle)
140 if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
142 if(autocvar_sv_gentle)
144 return ((gentle != "") ? gentle : normal);
149 string CCR(string input) // color code replace, place inside of sprintf and parse the string
151 input = strreplace("^F1", "^3", input);
152 input = strreplace("^F2", "^2", input);
153 input = strreplace("^BG", "^7", input);
155 input = strreplace("^N", "^7", input); // "none"-- reset to white
161 // ===============================
162 // Frontend Notification Pushing
163 // ===============================
166 // =========================
167 // Notification Networking
168 // =========================
171 void Read_Notification()
173 float net_type = ReadByte();
174 float net_name = ReadCoord(); // byte only has 256 selections, we need more than that
175 string s1 = ReadString();
176 string s2 = ReadString();
177 string s3 = ReadString();
183 #define MSG_INFO_NOTIF(name,args,normal,gentle) \
184 { if(min(NOTIF_MAX, name) == net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
186 MSG_INFO_NOTIFICATIONS
197 #define MSG_CENTER_NOTIF(name,args,cpid,normal,gentle) \
198 { if(min(NOTIF_MAX, name) == net_name) { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), 0, 0); } }
200 MSG_CENTER_NOTIFICATIONS
212 void Send_Notification(float net_type, entity client, float net_name, string s1, string s2, string s3)
214 if(net_type && net_name)
216 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
219 WRITESPECTATABLE_MSG_ONE({
220 WriteByte(MSG_ONE, SVC_TEMPENTITY);
221 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
222 WriteByte(MSG_ONE, net_type);
223 WriteCoord(MSG_ONE, net_name);
224 WriteString(MSG_ONE, s1);
225 WriteString(MSG_ONE, s2);
226 WriteString(MSG_ONE, s3);
230 if(!server_is_local && ((net_type == MSG_INFO || net_type == MSG_NOTIFY) || client == world))
236 #define MSG_INFO_NOTIF(name,args,normal,gentle) \
237 { if(min(NOTIF_MAX, name) == net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
239 MSG_INFO_NOTIFICATIONS
250 else { backtrace("Incorrect usage of Send_Notification!\n"); }
253 // LEGACY NOTIFICATION SYSTEMS
254 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
256 if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
259 WRITESPECTATABLE_MSG_ONE({
260 WriteByte(MSG_ONE, SVC_TEMPENTITY);
261 WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
262 WriteByte(MSG_ONE, id);
263 WriteString(MSG_ONE, s);
264 if (id != 0 && s != "")
266 WriteByte(MSG_ONE, duration);
267 WriteByte(MSG_ONE, countdown_num);
272 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
274 Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);