]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/notifications.qc
MASSIVE cleanup, especially of initialization code
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / notifications.qc
index cea5d3de29e008040769e32e976731c3c46d5746..2a190a35519ad24894eecea3dfa0833773c537bb 100644 (file)
@@ -3,71 +3,17 @@
 //  Last updated: February, 2013
 // ================================================
 
 //  Last updated: February, 2013
 // ================================================
 
-#ifndef MENUQC
-string arg_slot[8];
-string Fill_Notif_Args(string args, string input,
-       string s1, string s2, string s3, string s4,
-       float f1, float f2, float f3, float f4)
+string Get_Notif_TypeName(float net_type)
 {
 {
-       dprint(sprintf("Fill_Notif_Args('%s', '%s', %s, %s, %s, %s, %d, %d, %d, %d);\n",
-               args, input, s1, s2, s3, s4, f1, f2, f3, f4));
-
-       string selected, remaining = args;
-       float sel_num = 0;
-
-       #ifdef CSQC
-       string tmp_s;
-       #endif
-       
-       if((remaining != "") && (input != ""))
+       switch(net_type)
        {
        {
-               for(;remaining;)
-               {
-                       selected = car(remaining); remaining = cdr(remaining);
-
-                       switch(strtolower(selected))
-                       {
-                               #define ADD_ARG_CASE(selected,result) case selected: { arg_slot[sel_num] = result; ++sel_num; break; }
-                               
-                               ADD_ARG_CASE("s1", s1)
-                               ADD_ARG_CASE("s2", s2)
-                               ADD_ARG_CASE("s3", s3)
-                               ADD_ARG_CASE("s4", s4)
-                               ADD_ARG_CASE("f1", ftos(f1))
-                               ADD_ARG_CASE("f2", ftos(f2))
-                               ADD_ARG_CASE("f3", ftos(f3))
-                               ADD_ARG_CASE("f4", ftos(f4))
-
-                               #ifdef CSQC // CSQC replacements
-                               ADD_ARG_CASE("pass_key",                ((((tmp_s = getcommandkey("pass", "+use")) != "pass") && !(strstrofs(tmp_s, "not bound", 0) >= 0)) ? sprintf(CCR(_(" ^F1(Press %s)")), tmp_s) : ""))
-                               ADD_ARG_CASE("frag_ping",               ((f2 != BOT_PING) ? sprintf(CCR(_("\n(Ping ^2%d^BG)")), f2) : ""))
-                               ADD_ARG_CASE("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) : "")))
-                               //ADD_ARG_CASE("frag_pos",              ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))
-                               ADD_ARG_CASE("spree_cen",               (((f1 == 3) || (f1 == 5) || (f1 == 10) || (f1 == 15) || (f1 == 20) || (f1 == 25) || (f1 == 30)) ? sprintf(normal_or_gentle(_("%d frag spree! "), _("%d score spree! ")), f1) : ""))
-                               ADD_ARG_CASE("spree_inf",               (((f1 == 3) || (f1 == 5) || (f1 == 10) || (f1 == 15) || (f1 == 20) || (f1 == 25) || (f1 == 30)) ? sprintf(normal_or_gentle(_("%d frag spree! "), _("%d score spree! ")), f1) : ""))
-                               ADD_ARG_CASE("spree_end",               ((f1 >= 3) ? sprintf(normal_or_gentle(_(", ending their %d frag spree"), _(", ending their %d score spree")), f1) : ""))
-                               ADD_ARG_CASE("spree_lost",              ((f1 >= 3) ? sprintf(normal_or_gentle(_(", losing their %d frag spree"), _(", losing their %d score spree")), f1) : ""))
-                               ADD_ARG_CASE("death_team",              Team_ColoredFullName(f1 - 1))
-                               ADD_ARG_CASE("weapon_name",     ftos(f1)) // weaponorder[f1].netname
-
-                               #else // SVQC replacements
-                               ADD_ARG_CASE("spree_inf",               (((f1 == 3) || (f1 == 5) || (f1 == 10) || (f1 == 15) || (f1 == 20) || (f1 == 25) || (f1 == 30)) ? sprintf(normal_or_gentle(_("%d frag spree! "), _("%d score spree! ")), f1) : ""))
-                               ADD_ARG_CASE("spree_end",               ((f1 >= 3) ? sprintf(normal_or_gentle(_(", ending their %d frag spree"), _(", ending their %d score spree")), f1) : ""))
-                               ADD_ARG_CASE("spree_lost",              ((f1 >= 3) ? sprintf(normal_or_gentle(_(", losing their %d frag spree"), _(", losing their %d score spree")), f1) : ""))
-                               ADD_ARG_CASE("death_team",              Team_ColoredFullName(f1))
-                               ADD_ARG_CASE("weapon_name",             ftos(f1)) // weaponorder[f1].netname
-                               #endif
-
-                               #undef ADD_ARG_CASE
-                               default: { print("Hit unknown token in selected string! '", selected, "'\n"); break; }
-                       }
-                       if(sel_num == 7) { print("Hit maximum arguments!\n"); break; }
-               }
-
-               return sprintf(CCR(input), arg_slot[0], arg_slot[1], arg_slot[2], arg_slot[3], arg_slot[4], arg_slot[5], arg_slot[6], arg_slot[7]);
+               case MSG_INFO: return "MSG_INFO";
+               case MSG_CENTER: return "MSG_CENTER";
+               case MSG_WEAPON: return "MSG_WEAPON";
+               case MSG_DEATH: return "MSG_DEATH";
        }
        }
-
-       return "";
+       backtrace(sprintf("Get_Notif_TypeName(%d): Improper net type!\n", net_type));
+       return "your ass";
 }
 
 entity Get_Notif_Ent(float net_type, float net_name)
 }
 
 entity Get_Notif_Ent(float net_type, float net_name)
@@ -79,99 +25,545 @@ entity Get_Notif_Ent(float net_type, float net_name)
                case MSG_WEAPON: return msg_weapon_notifs[net_name - 1];
                case MSG_DEATH: return msg_death_notifs[net_name - 1];
        }
                case MSG_WEAPON: return msg_weapon_notifs[net_name - 1];
                case MSG_DEATH: return msg_death_notifs[net_name - 1];
        }
+       backtrace(sprintf("Get_Notif_Ent(%d, %d): Improper net type!\n", net_type, net_name));
        return world;
 }
 
        return world;
 }
 
-string Get_Field_Value(float field, float net_type, float net_name)
+string Notification_CheckArgs_TypeName(float net_type, float net_name)
 {
 {
-       entity e = Get_Notif_Ent(net_type, net_name);
-
-       dprint(sprintf("Get_Field_Value(%d, %d, %d); - name=%s, stringcount=%d, floatcount=%d...\n", field, net_type, net_name, e.nent_name, e.nent_stringcount, e.nent_floatcount));
-
+       // check supplied type and name for errors
+       string checkargs = "";
+       #define CHECKARG_TYPENAME(type) case MSG_##type##: \
+               { if(!net_name || (net_name > NOTIF_##type##_COUNT)) \
+               { checkargs = sprintf("Improper name: %d!", net_name); } break; }
        switch(net_type)
        {
        switch(net_type)
        {
-               case F_NAME: { return e.nent_name; }
-               case F_INFVAL: { return ftos(e.nent_infoname); } 
-               case F_CENVAL: { return ftos(e.nent_centername); } 
-               case F_STRNUM: { return ftos(e.nent_stringcount); } 
-               case F_FLNUM: { return ftos(e.nent_stringcount); }
+               CHECKARG_TYPENAME(INFO)
+               CHECKARG_TYPENAME(CENTER)
+               CHECKARG_TYPENAME(WEAPON)
+               CHECKARG_TYPENAME(DEATH)
+               default: { checkargs = sprintf("Improper type: %d!", checkargs, net_type); break; }
        }
        }
-       
-       return "";
+       #undef CHECKARG_TYPENAME
+       return checkargs;
 }
 
 }
 
-// get the actual name of a notification and return it as a string
-/*string Get_Field_Value(float field, float net_type, float net_name)
+#ifdef SVQC
+string Notification_CheckArgs(float broadcast, entity client, float net_type, float net_name)
 {
 {
-       #ifdef NOTIFICATIONS_DEBUG
-               dprint(sprintf("Get_Field_Value(%d, %d, %d);\n", field, net_type, net_name));
-       #endif
-       
-       #define GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) switch(field) { \
-                       case F_NAME: { return VAR_TO_TEXT(name); } \
-                       case F_STRNUM: { return ftos(strnum); } \
-                       case F_FLNUM: { return ftos(flnum); } }
-
-       #define GET_FIELD_VALUE_OUTPUT_PAIR(field,name,infoname,centername,strnum,flnum) switch(field) { \
-                       case F_NAME: { return VAR_TO_TEXT(name); } \
-                       case F_INFNAME: { return VAR_TO_TEXT(infoname); } \
-                       case F_CENNAME: { return VAR_TO_TEXT(centername); } \
-                       case F_INFVAL: { return ftos(infoname); } \
-                       case F_CENVAL: { return ftos(centername); } \
-                       case F_STRNUM: { return ftos(strnum); } \
-                       case F_FLNUM: { return ftos(flnum); } }
-
-       #define CLPSE_GETVALUE(name,arg,earg) \
-               #if name != NO_MSG \
-                       arg \
-               #else \
-                       earg \
+       // check supplied broadcast, target, type, and name for errors
+       string checkargs = Notification_CheckArgs_TypeName(net_type, net_name);
+       if(checkargs != "") { checkargs = strcat(checkargs, " "); }
+       switch(broadcast)
+       {
+               case NOTIF_ONE:
+               case NOTIF_ONE_ONLY:
+               {
+                       if(IS_NOT_A_CLIENT(client))
+                               { checkargs = sprintf("%sNo client provided!", checkargs); }
+                       break;
+               }
+               
+               case NOTIF_ANY_EXCEPT:
+               {
+                       if(IS_NOT_A_CLIENT(client))
+                               { checkargs = sprintf("%sException can't be a non-client!", checkargs); }
+                       break;
+               }
+               
+               case NOTIF_ANY:
+               {
+                       if(client)
+                               { checkargs = sprintf("%sEntity provided when world was required!", checkargs); }
+                       break;
+               }
+               
+               case NOTIF_TEAM:
+               case NOTIF_TEAM_EXCEPT:
+               {
+                       if not(teamplay) { checkargs = sprintf("%sTeamplay not active!", checkargs); }
+                       else if(IS_NOT_A_CLIENT(client))
+                       {
+                               if(broadcast == NOTIF_TEAM) { checkargs = sprintf("%sNo client provided!", checkargs); }
+                               else { checkargs = sprintf("%sException can't be a non-client!", checkargs); }
+                       }
+                       break;
+               }
+               
+               default: { checkargs = sprintf("%sImproper broadcast: %d!", checkargs, broadcast); break; }
+       }
+       return checkargs;
+}
+#endif
+
+// ===============================
+//  Initialization Core Functions
+// ===============================
+
+string Process_Notif_Line(
+       float msg_is_info,
+       float chat,
+       string input,
+       string notiftype,
+       string notifname,
+       string stringtype)
+{
+       if(msg_is_info)
+       {
+               #ifdef CSQC
+               if((chat && autocvar_notification_allow_chatboxprint)
+                       || (autocvar_notification_allow_chatboxprint == 2))
+               {
+                       // pass 1: add ETX char at beginning of line
+                       input = strcat("\{3}", input);
+
+                       // pass 2: add ETX char at end of each new line (so that
+                       // messages with multiple lines are put through chatbox too)
+                       input = strreplace("\n", "\n\{3}", input);
+
+                       // pass 3: strip trailing ETX char
+                       if(substring(input, (strlen(input) - 1), 1) == "\{3}")
+                               { input = substring(input, 0, (strlen(input) - 1)); }
+               }
                #endif
                #endif
+               if(substring(input, (strlen(input) - 1), 1) != "\n")
+               {
+                       print(sprintf(
+                               strcat(
+                                       "^1MISSING/BROKEN NEW LINE AT END OF NOTIFICATION: ",
+                                       "^7net_type = MSG_%s, net_name = %s, string = %s.\n"
+                               ),
+                               notiftype,
+                               notifname,
+                               stringtype
+                       ));
+                       notif_error = TRUE;
+                       return strcat(input, "\n");
+               }
+       }
+       return input;
+}
 
 
-       switch(net_type)
+string Process_Notif_Args(
+       float arg_type,
+       string args,
+       string notiftype,
+       string notifname)
+{
+       string selected, remaining = args;
+       float sel_num = 0;
+
+       for(;(remaining != "");)
+       {
+               selected = car(remaining); remaining = cdr(remaining);
+
+               switch(arg_type)
+               {
+                       case 1: // normal args
+                       {
+                               if(sel_num == NOTIF_MAX_ARGS)
+                               {
+                                       print(sprintf(
+                                               strcat(
+                                                       "^1NOTIFICATION HAS TOO MANY ARGUMENTS: ",
+                                                       "^7net_type = MSG_%s, net_name = %s, max args = %d.\n"
+                                               ),
+                                               notiftype,
+                                               notifname,
+                                               NOTIF_MAX_ARGS
+                                       ));
+                                       notif_error = TRUE;
+                                       break;
+                               }
+
+                               switch(strtolower(selected))
+                               {
+                                       #define ARG_CASE(prog,selected,result) case selected: { ++sel_num; break; }
+                                       NOTIF_ARGUMENT_LIST
+                                       #undef ARG_CASE
+                                       default:
+                                       {
+                                               print(sprintf(
+                                                       strcat(
+                                                               "^1NOTIFICATION WITH UNKNOWN TOKEN IN ARGUMENT STRING: ",
+                                                               "^7net_type = MSG_%s, net_name = %s, args arg = '%s'.\n"
+                                                       ),
+                                                       notiftype,
+                                                       notifname,
+                                                       selected
+                                               ));
+                                               notif_error = TRUE;
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+                       case 2: // hudargs
+                       {
+                               if(sel_num == NOTIF_MAX_HUDARGS)
+                               {
+                                       print(sprintf(
+                                               strcat(
+                                                       "^1NOTIFICATION HAS TOO MANY ARGUMENTS: ",
+                                                       "^7net_type = MSG_%s, net_name = %s, max hudargs = %d.\n"
+                                               ),
+                                               notiftype,
+                                               notifname,
+                                               NOTIF_MAX_HUDARGS
+                                       ));
+                                       notif_error = TRUE;
+                                       break;
+                               }
+
+                               switch(strtolower(selected))
+                               {
+                                       #define ARG_CASE(prog,selected,result) \
+                                               #if (prog == ARG_CS_SV_HA) \
+                                                       case selected: { ++sel_num; break; } \
+                                               #endif
+                                       NOTIF_ARGUMENT_LIST
+                                       #undef ARG_CASE
+                                       default:
+                                       {
+                                               print(sprintf(
+                                                       strcat(
+                                                               "^1NOTIFICATION WITH UNKNOWN TOKEN IN ARGUMENT STRING: ",
+                                                               "^7net_type = MSG_%s, net_name = %s, hudargs arg = '%s'.\n"
+                                                       ),
+                                                       notiftype,
+                                                       notifname,
+                                                       selected
+                                               ));
+                                               notif_error = TRUE;
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+                       case 3: // durcnt 
+                       {
+                               if(sel_num == NOTIF_MAX_DURCNT)
+                               {
+                                       print(sprintf(
+                                               strcat(
+                                                       "^1NOTIFICATION HAS TOO MANY ARGUMENTS: ",
+                                                       "^7net_type = MSG_%s, net_name = %s, max durcnt = %d.\n"
+                                               ),
+                                               notiftype,
+                                               notifname,
+                                               NOTIF_MAX_DURCNT
+                                       ));
+                                       notif_error = TRUE;
+                                       break;
+                               }
+
+                               switch(strtolower(selected))
+                               {
+                                       #define ARG_CASE(prog,selected,result) \
+                                               #if (prog == ARG_CS_SV_DC) || (prog == ARG_DC) \
+                                                       case selected: { ++sel_num; break; } \
+                                               #endif
+                                       NOTIF_ARGUMENT_LIST
+                                       #undef ARG_CASE
+                                       default:
+                                       {
+                                               if(ftos(stof(selected)) != "") { ++sel_num; }
+                                               else
+                                               {
+                                                       print(sprintf(
+                                                               strcat(
+                                                                       "^1NOTIFICATION WITH UNKNOWN TOKEN IN ARGUMENT STRING: ",
+                                                                       "^7net_type = MSG_%s, net_name = %s, durcnt arg = '%s'.\n"
+                                                               ),
+                                                               notiftype,
+                                                               notifname,
+                                                               selected
+                                                       ));
+                                                       notif_error = TRUE;
+                                               }
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+               }
+       }
+       return args;
+}
+
+void Create_Notification_Entity(
+       float var_default,
+       float var_cvar,
+       float typeid,
+       float nameid,
+       string namestring,
+       float infoname,
+       float centername,
+       float strnum,
+       float flnum,
+       string args,
+       string hudargs,
+       string icon,
+       float cpid,
+       string durcnt,
+       string normal,
+       string gentle,
+       float msg_is_info,
+       float msg_is_multi)
+{
+       // =====================
+       //  Global Entity Setup
+       // =====================
+       entity notif = spawn();
+       string typestring = "";
+       switch(typeid)
        {
                case MSG_INFO:
                {
        {
                case MSG_INFO:
                {
-                       #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) case name: { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) }
-                       NOTIF_SWITCH_LIST(MSG_INFO, net_name, return "")
-                       #undef MSG_INFO_NOTIF
+                       typestring = "MSG_INFO";
+                       msg_info_notifs[nameid - 1] = notif;
+                       notif.classname = "msg_info_notification";
                        break;
                }
                case MSG_CENTER:
                {
                        break;
                }
                case MSG_CENTER:
                {
-                       #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) case name: { GET_FIELD_VALUE_OUTPUT(field,name,strnum,flnum) }
-                       NOTIF_SWITCH_LIST(MSG_CENTER, net_name, return "")
-                       #undef MSG_CENTER_NOTIF
+                       typestring = "MSG_CENTER";
+                       msg_center_notifs[nameid - 1] = notif;
+                       notif.classname = "msg_center_notification";
                        break;
                }
                case MSG_WEAPON:
                {
                        break;
                }
                case MSG_WEAPON:
                {
-                       #define MSG_WEAPON_NOTIF(name,infoname,centername) case name: { GET_FIELD_VALUE_OUTPUT_PAIR(field,name, \
-                               CLPSE_GETVALUE(infoname, infoname, NO_MSG), CLPSE_GETVALUE(centername, centername, NO_MSG), \
-                               max(CLPSE_GETVALUE(infoname, stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), 0), CLPSE_GETVALUE(centername, stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername)), 0)), \
-                               max(CLPSE_GETVALUE(infoname, stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), 0), CLPSE_GETVALUE(centername, stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)), 0))) }
-                       NOTIF_SWITCH_LIST(MSG_WEAPON, net_name, return "")
-                       #undef MSG_WEAPON_NOTIF
+                       typestring = "MSG_WEAPON";
+                       msg_weapon_notifs[nameid - 1] = notif;
+                       notif.classname = "msg_weapon_notification";
                        break;
                }
                case MSG_DEATH:
                {
                        break;
                }
                case MSG_DEATH:
                {
-                       #define MSG_DEATH_NOTIF(name,infoname,centername) case name: { GET_FIELD_VALUE_OUTPUT_PAIR(field,name, \
-                               CLPSE_GETVALUE(infoname, infoname, NO_MSG), CLPSE_GETVALUE(centername, centername, NO_MSG), \
-                               max(CLPSE_GETVALUE(infoname, stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), 0), CLPSE_GETVALUE(centername, stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername)), 0)), \
-                               max(CLPSE_GETVALUE(infoname, stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), 0), CLPSE_GETVALUE(centername, stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)), 0))) }
-                       NOTIF_SWITCH_LIST(MSG_DEATH, net_name, return "")
-                       #undef MSG_DEATH_NOTIF
+                       typestring = "MSG_DEATH";
+                       msg_death_notifs[nameid - 1] = notif;
+                       notif.classname = "msg_death_notification";
                        break;
                }
                        break;
                }
+               default:
+               {
+                       error(sprintf(
+                               strcat(
+                                       "^1NOTIFICATION WITH IMPROPER TYPE: ",
+                                       "^7net_type = %d, net_name = %s.\n"
+                               ),
+                               typeid,
+                               namestring
+                       ));
+                       return; // It's not possible to recover from this one
+               }
        }
        }
+       notif.nent_default = var_default;
+       notif.nent_name = strzone(namestring);
+       notif.nent_id = nameid;
+       notif.nent_enabled = (1 <= var_cvar);
 
 
-       #undef GET_FIELD_VALUE_OUTPUT
-       #undef GET_FIELD_VALUE_OUTPUT_PAIR
-       #undef CLPSE_GETVALUE
-       return "";
-}*/
-#endif // ifndef MENUQC
+       // Other pre-notif-setup requisites
+       notif_error = FALSE;
+
+       // ====================
+       //  Notification Setup
+       // ====================
+       if(msg_is_multi)
+       {
+               // Set MSG_WEAPON and MSG_DEATH string/float counts
+               if((infoname == NO_MSG) && (centername == NO_MSG))
+               {
+                       print(sprintf(
+                               strcat(
+                                       "^1NOTIFICATION WITH NO SUBCALLS: ",
+                                       "^7net_type = %s, net_name = %s.\n"
+                               ),
+                               typestring,
+                               namestring
+                       ));
+                       notif_error = TRUE;
+               }
+               else
+               {
+                       float infoname_stringcount = 0, infoname_floatcount = 0;
+                       float centername_stringcount = 0, centername_floatcount = 0;
+                       
+                       if(infoname != NO_MSG)
+                       {
+                               notif.nent_msginfo = msg_info_notifs[infoname - 1];
+                               infoname_stringcount = notif.nent_msginfo.nent_stringcount;
+                               infoname_floatcount = notif.nent_msginfo.nent_floatcount;
+                       }
+                       
+                       if(centername != NO_MSG)
+                       {
+                               notif.nent_msgcenter = msg_center_notifs[centername - 1];
+                               centername_stringcount = notif.nent_msgcenter.nent_stringcount;
+                               centername_floatcount = notif.nent_msgcenter.nent_floatcount;
+                       }
+                       
+                       // set the requirements of THIS notification to the totals of its subcalls
+                       notif.nent_stringcount = max(infoname_stringcount, centername_stringcount);
+                       notif.nent_floatcount = max(infoname_floatcount, centername_floatcount);
+               }
+       }
+       else
+       {
+               // Set MSG_INFO and MSG_CENTER string/float counts
+               notif.nent_stringcount = strnum;
+               notif.nent_floatcount = flnum;
+
+               // Only initialize arguments if we're either a client or on a dedicated server
+               #ifdef SVQC
+               float should_process_args = server_is_dedicated;
+               #else
+               float should_process_args = TRUE;
+               #endif
+
+               if(should_process_args)
+               {
+                       // ========================
+                       //  Process Main Arguments
+                       // ========================
+                       if(strnum + flnum)
+                       {
+                               if(args != "")
+                               {
+                                       notif.nent_args = strzone(
+                                               Process_Notif_Args(1, args, typestring, namestring));
+                               }
+                               else if((hudargs == "") && (durcnt ==""))
+                               {
+                                       print(sprintf(
+                                               strcat(
+                                                       "^1NOTIFICATION HAS ARG COUNTS BUT NO ARGS OR HUDARGS OR DURCNT: ",
+                                                       "^7net_type = %s, net_name = %s, strnum = %d, flnum = %d\n"
+                                               ),
+                                               typestring,
+                                               namestring,
+                                               strnum,
+                                               flnum
+                                       ));
+                                       notif_error = TRUE;
+                               }
+                       }
+                       else if(args != "")
+                       {
+                               notif.nent_args = strzone(
+                                       Process_Notif_Args(1, args, typestring, namestring));
+                       }
+
+
+                       // =======================================
+                       //  Process HUD and Centerprint Arguments
+                       //    Only processed on CSQC, as these
+                       //    args are only for HUD features.
+                       // =======================================
+                       #ifdef CSQC
+                       if(hudargs != "")
+                       {
+                               notif.nent_hudargs = strzone(
+                                       Process_Notif_Args(2, hudargs, typestring, namestring));
+                                       
+                               if(icon != "") { notif.nent_icon = strzone(icon); }
+                               else
+                               {
+                                       print(sprintf(
+                                               strcat(
+                                                       "^1NOTIFICATION HAS HUDARGS BUT NO ICON: ",
+                                                       "^7net_type = MSG_%s, net_name = %s.\n"
+                                               ),
+                                               typestring,
+                                               namestring
+                                       ));
+                                       notif_error = TRUE;
+                               }
+                       }
+                       else if(icon != "")
+                       {
+                               print(sprintf(
+                                       strcat(
+                                               "^1NOTIFICATION HAS ICON BUT NO HUDARGS: ",
+                                               "^7net_type = MSG_%s, net_name = %s.\n"
+                                       ),
+                                       typestring,
+                                       namestring
+                               ));
+                               notif_error = TRUE;
+                       }
+
+                       if(durcnt != "")
+                       {
+                               notif.nent_durcnt = strzone(
+                                       Process_Notif_Args(3, durcnt, typestring, namestring));
+                                       
+                               if(cpid != NO_MSG) { notif.nent_cpid = cpid; }
+                               else
+                               {
+                                       print(sprintf(
+                                               strcat(
+                                                       "^1NOTIFICATION HAS DURCNT BUT NO CPID: ",
+                                                       "^7net_type = MSG_%s, net_name = %s.\n"
+                                               ),
+                                               typestring,
+                                               namestring
+                                       ));
+                                       notif_error = TRUE;
+                               }
+                       } 
+                       else if(cpid != NO_MSG) { notif.nent_cpid = cpid; }
+                       #endif
+
+
+                       // ======================
+                       //  Process Notif String
+                       // ======================
+                       #define SET_NOTIF_STRING(string,stringname) \
+                               notif.nent_string = strzone(CCR( \
+                                       Process_Notif_Line( \
+                                               msg_is_info, \
+                                               (var_cvar > 1), \
+                                               string, \
+                                               typestring, \
+                                               namestring, \
+                                               stringname \
+                                       )) \
+                               );
+
+                       if(GENTLE)
+                       {
+                               if(gentle != "") { SET_NOTIF_STRING(gentle, "GENTLE") }
+                               else if(normal != "") { SET_NOTIF_STRING(normal, "NORMAL") }
+                       }
+                       else if(normal != "") { SET_NOTIF_STRING(normal, "NORMAL") }
+                       
+                       #undef SET_NOTIF_STRING
+
+                       // Check to make sure a string was chosen
+                       if(notif.nent_string == "")
+                       {
+                               print(sprintf(
+                                       strcat(
+                                               "^1EMPTY NOTIFICATION: ",
+                                               "^7net_type = MSG_%s, net_name = %s.\n"
+                                       ),
+                                       typestring,
+                                       namestring
+                               ));
+                               notif_error = TRUE;
+                       }
+               }
+       }
+
+       // now check to see if any errors happened 
+       if(notif_error)
+       {
+               notif.nent_enabled = FALSE; // disable the notification so it can't cause trouble
+               notif_global_error = TRUE; // throw the red flag that an error happened on init
+       }
+}
 
 
 // ===============================
 
 
 // ===============================
@@ -180,215 +572,386 @@ string Get_Field_Value(float field, float net_type, float net_name)
 
 void Dump_Notifications(float fh, float alsoprint)
 {
 
 void Dump_Notifications(float fh, float alsoprint)
 {
-       float MSG_INFO_NOTIFS = 0, MSG_CENTER_NOTIFS = 0, MSG_WEAPON_NOTIFS = 0, MSG_DEATH_NOTIFS = 0;
+       #define NOTIF_WRITE(a) { \
+               fputs(fh, a); \
+               if(alsoprint) { print(a); } }
+       #define NOTIF_WRITE_ENTITY(name,default,description) { \
+               notif_msg = \
+                       sprintf( \
+                               "seta notification_%s \"%d\" \"%s\"\n", \
+                               name, default, description \
+                       ); \
+               NOTIF_WRITE(notif_msg) }
+       #define NOTIF_WRITE_HARDCODED(cvar,default,description) { \
+               notif_msg = \
+                       sprintf( \
+                               "seta notification_%s \"%s\" \"%s\"\n", \
+                               cvar, default, description \
+                       ); \
+               NOTIF_WRITE(notif_msg) }
+
        string notif_msg;
        string notif_msg;
+       float i;
+       entity e;
 
 
-       #define NOTIF_WRITE(type,name,text) { \
-               ++##type##_NOTIFS; \
-               notif_msg = sprintf("seta %s 1 // %s - %s\n", #name, #type, strreplace("\n", "\\n", text)); \
-               fputs(fh, notif_msg); \
-               if(alsoprint) { print(strreplace("^", "^^", notif_msg)); } }
-       
-       #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) NOTIF_WRITE(MSG_INFO, name, normal)
-       MSG_INFO_NOTIFICATIONS
-       #undef MSG_INFO_NOTIF
-       
-       #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) NOTIF_WRITE(MSG_CENTER, name, normal)
-       MSG_CENTER_NOTIFICATIONS
-       #undef MSG_CENTER_NOTIF
-       
-       #define MSG_WEAPON_NOTIF(name,infoname,centername) NOTIF_WRITE(MSG_WEAPON, name, \
-               sprintf("infoname: %s, centername: %s", VAR_TO_TEXT(infoname), VAR_TO_TEXT(centername)))
-       MSG_WEAPON_NOTIFICATIONS
-       #undef MSG_WEAPON_NOTIF
-       
-       #define MSG_DEATH_NOTIF(name,infoname,centername) NOTIF_WRITE(MSG_DEATH, name, \
-               sprintf("infoname: %s, centername: %s", VAR_TO_TEXT(infoname), VAR_TO_TEXT(centername)))
-       MSG_DEATH_NOTIFICATIONS
-       #undef MSG_DEATH_NOTIF
-       
-       print(sprintf("Notification counts: MSG_INFO = %d, MSG_CENTER = %d, MSG_WEAPON = %d, MSG_DEATH = %d\n",
-               MSG_INFO_NOTIFS, MSG_CENTER_NOTIFS, MSG_WEAPON_NOTIFS, MSG_DEATH_NOTIFS));
+       // Note: This warning only applies to the notifications.cfg file that is output...
+
+       // You ARE supposed to manually edit this function to add i.e. hard coded
+       // notification variables for mutators or game modes or such and then
+       // regenerate the notifications.cfg file from the new code.
+
+       NOTIF_WRITE("// ********************************************** //\n");
+       NOTIF_WRITE("// ** WARNING - DO NOT MANUALLY EDIT THIS FILE ** //\n");
+       NOTIF_WRITE("// **                                          ** //\n");
+       NOTIF_WRITE("// **  This file is automatically generated    ** //\n");
+       NOTIF_WRITE("// **  by code with the command 'dumpnotifs'.  ** //\n");
+       NOTIF_WRITE("// **                                          ** //\n");
+       NOTIF_WRITE("// **  If you add a new notification, please   ** //\n");
+       NOTIF_WRITE("// **  regenerate this file with that command  ** //\n");
+       NOTIF_WRITE("// **  making sure that the output matches     ** //\n");
+       NOTIF_WRITE("// **  with the lists and defaults in code.    ** //\n");
+       NOTIF_WRITE("// **                                          ** //\n");
+       NOTIF_WRITE("// ********************************************** //\n");
+
+       // These notifications will also append their string as a comment...
+       // This is not necessary, and does not matter if they vary between config versions,
+       // it is just a semi-helpful tool for those who want to manually change their user settings.
+
+       NOTIF_WRITE(sprintf("\n// MSG_INFO notifications (count = %d):\n", NOTIF_INFO_COUNT));
+       for(i = 1; i <= NOTIF_INFO_COUNT; ++i)
+       {
+               e = Get_Notif_Ent(MSG_INFO, i);
+               if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; }
+               NOTIF_WRITE_ENTITY(e.nent_name, e.nent_default, "Notification control cvar: 0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)");
+       }
+
+       NOTIF_WRITE(sprintf("\n// MSG_CENTER notifications (count = %d):\n", NOTIF_CENTER_COUNT));
+       for(i = 1; i <= NOTIF_CENTER_COUNT; ++i)
+       {
+               e = Get_Notif_Ent(MSG_CENTER, i);
+               if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; }
+               NOTIF_WRITE_ENTITY(e.nent_name, e.nent_default, "Notification control cvar: 0 = off, 1 = centerprint");
+       }
+
+       NOTIF_WRITE(sprintf("\n// MSG_WEAPON notifications (count = %d):\n", NOTIF_WEAPON_COUNT));
+       for(i = 1; i <= NOTIF_WEAPON_COUNT; ++i)
+       {
+               e = Get_Notif_Ent(MSG_WEAPON, i);
+               if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; }
+               NOTIF_WRITE_ENTITY(e.nent_name, e.nent_default, "Notification control cvar: 0 = off, 1 = trigger subcalls");
+       }
+
+       NOTIF_WRITE(sprintf("\n// MSG_DEATH notifications (count = %d):\n", NOTIF_DEATH_COUNT));
+       for(i = 1; i <= NOTIF_DEATH_COUNT; ++i)
+       {
+               e = Get_Notif_Ent(MSG_DEATH, i);
+               if not(e) { backtrace("Dump_Notifications(): Missing notification entity!\n"); return; }
+               NOTIF_WRITE_ENTITY(e.nent_name, e.nent_default, "Notification control cvar: 0 = off, 1 = trigger subcalls");
+       }
+
+       // edit these to match whichever cvars are used for specific notification options
+       NOTIF_WRITE("\n// HARD CODED notification variables:\n");
+       NOTIF_WRITE_HARDCODED("allow_chatboxprint",                             "1",    "Allow notifications to be printed to chat box by setting notification cvar to 2 (You can also set this cvar to 2 to force ALL notifications to be printed to the chatbox)");
+       NOTIF_WRITE_HARDCODED("show_location",                                          "0",    "Append location information to MSG_INFO death/kill messages");
+       NOTIF_WRITE_HARDCODED("show_location_string",                           "",     "Replacement string piped into sprintf, so you can do different messages like this: ' at the %s' or ' (near %s)'");
+       NOTIF_WRITE_HARDCODED("show_sprees",                                            "1",    "Print information about sprees in death/kill messages");
+       NOTIF_WRITE_HARDCODED("show_sprees_center",                             "1",    "Show spree information in MSG_CENTER messages... 0 = off, 1 = target (but only for first victim) and attacker");
+       NOTIF_WRITE_HARDCODED("show_sprees_center_specialonly",         "1",    "Don't show spree information in MSG_CENTER messages if it isn't an achievement");
+       NOTIF_WRITE_HARDCODED("show_sprees_info",                                       "3",    "Show spree information in MSG_INFO messages... 0 = off, 1 = target only, 2 = attacker only, 3 = target and attacker");
+       NOTIF_WRITE_HARDCODED("show_sprees_info_newline",                       "0",    "Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself");
+       NOTIF_WRITE_HARDCODED("show_sprees_info_specialonly",           "1",    "Don't show attacker spree information in MSG_INFO messages if it isn't an achievement");
+       NOTIF_WRITE_HARDCODED("item_centerprinttime",                           "1.5",  "How long to show item information centerprint messages (like 'You got the Electro' or such)");
+       NOTIF_WRITE_HARDCODED("errors_are_fatal",                                       "1",    "If a notification fails upon initialization, cause a Host_Error to stop the program");
+       NOTIF_WRITE_HARDCODED("ctf_pickup_team_verbose",                        "0",    "Show extra information if a team mate picks up a flag");
+       NOTIF_WRITE_HARDCODED("ctf_pickup_enemy_verbose",                       "0",    "Show extra information if an enemy picks up a flag");
+       NOTIF_WRITE_HARDCODED("ctf_capture_verbose",                            "0",    "Show extra information when someone captures a flag");
+       NOTIF_WRITE_HARDCODED("frag_verbose",                                           "1",    "Show extra information when you frag someone (or when you are fragged");
+       NOTIF_WRITE_HARDCODED("lifetime_runtime",                                       "0.5",  "Amount of time that notification entities last on the server during runtime (In seconds)");
+       NOTIF_WRITE_HARDCODED("lifetime_mapload",                                       "10",   "Amount of time that notification entities last immediately at mapload (in seconds) to help prevent notifications from being lost on early init (like gamestart countdown)");
+
+       NOTIF_WRITE(sprintf("\n// Notification counts (total = %d): MSG_INFO = %d, MSG_CENTER = %d, MSG_WEAPON = %d, MSG_DEATH = %d\n",
+               (NOTIF_INFO_COUNT + NOTIF_CENTER_COUNT + NOTIF_WEAPON_COUNT + NOTIF_DEATH_COUNT), 
+               NOTIF_INFO_COUNT, NOTIF_CENTER_COUNT, NOTIF_WEAPON_COUNT, NOTIF_DEATH_COUNT));
        
        return;
        
        return;
+       #undef NOTIF_WRITE_HARDCODED
+       #undef NOTIF_WRITE_ENTITY
        #undef NOTIF_WRITE
 }
 
        #undef NOTIF_WRITE
 }
 
-#ifndef MENUQC
-#ifdef CSQC
-void HUD_Notify_Push(string icon, string attacker, string victim)
+#ifdef SVQC
+void Notification_GetCvars()
 {
 {
-       if(icon != "")
-       {
-               --kn_index;
-               if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
-               killnotify_times[kn_index] = time;
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, FRAG_VERBOSE, "notification_frag_verbose");
+}
+#endif
 
 
-               // icon
-               if(killnotify_icon[kn_index]) { strunzone(killnotify_icon[kn_index]); }
-               killnotify_icon[kn_index] = strzone(icon);
+string Local_Notification_sprintf(string input, string args, 
+       string s1, string s2, string s3, string s4,
+       float f1, float f2, float f3, float f4)
+{
+       #ifdef NOTIFICATIONS_DEBUG
+       dprint(sprintf(
+               "Local_Notification_sprintf('%s^7', '%s', %s, %s);\n",
+               strreplace("\n", "\\n", input),
+               args,
+               strreplace("\n", "\\n", sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)),
+               sprintf("%d, %d, %d, %d", f1, f2, f3, f4)
+       ));
+       #endif
+       
+       string selected;
+       float sel_num;
+       for(sel_num = 0; sel_num < NOTIF_MAX_ARGS; ++sel_num) { arg_slot[sel_num] = ""; }
 
 
-               // attacker
-               if(killnotify_attackers[kn_index]) { strunzone(killnotify_attackers[kn_index]); }
-               killnotify_attackers[kn_index] = strzone(attacker);
+       string tmp_s;
 
 
-               // victim
-               if(killnotify_victims[kn_index]) { strunzone(killnotify_victims[kn_index]); }
-               killnotify_victims[kn_index] = strzone(victim);
+       for(sel_num = 0;(args != "");)
+       {
+               selected = car(args); args = cdr(args);
+               NOTIF_HIT_MAX(NOTIF_MAX_ARGS, "Local_Notification_sprintf")
+               switch(strtolower(selected))
+               {
+                       #define ARG_CASE(prog,selected,result) \
+                               #ifdef CSQC \
+                                       #if (prog != ARG_SV) && (prog != ARG_DC) \
+                                               case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \
+                                       #endif \
+                               #else \
+                                       #if (prog != ARG_CS) && (prog != ARG_DC) \
+                                               case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \
+                                       #endif \
+                               #endif
+                       NOTIF_ARGUMENT_LIST
+                       #undef ARG_CASE
+                       default: NOTIF_HIT_UNKNOWN(NOTIF_MAX_ARGS, "Local_Notification_sprintf")
+               }
        }
        }
+       return sprintf(input, arg_slot[0], arg_slot[1], arg_slot[2], arg_slot[3], arg_slot[4], arg_slot[5], arg_slot[6]);
 }
 }
-#endif // ifdef CSQC
 
 
-void Local_Notification(float net_type, float net_name, ...count)
+#ifdef CSQC
+void Local_Notification_HUD_Notify_Push(string icon, string hudargs, string s1, string s2, string s3, string s4)
 {
 {
-       // check supplied type and name for errors
-       #ifdef NOTIFICATIONS_DEBUG
+       string selected;
+       float sel_num;
+       arg_slot[0] = ""; arg_slot[1] = "";
+
+       for(sel_num = 0;(hudargs != "");)
        {
        {
-               #define CHECKARG_TYPENAME(type) case MSG_##type##: \
-                       { if(!net_name || (net_name > NOTIF_##type##_COUNT)) \
-                       { checkargs = sprintf("Improper name: %d!", net_name); } break; }
-                       
-               string checkargs = "";
-               switch(net_type)
+               selected = car(hudargs); hudargs = cdr(hudargs);
+               NOTIF_HIT_MAX(NOTIF_MAX_HUDARGS, "Local_Notification_HUD_Notify_Push")
+               switch(strtolower(selected))
                {
                {
-                       CHECKARG_TYPENAME(INFO)
-                       CHECKARG_TYPENAME(CENTER)
-                       CHECKARG_TYPENAME(WEAPON)
-                       CHECKARG_TYPENAME(DEATH)
-                       
-                       default: { checkargs = sprintf("Improper type: %d!", checkargs, net_type); break; }
+                       #define ARG_CASE(prog,selected,result) \
+                               #if (prog == ARG_CS_SV_HA) \
+                                       case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \
+                               #endif
+                       NOTIF_ARGUMENT_LIST
+                       #undef ARG_CASE
+                       default: NOTIF_HIT_UNKNOWN(NOTIF_MAX_HUDARGS, "Local_Notification_HUD_Notify_Push")
                }
                }
-               #undef CHECKARG_TYPENAME
+       }
+       #ifdef NOTIFICATIONS_DEBUG
+       dprint(sprintf(
+               "Local_Notification_HUD_Notify_Push('%s^7', '%s', %s, %s);\n",
+               icon,
+               hudargs,
+               strreplace("\n", "\\n", sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)),
+               strreplace("\n", "\\n", sprintf("'%s^7', '%s^7'", stof(arg_slot[0]), stof(arg_slot[1])))
+       ));
+       #endif
+       HUD_Notify_Push(icon, arg_slot[0], arg_slot[1]);
+}
+
+void Local_Notification_centerprint_generic(string input, string durcnt, float cpid, float f1, float f2)
+{
+       string selected;
+       float sel_num;
+       arg_slot[0] = ""; arg_slot[1] = "";
 
 
-               if(checkargs != "") { backtrace(sprintf("Incorrect usage of Local_Notification: %s\n", checkargs)); return; }
+       for(sel_num = 0;(durcnt != "");)
+       {
+               selected = car(durcnt); durcnt = cdr(durcnt);
+               NOTIF_HIT_MAX(NOTIF_MAX_DURCNT, "Local_Notification_centerprint_generic")
+               switch(strtolower(selected))
+               {
+                       #define ARG_CASE(prog,selected,result) \
+                               #if (prog == ARG_CS_SV_DC) || (prog == ARG_DC) \
+                                       case selected: { arg_slot[sel_num] = result; ++sel_num; break; } \
+                               #endif
+                       NOTIF_ARGUMENT_LIST
+                       #undef ARG_CASE
+                       default:
+                       {
+                               if(ftos(stof(selected)) != "") { arg_slot[sel_num] = selected; ++sel_num; }
+                               else { NOTIF_HIT_UNKNOWN(NOTIF_MAX_DURCNT, "Local_Notification_centerprint_generic") }
+                               break;
+                       }
+               }
        }
        }
+       #ifdef NOTIFICATIONS_DEBUG
+       dprint(sprintf(
+               "Local_Notification_centerprint_generic('%s^7', '%s', %d, %d, %d, %d);\n",
+               strreplace("\n", "\\n", input),
+               durcnt,
+               f1, f2,
+               stof(arg_slot[0]), stof(arg_slot[1])
+       ));
        #endif
        #endif
-       
-       float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
-       float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
-
-       string s1 = ((0 < stringcount) ? ...(0, string) : NO_STR_ARG);
-       string s2 = ((1 < stringcount) ? ...(1, string) : NO_STR_ARG);
-       string s3 = ((2 < stringcount) ? ...(2, string) : NO_STR_ARG);
-       string s4 = ((3 < stringcount) ? ...(3, string) : NO_STR_ARG);
-       float f1 = ((stringcount < count) ? ...(stringcount, float) : NO_FL_ARG);
-       float f2 = (((stringcount + 1) < count) ? ...((stringcount + 1), float) : NO_FL_ARG);
-       float f3 = (((stringcount + 2) < count) ? ...((stringcount + 2), float) : NO_FL_ARG);
-       float f4 = (((stringcount + 3) < count) ? ...((stringcount + 3), float) : NO_FL_ARG);
+       centerprint_generic(cpid, input, stof(arg_slot[0]), stof(arg_slot[1]));
+}
+#endif
+
+void Local_Notification(float net_type, float net_name, ...count)
+{
+       // check supplied type and name for errors
+       string checkargs = Notification_CheckArgs_TypeName(net_type, net_name);
+       if(checkargs != "") { backtrace(sprintf("Incorrect usage of Local_Notification: %s\n", checkargs)); return; }
+
+       entity notif = Get_Notif_Ent(net_type, net_name);
+       if not(notif) { backtrace("Local_Notification: Could not find notification entity!\n"); return; }
 
        #ifdef NOTIFICATIONS_DEBUG
 
        #ifdef NOTIFICATIONS_DEBUG
+       if not(notif.nent_enabled)
        {
        {
-               dprint(sprintf("Local_Notification(%d, %s, %s, %s, %s, %s, %d, %d, %d, %d);\n",
-                       net_type, Get_Field_Value(F_NAME, net_type, net_name),
-                       s1, s2, s3, s4, f1, f2, f3, f4));
-
-               if((stringcount + floatcount) > count)
-                       { backtrace(sprintf("Not enough arguments for Local_Notification! stringcount(%d) + floatcount(%d) > count(%d) \
-                       \nCheck the notification definition and function call for accuracy...?\n", stringcount, floatcount, count)); return; }
-               else if((stringcount + floatcount) < count)
-                       { backtrace(sprintf("Too many arguments for Local_Notification! stringcount(%d) + floatcount(%d) < count(%d) \
-                       \nCheck the notification definition and function call for accuracy...?\n", stringcount, floatcount, count)); return; }
+               dprint(sprintf(
+                       "Local_Notification(%s, %s): Entity was disabled...\n",
+                       Get_Notif_TypeName(net_type),
+                       notif.nent_name
+               ));
+               return;
        }
        #endif
        
        }
        #endif
        
+       if((notif.nent_stringcount + notif.nent_floatcount) > count)
+       {
+               backtrace(sprintf(
+                       strcat(
+                               "Not enough arguments for Local_Notification(%s, %s, ...)! ",
+                               "stringcount(%d) + floatcount(%d) > count(%d)\n", 
+                               "Check the definition and function call for accuracy...?\n"
+                       ),
+                       Get_Notif_TypeName(net_type), notif.nent_name,
+                       notif.nent_stringcount, notif.nent_floatcount, count
+               ));
+               return;
+       }
+       else if((notif.nent_stringcount + notif.nent_floatcount) < count)
+       {
+               backtrace(sprintf(
+                       strcat(
+                               "Too many arguments for Local_Notification(%s, %s, ...)! ",
+                               "stringcount(%d) + floatcount(%d) < count(%d)\n",
+                               "Check the definition and function call for accuracy...?\n"
+                       ),
+                       Get_Notif_TypeName(net_type), notif.nent_name,
+                       notif.nent_stringcount, notif.nent_floatcount, count
+               ));
+               return;
+       }
+
+       string s1 = ((0 < notif.nent_stringcount) ? ...(0, string) : "");
+       string s2 = ((1 < notif.nent_stringcount) ? ...(1, string) : "");
+       string s3 = ((2 < notif.nent_stringcount) ? ...(2, string) : "");
+       string s4 = ((3 < notif.nent_stringcount) ? ...(3, string) : "");
+       float f1 = ((0 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 0), float) : 0);
+       float f2 = ((1 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 1), float) : 0);
+       float f3 = ((2 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 2), float) : 0);
+       float f4 = ((3 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 3), float) : 0);
 
 
+       #ifdef NOTIFICATIONS_DEBUG
+       dprint(sprintf(
+               "Local_Notification(%s, %s, %s, %s);\n",
+               Get_Notif_TypeName(net_type),
+               notif.nent_name,
+               strreplace("\n", "\\n", sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)),
+               sprintf("%d, %d, %d, %d", f1, f2, f3, f4)
+       ));
+       #endif
+       
        switch(net_type)
        {
                case MSG_INFO:
                {
        switch(net_type)
        {
                case MSG_INFO:
                {
-                       #define MSG_INFO_NOTIF(name,strnum,flnum,args,hudargs,icon,normal,gentle) \
-                               case name: { CHECK_AUTOCVAR(name) \
-                               { \
-                                       print(sprintf(CCR(normal_or_gentle(normal, gentle)), args)); \
-                                       #ifdef CSQC \
-                                               if(icon != "") { HUD_Notify_Push(icon, hudargs); } \
-                                       #endif \
-                               } return; }
-                               
-                       NOTIF_SWITCH_LIST(MSG_INFO, net_name, return)
-                       
-                       #undef MSG_INFO_NOTIF
+                       print(
+                               Local_Notification_sprintf(
+                                       notif.nent_string,
+                                       notif.nent_args, 
+                                       s1, s2, s3, s4,
+                                       f1, f2, f3, f4)
+                       );
+                       #ifdef CSQC 
+                       if(notif.nent_icon != "")
+                       {
+                               Local_Notification_HUD_Notify_Push(
+                                       notif.nent_icon,
+                                       notif.nent_hudargs,
+                                       s1, s2, s3, s4);
+                       } 
+                       #endif 
                        break;
                }
                        break;
                }
+               
                #ifdef CSQC
                case MSG_CENTER:
                {
                #ifdef CSQC
                case MSG_CENTER:
                {
-                       #define MSG_CENTER_NOTIF(name,strnum,flnum,args,cpid,durcnt,normal,gentle) \
-                               case name: { CHECK_AUTOCVAR(name) \
-                               { \
-                                       centerprint_generic(HANDLE_CPID(cpid), sprintf(CCR(normal_or_gentle(normal, gentle)), args), durcnt); \
-                               } return; }
-
-                       NOTIF_SWITCH_LIST(MSG_CENTER, net_name, return)
-                       
-                       #undef MSG_CENTER_NOTIF
+                       Local_Notification_centerprint_generic(
+                               Local_Notification_sprintf(
+                                       notif.nent_string,
+                                       notif.nent_args, 
+                                       s1, s2, s3, s4,
+                                       f1, f2, f3, f4),
+                               notif.nent_durcnt,
+                               notif.nent_cpid,
+                               f1, f2);
                        break;
                }
                #endif
                        break;
                }
                #endif
+               
                case MSG_WEAPON:
                case MSG_WEAPON:
-               {
-                       #define MSG_WEAPON_NOTIF(name,infoname,centername) \
-                               case name: { CHECK_AUTOCVAR(name) \
-                               { \
-                                       #if infoname != NO_MSG \
-                                               Local_Notification_Without_VarArgs(MSG_INFO, infoname, \
-                                                       stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), \
-                                                       stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), \
-                                                       s1, s2, s3, s4, f1, f2, f3, f4); \
-                                       #endif \
-                                       #ifdef CSQC \
-                                               #if centername != NO_MSG \
-                                                       Local_Notification_Without_VarArgs(MSG_CENTER, centername, \
-                                                               stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername)), \
-                                                               stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)), \
-                                                               s1, s2, s3, s4, f1, f2, f3, f4); \
-                                               #endif \
-                                       #endif \
-                               } return; }
-
-                       NOTIF_SWITCH_LIST(MSG_WEAPON, net_name, return)
-                       
-                       #undef MSG_WEAPON_NOTIF
-                       break;
-               }
                case MSG_DEATH:
                {
                case MSG_DEATH:
                {
-                       #define MSG_DEATH_NOTIF(name,infoname,centername) \
-                               case name: { CHECK_AUTOCVAR(name) \
-                               { \
-                                       #if infoname != NO_MSG \
-                                               Local_Notification_Without_VarArgs(MSG_INFO, infoname, \
-                                                       stof(Get_Field_Value(F_STRNUM, MSG_INFO, infoname)), \
-                                                       stof(Get_Field_Value(F_FLNUM, MSG_INFO, infoname)), \
-                                                       s1, s2, s3, s4, f1, f2, f3, f4); \
-                                       #endif \
-                                       #ifdef CSQC \
-                                               #if centername != NO_MSG \
-                                                       Local_Notification_Without_VarArgs(MSG_CENTER, centername, \
-                                                               stof(Get_Field_Value(F_STRNUM, MSG_CENTER, centername)), \
-                                                               stof(Get_Field_Value(F_FLNUM, MSG_CENTER, centername)), \
-                                                               s1, s2, s3, s4, f1, f2, f3, f4); \
-                                               #endif \
-                                       #endif \
-                               } return; } 
-
-                       NOTIF_SWITCH_LIST(MSG_DEATH, net_name, return)
-                       
-                       #undef MSG_DEATH_NOTIF
+                       if(notif.nent_msginfo)
+                       if(notif.nent_msginfo.nent_enabled)
+                       {
+                               Local_Notification_WOVA(
+                                       MSG_INFO,
+                                       notif.nent_msginfo.nent_id, 
+                                       notif.nent_msginfo.nent_stringcount, 
+                                       notif.nent_msginfo.nent_floatcount, 
+                                       s1, s2, s3, s4,
+                                       f1, f2, f3, f4);
+                       }
+                       #ifdef CSQC
+                       if(notif.nent_msgcenter)
+                       if(notif.nent_msgcenter.nent_enabled)
+                       {
+                               Local_Notification_WOVA(
+                                       MSG_CENTER,
+                                       notif.nent_msgcenter.nent_id, 
+                                       notif.nent_msgcenter.nent_stringcount, 
+                                       notif.nent_msgcenter.nent_floatcount, 
+                                       s1, s2, s3, s4,
+                                       f1, f2, f3, f4); 
+                       }
+                       #endif
                        break;
                }
        }
 }
 
                        break;
                }
        }
 }
 
-void Local_Notification_Without_VarArgs(float net_type, float net_name,
+// WOVA = Without Variable Arguments 
+void Local_Notification_WOVA(float net_type, float net_name,
        float stringcount, float floatcount,
        string s1, string s2, string s3, string s4,
        float f1, float f2, float f3, float f4)
 {
        float stringcount, float floatcount,
        string s1, string s2, string s3, string s4,
        float f1, float f2, float f3, float f4)
 {
-       #define VARITEM(stringc,floatc,args) if((stringcount == stringc) && (floatcount == floatc)) { Local_Notification(net_type, net_name, args); return; }
+       #define VARITEM(stringc,floatc,args) \
+               if((stringcount == stringc) && (floatcount == floatc)) \
+                       { Local_Notification(net_type, net_name, args); return; }
        EIGHT_VARS_TO_VARARGS_VARLIST
        #undef VARITEM
        EIGHT_VARS_TO_VARARGS_VARLIST
        #undef VARITEM
-
        Local_Notification(net_type, net_name); // some notifications don't have any arguments at all
 }
 
        Local_Notification(net_type, net_name); // some notifications don't have any arguments at all
 }
 
@@ -403,46 +966,169 @@ void Read_Notification(float is_new)
        float net_type = ReadByte();
        float net_name = ReadShort();
 
        float net_type = ReadByte();
        float net_name = ReadShort();
 
-       float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
-       float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
+       entity notif;
+
+       if(net_type == MSG_CENTER_KILL)
+       {
+               if(is_new)
+               {
+                       if(net_name == 0) { reset_centerprint_messages(); }
+                       else
+                       {
+                               notif = Get_Notif_Ent(MSG_CENTER, net_name);
+                               if not(notif) { backtrace("Read_Notification: Could not find notification entity!\n"); return; }
+                               centerprint_generic(notif.nent_cpid, "", 0, 0);
+                       }
+               }
+       }
+       else
+       {
+               notif = Get_Notif_Ent(net_type, net_name);
+               if not(notif) { backtrace("Read_Notification: Could not find notification entity!\n"); return; }
 
 
-       string s1 = ((stringcount >= 1) ? ReadString() : NO_STR_ARG);
-       string s2 = ((stringcount >= 2) ? ReadString() : NO_STR_ARG);
-       string s3 = ((stringcount >= 3) ? ReadString() : NO_STR_ARG);
-       string s4 = ((stringcount == 4) ? ReadString() : NO_STR_ARG);
-       float f1 = ((floatcount >= 1) ? ReadLong() : NO_FL_ARG);
-       float f2 = ((floatcount >= 2) ? ReadLong() : NO_FL_ARG);
-       float f3 = ((floatcount >= 3) ? ReadLong() : NO_FL_ARG);
-       float f4 = ((floatcount == 4) ? ReadLong() : NO_FL_ARG);
+               #ifdef NOTIFICATIONS_DEBUG
+               dprint(sprintf(
+                       "Read_Notification(%d) at %f: net_type = %s, net_name = %s\n",
+                       is_new,
+                       time,
+                       Get_Notif_TypeName(net_type),
+                       notif.nent_name
+               ));
+               #endif
 
 
-       #ifdef NOTIFICATIONS_DEBUG
-               dprint(sprintf("Read_Notification(%d) at %f: net_name = %s.\n", is_new, time, Get_Field_Value(F_NAME, net_type, net_name)));
-       #endif
+               string s1 = ((0 < notif.nent_stringcount) ? ReadString() : "");
+               string s2 = ((1 < notif.nent_stringcount) ? ReadString() : "");
+               string s3 = ((2 < notif.nent_stringcount) ? ReadString() : "");
+               string s4 = ((3 < notif.nent_stringcount) ? ReadString() : "");
+               float f1 = ((0 < notif.nent_floatcount) ? ReadLong() : 0);
+               float f2 = ((1 < notif.nent_floatcount) ? ReadLong() : 0);
+               float f3 = ((2 < notif.nent_floatcount) ? ReadLong() : 0);
+               float f4 = ((3 < notif.nent_floatcount) ? ReadLong() : 0);
        
        
-       if(is_new) { Local_Notification_Without_VarArgs(net_type, net_name, stringcount, floatcount, s1, s2, s3, s4, f1, f2, f3, f4); }
+               if(is_new)
+               {
+                       Local_Notification_WOVA(
+                               net_type, net_name,
+                               notif.nent_stringcount,
+                               notif.nent_floatcount,
+                               s1, s2, s3, s4,
+                               f1, f2, f3, f4);
+               }
+       }
 }
 #endif
 
 #ifdef SVQC
 }
 #endif
 
 #ifdef SVQC
-void Notification_Remove()
+void Net_Notification_Remove()
 {
 {
+       #ifdef NOTIFICATIONS_DEBUG
+       if not(self) { dprint(sprintf("Net_Notification_Remove() at %f: Missing self!?\n", time)); return; }
+       if(self.nent_net_name == -1)
+       {
+               dprint(sprintf(
+                       "Net_Notification_Remove() at %f: Killed '%s' notification\n",
+                       time,
+                       Get_Notif_TypeName(self.nent_net_type)
+               ));
+       }
+       else
+       #endif
+       {
+               string checkargs = Notification_CheckArgs_TypeName(self.nent_net_type, self.nent_net_name);
+               if(checkargs != "") { dprint(sprintf("Incorrect usage of Net_Notification_Remove() at %f: %s\n", time, checkargs)); return; }
+
+               #ifdef NOTIFICATIONS_DEBUG
+               entity realent = Get_Notif_Ent(self.nent_net_type, self.nent_net_name);
+               dprint(sprintf(
+                       "Net_Notification_Remove() at %f: Removed '%s - %s' notification\n",
+                       time,
+                       Get_Notif_TypeName(self.nent_net_type), 
+                       realent.nent_name
+               ));
+               #endif
+       }
+       
        float i;
        for(i = 0; i < 4; ++i) { if(self.nent_strings[i]) { strunzone(self.nent_strings[i]); } }
        remove(self);
 }
 
        float i;
        for(i = 0; i < 4; ++i) { if(self.nent_strings[i]) { strunzone(self.nent_strings[i]); } }
        remove(self);
 }
 
-float Write_Notification(entity client, float sf)
+float Net_Write_Notification(entity client, float sf)
 {
        float i, send = FALSE;
        
        switch(self.nent_broadcast)
        {
 {
        float i, send = FALSE;
        
        switch(self.nent_broadcast)
        {
-               case NOTIF_ONE: { if((client == self.nent_client) || (client.classname == STR_SPECTATOR && client.enemy == self.nent_client)) { send = TRUE; } break; }
-               case NOTIF_ONE_ONLY: { if(client == self.nent_client) { send = TRUE; } break; }
-               case NOTIF_TEAM: { if((client.team == self.nent_client.team) || (client.classname == STR_SPECTATOR && client.enemy.team == self.nent_client.team)) { send = TRUE; } break; }
-               case NOTIF_TEAM_EXCEPT: { if(((client != self.nent_client) && (client.team == self.nent_client.team) && !(client.classname == STR_SPECTATOR && client.enemy == self.nent_client))) { send = TRUE; } break; }
-               case NOTIF_ANY: { send = TRUE; break; }
-               case NOTIF_ANY_EXCEPT: { if((client != self.nent_client) && !(client.classname == STR_SPECTATOR && client.enemy == self.nent_client)) { send = TRUE; } break; }
+               case NOTIF_ONE: // send to one client and their spectator
+               {
+                       if(
+                               (client == self.nent_client)
+                               ||
+                               (
+                                       (client.classname == STR_SPECTATOR)
+                                       &&
+                                       (client.enemy == self.nent_client)
+                               )
+                       ) { send = TRUE; }
+                       break;
+               }
+               case NOTIF_ONE_ONLY: // send ONLY to one client
+               {
+                       if(client == self.nent_client) { send = TRUE; }
+                       break;
+               }
+               case NOTIF_TEAM: // send only to X team and their spectators
+               {
+                       if(
+                               (client.team == self.nent_client.team)
+                               ||
+                               (
+                                       (client.classname == STR_SPECTATOR)
+                                       &&
+                                       (client.enemy.team == self.nent_client.team)
+                               )
+                       ) { send = TRUE; }
+                       break;
+               }
+               case NOTIF_TEAM_EXCEPT: // send only to X team and their spectators, except for Y person and their spectators
+               {
+                       if(
+                               (client != self.nent_client)
+                               &&
+                               (
+                                       (client.team == self.nent_client.team)
+                                       ||
+                                       (
+                                               (client.classname == STR_SPECTATOR)
+                                               &&
+                                               (
+                                                       (client.enemy != self.nent_client)
+                                                       &&
+                                                       (client.enemy.team == self.nent_client.team)
+                                               )
+                                       )
+                               )
+                       ) { send = TRUE; }
+                       break;
+               }
+               case NOTIF_ANY: // send to everyone
+               {
+                       send = TRUE;
+                       break;
+               }
+               case NOTIF_ANY_EXCEPT: // send to everyone except X person and their spectators
+               {
+                       if(
+                               (client != self.nent_client)
+                               &&
+                               !(
+                                       (client.classname == STR_SPECTATOR)
+                                       &&
+                                       (client.enemy == self.nent_client)
+                               )
+                       ) { send = TRUE; }
+                       break;
+               }
                default: { send = FALSE; break; }
        }
 
                default: { send = FALSE; break; }
        }
 
@@ -458,122 +1144,175 @@ float Write_Notification(entity client, float sf)
        return send; 
 }
 
        return send; 
 }
 
-void Send_Notification(float broadcast, entity client,
-       float net_type, float net_name, ...count)
+void Kill_Notification(float broadcast, entity client, float net_type, float net_name)
 {
 {
-       // check supplied broadcast, target, type, and name for errors
+       string checkargs = Notification_CheckArgs(broadcast, client, 1, 1);
+       if(checkargs != "") { backtrace(sprintf("Incorrect usage of Kill_Notification: %s\n", checkargs)); return; }
+
        #ifdef NOTIFICATIONS_DEBUG
        #ifdef NOTIFICATIONS_DEBUG
+       dprint(sprintf(
+               "Kill_Notification(%d, '%s', %d, %d);\n",
+               broadcast,
+               client.netname,
+               net_type,
+               net_name
+       ));
+       #endif
+
+       entity notif, net_notif;
+
+       // if no name is provided, just kill ALL the centerprint notifications
+       if(net_type == MSG_CENTER)
        {
        {
-               #define CHECKARG_TYPENAME(type) case MSG_##type##: \
-                       { if(!net_name || (net_name > NOTIF_##type##_COUNT)) \
-                       { checkargs = sprintf("Improper name: %d!", net_name); } break; }
-                       
-               string checkargs = "";
-               switch(net_type)
-               {
-                       CHECKARG_TYPENAME(INFO)
-                       CHECKARG_TYPENAME(CENTER)
-                       CHECKARG_TYPENAME(WEAPON)
-                       CHECKARG_TYPENAME(DEATH)
-                       
-                       default: { checkargs = sprintf("Improper type: %d!", checkargs, net_type); break; }
-               }
-               #undef CHECKARG_TYPENAME
-               
-               if(checkargs != "") { checkargs = strcat(checkargs, " "); }
-               switch(broadcast)
+               net_notif = spawn();
+               net_notif.classname = "net_kill_notification";
+               net_notif.nent_broadcast = broadcast;
+               net_notif.nent_client = client;
+               net_notif.nent_net_type = MSG_CENTER_KILL;
+               net_notif.nent_net_name = net_name;
+               Net_LinkEntity(net_notif, FALSE, autocvar_notification_lifetime_runtime, Net_Write_Notification);
+       }
+
+       for(notif = world; (notif = find(notif, classname, "net_notification"));)
+       {
+               // now kill the old send notification entity
+               if(net_type)
                {
                {
-                       case NOTIF_ONE:
-                       case NOTIF_ONE_ONLY: { if(clienttype(client) == CLIENTTYPE_NOTACLIENT) { checkargs = sprintf("%sNo client provided!", checkargs); } break; }
-                       case NOTIF_ANY_EXCEPT: { if(clienttype(client) == CLIENTTYPE_NOTACLIENT) { checkargs = sprintf("%sException can't be a non-client!", checkargs); } break; }
-                       case NOTIF_ANY: { if(client) { checkargs = sprintf("%sEntity provided when world was required!", checkargs); } break; }
-                       
-                       case NOTIF_TEAM:
-                       case NOTIF_TEAM_EXCEPT:
+                       if(notif.nent_net_type == net_type)
                        {
                        {
-                               if not(teamplay) { checkargs = sprintf("%sTeamplay not active!", checkargs); }
-                               else if(clienttype(client) == CLIENTTYPE_NOTACLIENT)
+                               if(net_name)
                                {
                                {
-                                       if(broadcast == NOTIF_TEAM) { checkargs = sprintf("%sNo client provided!", checkargs); }
-                                       else { checkargs = sprintf("%sException can't be a non-client!", checkargs); }
+                                       if(notif.nent_net_name == net_name) { notif.nent_net_name = -1; notif.think(); }
+                                       else { continue; } // we ARE looking for a certain net_name, don't kill everything else too
                                }
                                }
-                               break;
+                               else { notif.nent_net_name = -1; notif.think(); }
                        }
                        }
-                       
-                       default: { checkargs = sprintf("%sImproper broadcast: %d!", checkargs, broadcast); break; }
+                       else { continue; } // we ARE looking for a certain net_type, don't kill everything else too
                }
                }
-               
-               if(checkargs != "") { backtrace(sprintf("Incorrect usage of Send_Notification: %s\n", checkargs)); return; }
+               else { notif.nent_net_name = -1; notif.think(); }
        }
        }
-       #endif
+}
 
 
-       // retreive counts for the arguments of this notification
-       float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
-       float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
+void Send_Notification(float broadcast, entity client,
+       float net_type, float net_name, ...count)
+{
+       // check supplied broadcast, target, type, and name for errors
+       string checkargs = Notification_CheckArgs(broadcast, client, net_type, net_name);
+       if(checkargs != "") { backtrace(sprintf("Incorrect usage of Send_Notification: %s\n", checkargs)); return; }
 
 
-       entity e = Get_Notif_Ent(net_type, net_name);
-       print(sprintf("stringcount from ent: %d... floatcount from ent: %d\n", e.nent_stringcount, e.nent_floatcount));
+       // retreive counts for the arguments of this notification
+       entity notif = Get_Notif_Ent(net_type, net_name);
+       if not(notif) { backtrace("Send_Notification: Could not find notification entity!\n"); return; }
 
 
-       #ifdef NOTIFICATIONS_DEBUG
+       if((notif.nent_stringcount + notif.nent_floatcount) > count)
        {
        {
-               dprint(sprintf("Send_Notification(%d, %d, %s, stringcount: %d, floatcount: %d, varargs: %d);\n",
-                       broadcast, net_type, Get_Field_Value(F_NAME, net_type, net_name), stringcount, floatcount, count));
-
-               if((stringcount + floatcount) > count)
-                       { backtrace(sprintf(strcat("Not enough arguments for Send_Notification! stringcount(%d) + floatcount(%d) > count(%d)\n", 
-                       "Check the notification definition and function call for accuracy...?\n"), stringcount, floatcount, count)); return; }
-               else if((stringcount + floatcount) < count)
-                       { backtrace(sprintf(strcat("Too many arguments for Send_Notification! stringcount(%d) + floatcount(%d) < count(%d)\n",
-                       "Check the notification definition and function call for accuracy...?\n"), stringcount, floatcount, count)); return; }
+               backtrace(sprintf(
+                       strcat(
+                               "Not enough arguments for Send_Notification(%d, %s, %s, ...)! ",
+                               "stringcount(%d) + floatcount(%d) > count(%d)\n", 
+                               "Check the definition and function call for accuracy...?\n"
+                       ),
+                       broadcast, Get_Notif_TypeName(net_type), notif.nent_name,
+                       notif.nent_stringcount, notif.nent_floatcount, count
+               ));
+               return;
+       }
+       else if((notif.nent_stringcount + notif.nent_floatcount) < count)
+       {
+               backtrace(sprintf(
+                       strcat(
+                               "Too many arguments for Send_Notification(%d, %s, %s, ...)! ",
+                               "stringcount(%d) + floatcount(%d) < count(%d)\n",
+                               "Check the definition and function call for accuracy...?\n"
+                       ),
+                       broadcast, Get_Notif_TypeName(net_type), notif.nent_name,
+                       notif.nent_stringcount, notif.nent_floatcount, count
+               ));
+               return;
        }
        }
+
+       #ifdef NOTIFICATIONS_DEBUG
+       string s1 = ((0 < notif.nent_stringcount) ? ...(0, string) : "");
+       string s2 = ((1 < notif.nent_stringcount) ? ...(1, string) : "");
+       string s3 = ((2 < notif.nent_stringcount) ? ...(2, string) : "");
+       string s4 = ((3 < notif.nent_stringcount) ? ...(3, string) : "");
+       float f1 = ((0 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 0), float) : 0);
+       float f2 = ((1 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 1), float) : 0);
+       float f3 = ((2 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 2), float) : 0);
+       float f4 = ((3 < notif.nent_floatcount) ? ...((notif.nent_stringcount + 3), float) : 0);
+       dprint(sprintf(
+               "Send_Notification(%d, %s, %s, %s, %s);\n",
+               broadcast,
+               Get_Notif_TypeName(net_type),
+               notif.nent_name,
+               strreplace("\n", "\\n", sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4)),
+               sprintf("%d, %d, %d, %d", f1, f2, f3, f4)
+       ));
        #endif
 
        #endif
 
-       entity notif = spawn();
-       notif.nent_broadcast = broadcast;
-       notif.nent_client = client;
-       notif.nent_net_type = net_type;
-       notif.nent_net_name = net_name;
-       notif.nent_stringcount = stringcount;
-       notif.nent_floatcount = floatcount;
+       entity net_notif = spawn();
+       net_notif.classname = "net_notification";
+       net_notif.nent_broadcast = broadcast;
+       net_notif.nent_client = client;
+       net_notif.nent_net_type = net_type;
+       net_notif.nent_net_name = net_name;
+       net_notif.nent_stringcount = notif.nent_stringcount;
+       net_notif.nent_floatcount = notif.nent_floatcount;
        
        float i;
        
        float i;
-       
-       for(i = 0; i < stringcount; ++i) { notif.nent_strings[i] = strzone(...(i, string)); }
-       for(i = 0; i < floatcount; ++i) { notif.nent_floats[i] = ...((stringcount + i), float); }
-       
-       notif.think = Notification_Remove;
-       notif.nextthink = (time + 0.5); 
+       for(i = 0; i < net_notif.nent_stringcount; ++i) { net_notif.nent_strings[i] = strzone(...(i, string)); }
+       for(i = 0; i < net_notif.nent_floatcount; ++i) { net_notif.nent_floats[i] = ...((net_notif.nent_stringcount + i), float); }
 
 
-       Net_LinkEntity(notif, FALSE, 0, Write_Notification);
+       net_notif.think = Net_Notification_Remove;
+       net_notif.nextthink =
+               ((time > autocvar_notification_lifetime_mapload)
+               ?
+                       (time + autocvar_notification_lifetime_runtime)
+                       :
+                       autocvar_notification_lifetime_mapload
+               ); 
 
 
-       if((!server_is_local) && (broadcast == NOTIF_ANY || broadcast == NOTIF_ANY_EXCEPT) && (net_type != MSG_CENTER))
-               { Local_Notification_Without_VarArgs(net_type, net_name, stringcount, floatcount,
-                       IFSTR(0), IFSTR(1), IFSTR(2), IFSTR(3), IFFL(0), IFFL(1), IFFL(2), IFFL(3)); }
+       Net_LinkEntity(net_notif, FALSE, 0, Net_Write_Notification);
+
+       if(server_is_dedicated && (broadcast == NOTIF_ANY || broadcast == NOTIF_ANY_EXCEPT) && (net_type != MSG_CENTER))
+       {
+               Local_Notification_WOVA(
+                       net_type, net_name,
+                       notif.nent_stringcount,
+                       notif.nent_floatcount,
+                       IFSTR(0), IFSTR(1), IFSTR(2), IFSTR(3),
+                       IFFL(0), IFFL(1), IFFL(2), IFFL(3));
+       }
 }
 
 }
 
-void Send_Notification_Without_VarArgs(float broadcast, entity client,
+// WOVA = Without Variable Arguments 
+void Send_Notification_WOVA(float broadcast, entity client,
        float net_type, float net_name,
        float net_type, float net_name,
-       float stringcount, float floatcount,
        string s1, string s2, string s3, string s4,
        float f1, float f2, float f3, float f4)
        string s1, string s2, string s3, string s4,
        float f1, float f2, float f3, float f4)
-{              
-       #define VARITEM(stringc,floatc,args) if((stringcount == stringc) && (floatcount == floatc)) { Send_Notification(broadcast, client, net_type, net_name, args); return; }
+{
+       entity notif = Get_Notif_Ent(net_type, net_name);
+       
+       #ifdef NOTIFICATIONS_DEBUG
+       dprint(sprintf(
+               "Send_Notification_WOVA(%d, %s, %s, %s, %s - %d %d);\n",
+               broadcast,
+               Get_Notif_TypeName(net_type),
+               notif.nent_name,
+               sprintf("'%s^7', '%s^7', '%s^7', '%s^7'", s1, s2, s3, s4),
+               sprintf("%d, %d, %d, %d", f1, f2, f3, f4),
+               notif.nent_stringcount, notif.nent_floatcount
+       ));
+       #endif
+       
+       #define VARITEM(stringc,floatc,args) \
+               if((notif.nent_stringcount == stringc) && (notif.nent_floatcount == floatc)) \
+                       { Send_Notification(broadcast, client, net_type, net_name, args); return; }
        EIGHT_VARS_TO_VARARGS_VARLIST
        #undef VARITEM
        EIGHT_VARS_TO_VARARGS_VARLIST
        #undef VARITEM
-
        Send_Notification(broadcast, client, net_type, net_name); // some notifications don't have any arguments at all
 }
 
        Send_Notification(broadcast, client, net_type, net_name); // some notifications don't have any arguments at all
 }
 
-void Send_Notification_Legacy_Wrapper(float broadcast, entity client,
-       float net_type, float net_name,
-       string s1, string s2,
-       float f1, float f2, float f3)
-{
-       float stringcount = stof(Get_Field_Value(F_STRNUM, net_type, net_name));
-       float floatcount = stof(Get_Field_Value(F_FLNUM, net_type, net_name));
-       Send_Notification_Without_VarArgs(broadcast, client, net_type, net_name, stringcount, floatcount, s1, s2, NO_STR_ARG, NO_STR_ARG, f1, f2, f3, NO_FL_ARG);
-}
-
 
 // =============================
 //  LEGACY NOTIFICATION SYSTEMS
 
 // =============================
 //  LEGACY NOTIFICATION SYSTEMS
@@ -597,9 +1336,4 @@ void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration,
                });
        }
 }
                });
        }
 }
-void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
-{
-       Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
-}
 #endif // ifdef SVQC
 #endif // ifdef SVQC
-#endif // ifndef MENUQC