]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/notifications.qc
IT'S ALIVEEEEE... for 3 messages. :D
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / notifications.qc
1 // ================================================
2 //  Unified notification system, written by Samual
3 //  Last updated: September, 2012
4 // ================================================
5
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)
11
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
16
17 // accumulate functions for declarations
18 #define NOTIF_FIRST 1
19 #define NOTIF_MAX 1024
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;
25
26 #define MSG_INFO_NOTIF(name,args,normal,gentle) \
27         float name; \
28         void DecNotif_##name() { \
29                 if(!name) { \
30                         name = (NOTIF_FIRST + NOTIF_INFO_COUNT); \
31                         ++NOTIF_INFO_COUNT; } } \
32         ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
33
34 #define MSG_NOTIFY_NOTIF(name,args,icon,normal,gentle) \
35         float name; \
36         void DecNotif_##name() { \
37                 if(!name) { \
38                         name = (NOTIF_FIRST + NOTIF_NOTIFY_COUNT); \
39                         ++NOTIF_NOTIFY_COUNT; } } \
40         ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
41
42 #define MSG_CENTER_NOTIF(name,args,cpid,normal,gentle) \
43         float name; \
44         float cpid; \
45         void DecNotif_##name() { \
46                 if(!name) { \
47                         name = (NOTIF_FIRST + NOTIF_CENTER_COUNT); \
48                         ++NOTIF_CENTER_COUNT; } \
49                 if(!cpid) { \
50                         cpid = (NOTIF_FIRST + NOTIF_CPID_COUNT); \
51                         ++NOTIF_CPID_COUNT; } } \
52         ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
53
54 #define MSG_WEAPON_NOTIF(name,args,normal,gentle) \
55         float name; \
56         void DecNotif_##name() { \
57                 if(!name) { \
58                         name = (NOTIF_FIRST + NOTIF_WEAPON_COUNT); \
59                         ++NOTIF_WEAPON_COUNT; } } \
60         ACCUMULATE_FUNCTION(DecNotifs, DecNotif_##name)
61
62
63 // ====================================
64 //  Notifications List and Information
65 // ====================================
66 /*
67  List of all notifications (including identifiers and display information)
68  Format: name, number, args, icon/CPID, normal, gentle
69  Specifications:
70     Name of notification
71     ID number of notification
72     Arguments for sprintf(string, args), if no args needed then use ""
73     Icon/CPID:
74       MSG_NOTIFY: STRING: icon string name for the hud notify panel, "" if no icon is used
75       MSG_CENTER: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
76     Normal message (string for sprintf when gentle messages are NOT enabled)
77     Gentle message (string for sprintf when gentle messages ARE enabled)
78
79  Messages have ^F1, ^F2, and ^BG in them-- these are replaced
80  with colors according to the cvars the user has chosen.
81     ^F1 = highest priority, "primary"
82     ^F2 = next highest priority, "secondary"
83     ^BG = normal/less important priority, "tertiary"
84
85  Guidlines:
86     ALWAYS start the string with a color, preferably background
87     ALWAYS end messages with a new line
88     ARIRE unir frk jvgu lbhe bja zbgure (gvc sbe zvxrrhfn)
89 */
90 #define MSG_INFO_NOTIFICATIONS \
91         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"), "") \
92         #undef MSG_INFO_NOTIF
93
94 #define MSG_NOTIFY_NOTIFICATIONS \
95         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"), "") \
96         #undef MSG_NOTIFY_NOTIF
97
98 #define MSG_CENTER_NOTIFICATIONS \
99         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."), "") \
100         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."), "") \
101         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS, CLPS2(s1, s2, s3), CPID_CTF_PASS, _("^BG%s passed the ^F1%s^BG to %s"), "") \
102         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_SENT, CLPS2(s1, s2), CPID_CTF_PASS, _("^BGYou passed the ^F1%s^BG to %s"), "") \
103         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_PASS_RECEIVED, CLPS2(s1, s2), CPID_CTF_PASS, _("^BGYou received the ^F1%s^BG from %s"), "") \
104         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_RETURN, s1, CPID_CTF_LOWPRIO, _("^BGYou returned the ^F1%s"), "") \
105         MSG_CENTER_NOTIF(CENTER_CTF_EVENT_CAPTURE, s1, NO_CPID, _("^BGYou captured the ^F1%s"), "") \
106         #undef MSG_CENTER_NOTIF
107
108 #define MSG_WEAPON_NOTIFICATIONS \
109         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"), "") \
110         #undef MSG_WEAPON_NOTIF
111
112 // NOW we actually activate the declarations
113 MSG_INFO_NOTIFICATIONS
114 MSG_NOTIFY_NOTIFICATIONS
115 MSG_CENTER_NOTIFICATIONS
116 MSG_WEAPON_NOTIFICATIONS
117
118
119 // ======================
120 //  Supporting Functions
121 // ======================
122
123 #ifdef SVQC
124 #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
125 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
126 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
127 #endif
128
129 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
130
131 string normal_or_gentle(string normal, string gentle)
132 {
133 #ifdef CSQC
134         if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
135 #else
136         if(autocvar_sv_gentle)
137 #endif
138                 return ((gentle != "") ? gentle : normal);
139         else
140                 return normal;
141 }
142
143 string CCR(string input) // color code replace, place inside of sprintf and parse the string
144 {
145         input = strreplace("^F1", "^3", input);
146         input = strreplace("^F2", "^2", input);
147         input = strreplace("^BG", "^7", input);
148
149         input = strreplace("^N", "^7", input); // "none"-- reset to white
150
151         return input;
152 }
153
154
155 // ===============================
156 //  Frontend Notification Pushing
157 // ===============================
158
159
160 // =========================
161 //  Notification Networking
162 // =========================
163
164 #ifdef CSQC
165 void Read_Notification()
166 {
167         float net_type = ReadByte();
168         float net_name = ReadCoord(); // byte only has 256 selections, we need more than that
169         string s1 = ReadString();
170         string s2 = ReadString();
171         string s3 = ReadString();
172
173         switch(net_type)
174         {
175                 case MSG_INFO:
176                 {
177                         #define MSG_INFO_NOTIF(name,args,normal,gentle) \
178                                 { if(min(NOTIF_MAX, name) == net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
179
180                         MSG_INFO_NOTIFICATIONS
181                         break;
182                 }
183
184                 case MSG_NOTIFY:
185                 {
186                         break;
187                 }
188
189                 case MSG_CENTER:
190                 {
191                         #define MSG_CENTER_NOTIF(name,args,cpid,normal,gentle) \
192                                 { if(min(NOTIF_MAX, name) == net_name) { centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), 0, 0); } }
193
194                         MSG_CENTER_NOTIFICATIONS
195                         break;
196                 }
197
198                 case MSG_WEAPON:
199                 {
200                         break;
201                 }
202         }
203 }
204 #endif
205 #ifdef SVQC
206 void Send_Notification(float net_type, entity client, float net_name, string s1, string s2, string s3)
207 {
208         if(net_type && net_name)
209         {
210                 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
211                 {
212                         msg_entity = client;
213                         WRITESPECTATABLE_MSG_ONE({
214                                 WriteByte(MSG_ONE, SVC_TEMPENTITY);
215                                 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
216                                 WriteByte(MSG_ONE, net_type);
217                                 WriteCoord(MSG_ONE, net_name);
218                                 WriteString(MSG_ONE, s1);
219                                 WriteString(MSG_ONE, s2);
220                                 WriteString(MSG_ONE, s3);
221                         });
222                 }
223
224                 if(!server_is_local && ((net_type == MSG_INFO || net_type == MSG_NOTIFY) || client == world))
225                 {
226                         switch(net_type)
227                         {
228                                 case MSG_INFO:
229                                 {
230                                         #define MSG_INFO_NOTIF(name,args,normal,gentle) \
231                                                 { if(min(NOTIF_MAX, name) == net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
232
233                                         MSG_INFO_NOTIFICATIONS
234                                         break;
235                                 }
236
237                                 case MSG_NOTIFY:
238                                 {
239                                         break;
240                                 }
241                         }
242                 }
243         }
244         else { backtrace("Incorrect usage of Send_Notification!\n"); }
245 }
246
247 // LEGACY NOTIFICATION SYSTEMS
248 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
249 {
250         if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
251         {
252                 msg_entity = e;
253                 WRITESPECTATABLE_MSG_ONE({
254                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
255                         WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
256                         WriteByte(MSG_ONE, id);
257                         WriteString(MSG_ONE, s);
258                         if (id != 0 && s != "")
259                         {
260                                 WriteByte(MSG_ONE, duration);
261                                 WriteByte(MSG_ONE, countdown_num);
262                         }
263                 });
264         }
265 }
266 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
267 {
268         Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
269 }
270 #endif