1 // ================================================
2 // Unified notification system, written by Samual
3 // Last updated: November, 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 is 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)
29 Acquire special information to generate for display in the
30 notification from variables networked to the client.
32 PASS_KEY: find the keybind for "passing" or "dropping" in CTF game mode
33 FRAG_SPREE: find out if the player is on a kill spree/how many kills they have
34 FRAG_PING: show the ping of a player
35 FRAG_STATS: show health/armor/ping of a player
36 FRAG_POS: show score status and position in the match of a player
37 DEATH_TEAM: show the full name of the team a player is switching from
39 string got_commandkey;
40 #define PASS_KEY ((((got_commandkey = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(got_commandkey, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), got_commandkey) : "")
41 #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) : "")
42 #define FRAG_PING ((f2 != BOT_PING) ? sprintf(CCR(_("\n(Ping ^2%d^BG)")), f2) : "")
43 #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) : ""))
44 //#define FRAG_POS ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : "")
45 #define DEATH_TEAM Team_ColoredFullName(TEAM_SV_TO_CL(f1))
46 #define WEAPON_NAME f1
48 // NO_CPID normally has a variable value, so we need to check and see
49 // whether a notification uses it. If so, cancel out the centerprint ID.
50 #define HANDLE_CPID(cpid) ((min(NOTIF_MAX, cpid) == NO_CPID) ? FALSE : cpid)
52 // client-side handling of cvars
53 #define ADD_CSQC_AUTOCVAR(name) var float autocvar_notification_##name = TRUE;
54 #define CHECK_AUTOCVAR(name) if(autocvar_notification_##name)
57 // allow sending of notifications to also pass through to spectators (specifically for centerprints)
59 #define DEATH_TEAM Team_ColoredFullName(f1)
60 #define WEAPON_NAME f1
62 #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
63 #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
64 #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
67 // do nothing for the other programs, they don't need cvars (those are just for the clients)
68 #define ADD_CSQC_AUTOCVAR(name)
73 If BELOW negative maxplayers, you dropped a place lower
74 If below 0, you are tied for that place
75 If above 0, you are holding that place alone
76 If above positive maxplayers, you moved up a place
78 float Should_Print_Score_Pos
80 string Read_Score_Pos(float num)
85 float Form_Score_Pos(entity player)
90 // ====================================
91 // Notifications List and Information
92 // ====================================
93 /*(name,strnum,flnum,args,cpid,cennor,cengen,infargs,hudargs,icon,infnor,infgen)
94 List of all notifications (including identifiers and display information)
95 Possible Tokens: name, infoname, centername, strnum, flnum, args, hudargs, icon, cpid, durcnt, normal, gentle
96 Format Specifications:
98 name: VAR: Name of notification
99 strnum: FLOAT: Number of STRING arguments (so that networking knows how many to send/receive)
100 flnum: FLOAT: Number of FLOAT arguments (so that networking knows how many to send/receive)
101 args: MISC: Arguments for sprintf(string, args), if no args needed then use ""
102 hudargs: XPND2(STRING, STRING): arguments for names in notify messages
103 icon: STRING: icon string name for the hud notify panel, "" if no icon is used
104 normal: STRING: Normal message (string for sprintf when gentle messages are NOT enabled)
105 gentle: STRING: Gentle message (string for sprintf when gentle messages ARE enabled)
107 name: VAR: Name of notification
108 strnum: FLOAT: Number of STRING arguments (so that networking knows how many to send/receive)
109 flnum: FLOAT: Number of FLOAT arguments (so that networking knows how many to send/receive)
110 args: MISC: Arguments for sprintf(string, args), if no args needed then use ""
111 cpid: FLOAT: centerprint ID number (CPID_*), NO_CPID if no CPID is needed
112 durcnt: XPND2(FLOAT, FLOAT): Duration/Countdown: extra arguments for centerprint messages
113 normal: STRING: Normal message (string for sprintf when gentle messages are NOT enabled)
114 gentle: STRING: Gentle message (string for sprintf when gentle messages ARE enabled)
117 name: VAR: Name of chaining notification
118 infoname: VAR: Name of info notification for reference
119 centername: VAR: Name of centerprint notification for reference
121 Messages with ^F1, ^BG, ^TC, etc etc in them will replace those strings
122 with colors according to the cvars the user has chosen. This allows for
123 users to create unique color profiles for their HUD, giving more customization
124 options to HUD designers and end users who want such a feature.
126 Check out the function calls for string CCR(...) and
127 string TCR(...) to better understand how these codes work.
129 Guidlines (please try and follow these):
130 -ALWAYS start the string with a color, preferably background.
131 -ALWAYS reset a color after a name (this way they don't set it for the whole string).
132 -NEVER re-declare an event twice.
133 -NEVER add or remove fields from the format, it SHOULD already work.
134 -MSG_INFO messages must ALWAYS end with a new line: \n
135 -Be clean and simple with your notification naming,
136 nothing too long for the name field... Abbreviations are your friend. :D
137 -Keep the spacing as clean as possible... if the arguments are abnormally long,
138 it's okay to go out of line a bit... but try and keep it clean still.
139 -Sort the notifications in the most appropriate order for their tasks.
140 TODO: ? centerprint IDs are given priority based on their order (first being highest priority going downwards)
141 -ARIRE unir frk jvgu lbhe bja zbgure. (gvc sbe zvxrrhfn) -- Don't pay attention to this ^_^
144 // weaponorder[f1].netname
146 #define MULTITEAM_INFO(prefix,teams,strnum,flnum,args,hudargs,icon,normal,gentle) \
147 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))) \
148 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))) \
150 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))) \
153 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))) \
155 #define MSG_INFO_NOTIFICATIONS \
156 MSG_INFO_NOTIF(INFO_EMPTY, 0, 0, NO_STR_ARG, XPND2("", ""), "", "", "") \
157 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"), "") \
158 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"), "") \
159 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"), "") \
160 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"), "") \
161 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"), "") \
162 MULTITEAM_INFO(INFO_CTF_FLAGRETURN_TIMEOUT_, 2, 0, 0, NO_STR_ARG, XPND2("", ""), "", _("^BGThe ^TC^TT^BG flag has returned to the base\n"), "") \
163 MULTITEAM_INFO(INFO_CTF_PICKUP_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_taken", _("^BG%s^BG got the ^TC^TT^BG flag\n"), "") \
164 MULTITEAM_INFO(INFO_CTF_RETURN_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag\n"), "") \
165 MULTITEAM_INFO(INFO_CTF_LOST_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_lost", _("^BG%s^BG lost the ^TC^TT^BG flag\n"), "") \
166 MULTITEAM_INFO(INFO_CTF_CAPTURE_, 2, 1, 0, s1, XPND2(s1, ""), "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag\n"), "") \
167 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"), "") \
168 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"), "") \
169 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"), "") \
170 MSG_INFO_NOTIF(INFO_DEATH_SELF_CUSTOM, 2, 0, XPND2(s1, s2), XPND2(s1, ""), "notify_void", _("^F1%s^K1 %s\n"), "") \
171 MSG_INFO_NOTIF(INFO_DEATH_SELF_GENERIC, 1, 0, s1, XPND2(s1, ""), "notify_void", _("^F1%s^K1 was in the wrong place\n"), "") \
172 MSG_INFO_NOTIF(INFO_DEATH_SELF_SELFKILL, 1, 0, s1, XPND2(s1, ""), "notify_selfkill", _("^F1%s^K1 died\n"), "") \
173 MSG_INFO_NOTIF(INFO_DEATH_SELF_SUICIDE, 1, 0, s1, XPND2(s1, ""), "notify_selfkill", _("^F1%s^K1 couldn't take it anymore\n"), "") \
174 MSG_INFO_NOTIF(INFO_DEATH_SELF_NOAMMO, 1, 0, s1, XPND2(s1, ""), "notify_outofammo", _("^F1%s^K1 died. What's the point of living without ammo?\n"), _("^F1%s^K1 ran out of ammo\n")) \
175 MSG_INFO_NOTIF(INFO_DEATH_SELF_ROT, 1, 0, s1, XPND2(s1, ""), "notify_death", _("^F1%s^K1 rotted away\n"), "") \
176 MSG_INFO_NOTIF(INFO_DEATH_SELF_CAMP, 1, 0, s1, XPND2(s1, ""), "notify_camping", _("^F1%s^K1 thought they found a nice camping ground\n"), "") \
177 MSG_INFO_NOTIF(INFO_DEATH_SELF_BETRAYAL, 1, 1, s1, XPND2(s1, ""), "notify_teamkill_red", _("^F1%s^K1 became enemies with the Lord of Teamplay\n"), "") \
178 MSG_INFO_NOTIF(INFO_DEATH_SELF_TEAMCHANGE, 1, 1, XPND2(s1, DEATH_TEAM), XPND2("", ""), "", _("^F1%s^K1 switched to the %s\n"), "") \
179 MSG_INFO_NOTIF(INFO_DEATH_SELF_AUTOTEAMCHANGE, 1, 1, XPND2(s1, DEATH_TEAM), XPND2("", ""), "", _("^F1%s^K1 was moved into the %s\n"), "") \
180 MSG_INFO_NOTIF(INFO_DEATH_SELF_FALL, 1, 0, s1, XPND2(s1, ""), "notify_fall", _("^F1%s^K1 hit the ground with a crunch\n"), _("^F1%s^K1 hit the ground with a bit too much force\n")) \
181 MSG_INFO_NOTIF(INFO_DEATH_SELF_DROWN, 1, 0, s1, XPND2(s1, ""), "notify_water", _("^F1%s^K1 couldn't catch their breath\n"), _("^F1%s^K1 was in the water for too long\n")) \
182 MSG_INFO_NOTIF(INFO_DEATH_SELF_FIRE, 1, 0, s1, XPND2(s1, ""), "notify_death", _("^F1%s^K1 became a bit too crispy\n"), _("^F1%s^K1 felt a little hot\n")) \
183 MSG_INFO_NOTIF(INFO_DEATH_SELF_LAVA, 1, 0, s1, XPND2(s1, ""), "notify_lava", _("^F1%s^K1 turned into hot slag\n"), _("^F1%s^K1 found a hot place\n")) \
184 MSG_INFO_NOTIF(INFO_DEATH_SELF_SLIME, 1, 0, s1, XPND2(s1, ""), "notify_slime", _("^F1%s^K1 was slimed\n"), "") \
185 MSG_INFO_NOTIF(INFO_DEATH_SELF_SHOOTING_STAR, 1, 0, s1, XPND2(s1, ""), "notify_shootingstar", _("^F1%s^K1 became a shooting star\n"), "") \
186 MSG_INFO_NOTIF(INFO_DEATH_SELF_SWAMP, 1, 0, s1, XPND2(s1, ""), "notify_slime", _("^F1%s^K1 is now conserved for centuries to come\n"), _("^F1%s^K1 discovered a swamp\n")) \
187 MULTITEAM_INFO(INFO_SCORES_, 4, 0, 0, NO_STR_ARG, XPND2("", ""), "", _("^TC^TT ^BGteam scores!\n"), "") \
188 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"), "")
190 #define MULTITEAM_CENTER(prefix,teams,strnum,flnum,args,cpid,durcnt,normal,gentle) \
191 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))) \
192 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))) \
194 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))) \
197 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))) \
199 #define MSG_CENTER_NOTIFICATIONS \
200 MSG_CENTER_NOTIF(CENTER_EMPTY, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), "", "") \
201 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."), "") \
202 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."), "") \
203 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"), "") \
204 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"), "") \
205 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"), "") \
206 MSG_CENTER_NOTIF(CENTER_CTF_PASS_REQUESTING, 1, 0, s1, CPID_CTF_PASS, XPND2(0, 0), _("^BGRequesting %s^BG to pass you the flag"), "") \
207 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"), "") \
208 MULTITEAM_CENTER(CENTER_CTF_RETURN_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou returned the ^TC^TT^BG flag!"), "") \
209 MULTITEAM_CENTER(CENTER_CTF_CAPTURE_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou captured the ^TC^TT^BG flag!"), "") \
210 MULTITEAM_CENTER(CENTER_CTF_PICKUP_, 2, 0, 0, NO_STR_ARG, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGYou got the ^TC^TT^BG flag!"), "") \
211 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!"), "") \
212 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!"), "") \
213 MSG_CENTER_NOTIF(CENTER_CTF_PICKUP_ENEMY, 1, 0, s1, CPID_CTF_LOWPRIO, XPND2(0, 0), _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
214 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!"), "") \
215 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!"), "") \
216 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!"), "") \
217 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."), "") \
218 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CUSTOM, 2, 0, s2, NO_CPID, XPND2(0, 0), _("^K1You were %s"), "") \
219 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_GENERIC, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1Watch your step!"), "") \
220 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SELFKILL, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You killed your own dumb self!"), _("^K1You need to be more careful!")) \
221 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SUICIDE, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You committed suicide!"), _("^K1You ended it all!")) \
222 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...")) \
223 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")) \
224 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_CAMP, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1Die camper!"), _("^K1Reconsider your tactics, camper!")) \
225 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!")) \
226 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_TEAMCHANGE, 0, 1, DEATH_TEAM, NO_CPID, XPND2(0, 0), _("^BGYou are now on: %s"), "") \
227 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"), "") \
228 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_FALL, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You hit the ground with a crunch!"), "") \
229 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!"), "") \
230 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!")) \
231 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_LAVA, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You couldn't stand the heat!"), "") \
232 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SLIME, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You melted away in slime!"), "") \
233 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SHOOTING_STAR, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You became a shooting star!"), "") \
234 MSG_CENTER_NOTIF(CENTER_DEATH_SELF_SWAMP, 0, 0, NO_STR_ARG, NO_CPID, XPND2(0, 0), _("^K1You got stuck in a swamp!"), "") \
235 MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_FRAG, 1, 1, XPND2(FRAG_SPREE, s1), NO_CPID, XPND2(0, 0), _("^K3%sYou fragged ^BG%s"), _("^K3%sYou scored against ^BG%s")) \
236 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")) \
237 MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_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")) \
238 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!")) \
239 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")) \
240 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")) \
241 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")) \
242 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!")) \
243 MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_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")) \
244 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")) \
245 MSG_CENTER_NOTIF(CENTER_DEATH_MURDER_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")) \
246 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")) \
247 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")) \
248 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")) \
249 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")) \
250 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!")) \
251 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!"), "")
253 #define MSG_WEAPON_NOTIFICATIONS \
254 MSG_WEAPON_NOTIF(WEAPON_EMPTY, NO_MSG, NO_MSG) \
255 MSG_WEAPON_NOTIF(WEAPON_MARBLES_LOST, INFO_WEAPON_MARBLES_LOST, CENTER_WEAPON_MARBLES_LOST)
257 #define MSG_DEATH_NOTIFICATIONS \
258 MSG_DEATH_NOTIF(DEATH_EMPTY, NO_MSG, NO_MSG) \
259 MSG_DEATH_NOTIF(DEATH_SELF_CUSTOM, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_CUSTOM) \
260 MSG_DEATH_NOTIF(DEATH_SELF_GENERIC, INFO_DEATH_SELF_GENERIC, CENTER_DEATH_SELF_GENERIC) \
261 MSG_DEATH_NOTIF(DEATH_SELF_SELFKILL, INFO_DEATH_SELF_SELFKILL, CENTER_DEATH_SELF_SELFKILL) \
262 MSG_DEATH_NOTIF(DEATH_SELF_SUICIDE, INFO_DEATH_SELF_SUICIDE, CENTER_DEATH_SELF_SUICIDE) \
263 MSG_DEATH_NOTIF(DEATH_SELF_NOAMMO, INFO_DEATH_SELF_NOAMMO, CENTER_DEATH_SELF_NOAMMO) \
264 MSG_DEATH_NOTIF(DEATH_SELF_ROT, INFO_DEATH_SELF_ROT, CENTER_DEATH_SELF_ROT) \
265 MSG_DEATH_NOTIF(DEATH_SELF_CAMP, INFO_DEATH_SELF_CAMP, CENTER_DEATH_SELF_CAMP) \
266 MSG_DEATH_NOTIF(DEATH_SELF_BETRAYAL, INFO_DEATH_SELF_BETRAYAL, CENTER_DEATH_SELF_BETRAYAL) \
267 MSG_DEATH_NOTIF(DEATH_SELF_TEAMCHANGE, INFO_DEATH_SELF_TEAMCHANGE, CENTER_DEATH_SELF_TEAMCHANGE) \
268 MSG_DEATH_NOTIF(DEATH_SELF_AUTOTEAMCHANGE, INFO_DEATH_SELF_AUTOTEAMCHANGE, CENTER_DEATH_SELF_AUTOTEAMCHANGE) \
269 MSG_DEATH_NOTIF(DEATH_SELF_FALL, INFO_DEATH_SELF_FALL, CENTER_DEATH_SELF_FALL) \
270 MSG_DEATH_NOTIF(DEATH_SELF_DROWN, INFO_DEATH_SELF_DROWN, CENTER_DEATH_SELF_DROWN) \
271 MSG_DEATH_NOTIF(DEATH_SELF_FIRE, INFO_DEATH_SELF_FIRE, CENTER_DEATH_SELF_FIRE) \
272 MSG_DEATH_NOTIF(DEATH_SELF_LAVA, INFO_DEATH_SELF_LAVA, CENTER_DEATH_SELF_LAVA) \
273 MSG_DEATH_NOTIF(DEATH_SELF_SLIME, INFO_DEATH_SELF_SLIME, CENTER_DEATH_SELF_SLIME) \
274 MSG_DEATH_NOTIF(DEATH_SELF_SHOOTING_STAR, INFO_DEATH_SELF_SHOOTING_STAR, CENTER_DEATH_SELF_SHOOTING_STAR) \
275 MSG_DEATH_NOTIF(DEATH_SELF_SWAMP, INFO_DEATH_SELF_SWAMP, CENTER_DEATH_SELF_SWAMP) \
276 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG, NO_MSG, CENTER_DEATH_MURDER_FRAG) \
277 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED, NO_MSG, CENTER_DEATH_MURDER_FRAGGED) \
278 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAG) \
279 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED) \
280 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_FIRST, NO_MSG, CENTER_DEATH_MURDER_FRAG_FIRST) \
281 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_FIRST, NO_MSG, CENTER_DEATH_MURDER_FRAGGED_FIRST) \
282 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_FIRST, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAG_FIRST) \
283 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_FIRST, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST) \
284 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_FRAG_VERBOSE) \
285 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_FRAGGED_VERBOSE) \
286 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE) \
287 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE) \
288 MSG_DEATH_NOTIF(DEATH_MURDER_FRAG_FIRST_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE) \
289 MSG_DEATH_NOTIF(DEATH_MURDER_FRAGGED_FIRST_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE) \
290 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE) \
291 MSG_DEATH_NOTIF(DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE, NO_MSG, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE)
294 // ====================================
295 // Initialization/Create Declarations
296 // ====================================
298 #define NOTIF_FIRST 1
299 #define NOTIF_MAX 1024 // limit of recursive functions with ACCUMULATE_FUNCTION
300 float NOTIF_INFO_COUNT;
301 float NOTIF_CENTER_COUNT;
302 float NOTIF_WEAPON_COUNT;
303 float NOTIF_DEATH_COUNT;
304 float NOTIF_CPID_COUNT;
306 #define MSG_INFO_NOTIF(name,strnum,flnum,args,icon,normal,gentle) \
307 ADD_CSQC_AUTOCVAR(name) \
309 void RegisterNotification_##name() \
311 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_INFO_COUNT) \
312 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_INFO_COUNT, "notifications") \
314 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
316 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
317 ADD_CSQC_AUTOCVAR(name) \
320 void RegisterNotification_##name() \
322 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_CENTER_COUNT) \
323 SET_FIELD_COUNT(cpid, NOTIF_FIRST, NOTIF_CPID_COUNT) \
324 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_CENTER_COUNT, "notifications") \
326 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
328 #define MSG_WEAPON_NOTIF(name,infoname,centername) \
329 ADD_CSQC_AUTOCVAR(name) \
331 void RegisterNotification_##name() \
333 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_WEAPON_COUNT) \
334 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_WEAPON_COUNT, "notifications") \
336 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
338 #define MSG_DEATH_NOTIF(name,infoname,centername) \
339 ADD_CSQC_AUTOCVAR(name) \
341 void RegisterNotification_##name() \
343 SET_FIELD_COUNT(name, NOTIF_FIRST, NOTIF_DEATH_COUNT) \
344 CHECK_MAX_COUNT(name, NOTIF_MAX, NOTIF_DEATH_COUNT, "notifications") \
346 ACCUMULATE_FUNCTION(RegisterNotifications, RegisterNotification_##name)
348 // NOW we actually activate the declarations
349 MSG_INFO_NOTIFICATIONS
350 MSG_CENTER_NOTIFICATIONS
351 MSG_WEAPON_NOTIFICATIONS
352 MSG_DEATH_NOTIFICATIONS
353 #undef MSG_INFO_NOTIF
354 #undef MSG_CENTER_NOTIF
355 #undef MSG_WEAPON_NOTIF
356 #undef MSG_DEATH_NOTIF
358 // ======================
359 // Supporting Functions
360 // ======================
362 // select between the normal or the gentle message string based on client (or server) settings
363 string normal_or_gentle(string normal, string gentle)
367 if(autocvar_cl_gentle || autocvar_cl_gentle_messages)
369 if(autocvar_sv_gentle)
371 return ((gentle != "") ? gentle : normal);
379 float notif_stringcount(string s1, string s2)
382 if(s1 != NO_STR_ARG) ++stringcount;
383 if(s2 != NO_STR_ARG) ++stringcount;
387 float notif_floatcount(float f1, float f2, float f3)
390 if(f1 != NO_FL_ARG) ++floatcount;
391 if(f2 != NO_FL_ARG) ++floatcount;
392 if(f3 != NO_FL_ARG) ++floatcount;
396 // get the actual name of a notification and return it as a string
397 string Get_Field_Value(float field, float net_type, float net_name)
401 #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) \
402 if(field == F_NAME) { output = VAR_TO_TEXT(name); } \
403 else if(field == F_STRNUM) { output = ftos(strnum); } \
404 else if(field == F_FLNUM) { output = ftos(flnum); }
410 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
411 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
412 MSG_INFO_NOTIFICATIONS
413 #undef MSG_INFO_NOTIF
418 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
419 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) } }
420 MSG_CENTER_NOTIFICATIONS
421 #undef MSG_CENTER_NOTIF
426 #define MSG_WEAPON_NOTIF(name,infoname,centername) \
427 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name, \
428 max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \
429 max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } }
430 MSG_WEAPON_NOTIFICATIONS
431 #undef MSG_WEAPON_NOTIF
436 #define MSG_DEATH_NOTIF(name,infoname,centername) \
437 { NOTIF_MATCH(name, net_name) { GET_FIELD_VALUE_OUTPUT(field,name, \
438 max(stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername))), \
439 max(stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)))) } }
440 MSG_DEATH_NOTIFICATIONS
441 #undef MSG_DEATH_NOTIF
446 #undef GET_FIELD_VALUE_OUTPUT
451 string TCR(string input, string teamcolor, string teamtext)
454 input = strreplace("^TC", teamcolor, input);
455 input = strreplace("^TT", teamtext, input);
459 // color code replace, place inside of sprintf and parse the string
460 string CCR(string input)
462 // foreground/normal colors
463 input = strreplace("^F1", "^2", input); // primary priority (important names, etc)
464 input = strreplace("^F2", "^3", input); // secondary priority (items, locations, numbers, etc)
467 input = strreplace("^K1", "^1", input); // "bad" or "dangerous" text (death messages against you, kill notifications, etc)
468 input = strreplace("^K2", "^3", input); // similar to above, but less important... OR, a highlight out of above message type
469 input = strreplace("^K3", "^4", input); // "good" or "beneficial" text (you fragging someone, etc)
472 input = strreplace("^BG", "^7", input); // neutral/unimportant text
473 input = strreplace("^N", "^7", input); // "none"-- reset to white...
478 // =============================
479 // Debug/Maintenance Functions
480 // =============================
482 #define NOTIF_Write(type,name,text) fputs(fh, (sprintf("seta %s 1 // %s - %s\n", name, type, strreplace("\n", "\\n", text))))
483 void Dump_Notifications(float fh)
485 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) { NOTIF_Write("MSG_INFO", VAR_TO_TEXT(name), normal); }
486 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) { NOTIF_Write("MSG_CENTER", VAR_TO_TEXT(name), normal); }
487 #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))); }
488 #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))); }
489 MSG_INFO_NOTIFICATIONS
490 MSG_CENTER_NOTIFICATIONS
491 MSG_WEAPON_NOTIFICATIONS
492 MSG_DEATH_NOTIFICATIONS
493 #undef MSG_INFO_NOTIF
494 #undef MSG_CENTER_NOTIF
495 #undef MSG_WEAPON_NOTIF
496 #undef MSG_DEATH_NOTIF
501 // ===============================
502 // Frontend Notification Pushing
503 // ===============================
506 #define KN_MAX_ENTRIES 10
508 float killnotify_times[KN_MAX_ENTRIES];
509 string killnotify_icon[KN_MAX_ENTRIES];
510 string killnotify_attackers[KN_MAX_ENTRIES];
511 string killnotify_victims[KN_MAX_ENTRIES];
512 // 0 = "Y [used by] X", 1 = "X [did action to] Y"
513 void HUD_Notify_Push(string icon, string attacker, string victim)
518 if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
519 killnotify_times[kn_index] = time;
522 if(killnotify_icon[kn_index]) { strunzone(killnotify_icon[kn_index]); }
523 killnotify_icon[kn_index] = strzone(icon);
526 if(killnotify_attackers[kn_index]) { strunzone(killnotify_attackers[kn_index]); }
527 killnotify_attackers[kn_index] = strzone(attacker);
530 if(killnotify_victims[kn_index]) { strunzone(killnotify_victims[kn_index]); }
531 killnotify_victims[kn_index] = strzone(victim);
535 void Local_Notification(float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
537 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")));
542 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
543 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
545 print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); \
546 if(strtolower(icon) != "") { HUD_Notify_Push(icon, hudargs); } \
548 MSG_INFO_NOTIFICATIONS
549 #undef MSG_INFO_NOTIF
554 #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
555 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
557 centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); \
559 MSG_CENTER_NOTIFICATIONS
560 #undef MSG_CENTER_NOTIF
565 #define MSG_WEAPON_NOTIF(name,infoname,centername) \
566 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
568 #if infoname != NO_MSG \
569 Local_Notification(MSG_INFO, infoname, s1, s2, f1, f2, f3); \
571 #if centername != NO_MSG \
572 Local_Notification(MSG_CENTER, centername, s1, s2, f1, f2, f3); \
575 MSG_WEAPON_NOTIFICATIONS
576 #undef MSG_WEAPON_NOTIF
581 #define MSG_DEATH_NOTIF(name,infoname,centername) \
582 { NOTIF_MATCH(name, net_name) CHECK_AUTOCVAR(name) \
584 #if infoname != NO_MSG \
585 Local_Notification(MSG_INFO, infoname, s1, s2, f1, f2, f3); \
587 #if centername != NO_MSG \
588 Local_Notification(MSG_CENTER, centername, s1, s2, f1, f2, f3); \
591 MSG_DEATH_NOTIFICATIONS
592 #undef MSG_DEATH_NOTIF
600 // =========================
601 // Notification Networking
602 // =========================
605 void Read_Notification(void)
607 float net_type = ReadByte();
608 float net_name = ReadShort();
610 float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
611 float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
613 //print("stringcount = ", ftos(stringcount), ", floatcount = ", ftos(floatcount), ".\n");
615 Local_Notification(net_type, net_name,
616 ((stringcount >= 1) ? ReadString() : ""),
617 ((stringcount == 2) ? ReadString() : ""),
618 ((floatcount >= 1) ? ReadLong() : 0),
619 ((floatcount >= 2) ? ReadLong() : 0),
620 ((floatcount == 3) ? ReadLong() : 0));
625 void Send_Notification(entity client, float broadcast, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
627 if(net_type && net_name)
629 //print("notification: ", Get_Field_Value(F_NAME, net_type, net_name), ": ", ftos(net_name), ".\n");
630 print("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")));
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 if(notif_stringcount(s1, s2) > stringcount) { backtrace("Too many string arguments for notification!\n"); return; }
636 if(notif_floatcount(f1, f2, f3) > floatcount) { backtrace("Too many float arguments for notification!\n"); return; }
638 if(broadcast == MSG_ONE)
640 if(client && (clienttype(client) == CLIENTTYPE_REAL) && (client.flags & FL_CLIENT))
642 // personal/direct notification sent to ONE person and their spectators
644 WRITESPECTATABLE_MSG_ONE({
645 WriteByte(MSG_ONE, SVC_TEMPENTITY);
646 WriteByte(MSG_ONE, TE_CSQC_NOTIFICATION);
647 WriteByte(MSG_ONE, net_type);
648 WriteShort(MSG_ONE, net_name);
649 if(stringcount >= 1) { WriteString(MSG_ONE, s1); }
650 if(stringcount == 2) { WriteString(MSG_ONE, s2); }
651 if(floatcount >= 1) { WriteLong(MSG_ONE, f1); }
652 if(floatcount >= 2) { WriteLong(MSG_ONE, f2); }
653 if(floatcount == 3) { WriteLong(MSG_ONE, f3); }
657 else if(broadcast == MSG_ALL)
659 // global notification sent to EVERYONE
660 WriteByte(MSG_ALL, SVC_TEMPENTITY);
661 WriteByte(MSG_ALL, TE_CSQC_NOTIFICATION);
662 WriteByte(MSG_ALL, net_type);
663 WriteShort(MSG_ALL, net_name);
664 if(stringcount >= 1) { WriteString(MSG_ALL, s1); }
665 if(stringcount == 2) { WriteString(MSG_ALL, s2); }
666 if(floatcount >= 1) { WriteLong(MSG_ALL, f1); }
667 if(floatcount >= 2) { WriteLong(MSG_ALL, f2); }
668 if(floatcount == 3) { WriteLong(MSG_ALL, f3); }
670 else { backtrace("Unknown MSG_ type to write with!\n"); }
672 if(!server_is_local && (net_type == MSG_INFO))
674 #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
675 { NOTIF_MATCH(name, net_name) { print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); } }
676 MSG_INFO_NOTIFICATIONS
677 #undef MSG_INFO_NOTIF
680 else { backtrace("Incorrect usage of Send_Notification!\n"); }
683 void Send_Notification_ToTeam(float targetteam, entity except, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
686 FOR_EACH_REALCLIENT(tmp_entity)
688 if(tmp_entity.classname == STR_PLAYER)
689 if(tmp_entity.team == targetteam)
690 if(tmp_entity != except)
692 Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
697 // WARNING: use this ONLY if you need exceptions or want to exclude spectators, otherwise use Send_Notification(world, MSG_ALL, ...)
698 void Send_Notification_ToAll(entity except, float spectators, float net_type, float net_name, string s1, string s2, float f1, float f2, float f3)
701 FOR_EACH_REALCLIENT(tmp_entity)
703 if((tmp_entity.classname == STR_PLAYER) || spectators)
704 if(tmp_entity != except)
706 Send_Notification(tmp_entity, MSG_ONE, net_type, net_name, s1, s2, f1, f2, f3);
712 // =============================
713 // LEGACY NOTIFICATION SYSTEMS
714 // =============================
716 void Send_KillNotification(string s1, string s2, string s3, float msg, float type)
718 WriteByte(MSG_ALL, SVC_TEMPENTITY);
719 WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY);
720 WriteString(MSG_ALL, s1);
721 WriteString(MSG_ALL, s2);
722 WriteString(MSG_ALL, s3);
723 WriteShort(MSG_ALL, msg);
724 WriteByte(MSG_ALL, type);
727 // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
728 void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
730 if (clienttype(e) == CLIENTTYPE_REAL)
733 WRITESPECTATABLE_MSG_ONE({
734 WriteByte(MSG_ONE, SVC_TEMPENTITY);
735 WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
736 WriteString(MSG_ONE, s1);
737 WriteString(MSG_ONE, s2);
738 WriteShort(MSG_ONE, msg);
739 WriteByte(MSG_ONE, type);
744 void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
746 if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
749 WRITESPECTATABLE_MSG_ONE({
750 WriteByte(MSG_ONE, SVC_TEMPENTITY);
751 WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
752 WriteByte(MSG_ONE, id);
753 WriteString(MSG_ONE, s);
754 if (id != 0 && s != "")
756 WriteByte(MSG_ONE, duration);
757 WriteByte(MSG_ONE, countdown_num);
762 void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
764 Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);