]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
MASSIVE update to how sprees and frag messages are handled (much better!)
authorSamual Lenks <samual@xonotic.org>
Sat, 23 Feb 2013 19:53:47 +0000 (14:53 -0500)
committerSamual Lenks <samual@xonotic.org>
Sat, 23 Feb 2013 19:53:47 +0000 (14:53 -0500)
qcsrc/common/notifications.qc
qcsrc/common/notifications.qh
qcsrc/server/g_damage.qc

index d0bf7bb053a6fbc29a869a2b0cfec2c19ed1a074..e9c0e8ebc6b9d3a6508b410fd56c164bf6433147 100644 (file)
@@ -105,6 +105,8 @@ void Dump_Notifications(float fh, float alsoprint)
        NOTIF_WRITE("\n// HARD CODED notification variables:\n");
        NOTIF_WRITE("seta notification_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)\"\n");
        NOTIF_WRITE("seta notification_show_sprees 1 \"Print information about sprees in death/kill messages\"\n");
+       NOTIF_WRITE("seta notification_show_sprees_info_newline 1 \"Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself\"\n");
+       NOTIF_WRITE("seta notification_show_sprees_info_specialonly 1 \"Don't show attacker spree information if it isn't an achievement\"\n");
        NOTIF_WRITE("seta notification_version_mismatch_client_error 0 \"Cause a notif error on client if the version in notifications.cfg mismatches the code\"\n");
        NOTIF_WRITE("seta notification_version_mismatch_server_error 1 \"Cause a notif error on server if the version in notifications.cfg mismatches the code\"\n");
        NOTIF_WRITE("seta notification_errors_are_fatal 1 \"If a notification fails upon initialization, cause a Host_Error to stop the program\"\n");
index e2d55ebef71d5ed2a6d5d16929bc362a9d55ea9e..658faea37d95264d1d25f68bbb5fff4ff5a62b7f 100644 (file)
@@ -166,7 +166,6 @@ void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration,
        MULTITEAM_INFO(1, INFO_CTF_CAPTURE_BROKEN_, 2,                  2, 2, "s1 f1p2dec s2 f2p2dec", "s1",    "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG%s^BG's previous record of ^F2%s^BG seconds\n"), "") \
        MULTITEAM_INFO(1, INFO_CTF_CAPTURE_UNBROKEN_, 2,                2, 2, "s1 f1p2dec s2 f2p2dec", "s1",    "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break ^BG%s^BG's previous record of ^F1%s^BG seconds\n"), "") \
        MULTITEAM_INFO(1, INFO_DEATH_TEAMKILL_, 4,                              2, 1, "s1 s2 spree_end", "s2 s1",               "notify_teamkill_%s",   _("^BG%s^K1 was betrayed by ^BG%s^K1%s\n"), "") \
-       MSG_INFO_NOTIF(1, INFO_DEATH_FIRSTBLOOD,                                2, 0, "s2", "",                                                 "",                                             _("^BG%s^K1 drew first blood\n"), _("^F1%s^K1 got the first score\n")) \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_CUSTOM,                               2, 1, "s1 s2 spree_end", "s1",                  "notify_void",                  _("^BG%s^K1 %s^K1%s\n"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_GENERIC,                              1, 1, "s1 spree_end", "s1",                             "notify_selfkill",              _("^BG%s^K1 died%s\n"), "") \
        MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VOID,                                 1, 1, "s1 spree_end", "s1",                             "notify_void",                  _("^BG%s^K1 was in the wrong place%s\n"), "") \
@@ -384,10 +383,10 @@ void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration,
        MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAGGED_VERBOSE,                        1, 3, "s1 frag_stats",                          NO_CPID, XPD(0, 0), _("^K1You were fragged by ^BG%s^BG%s"), _("^K1You were scored against by ^BG%s^BG%s")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE,                       1, 2, "spree_cen s1 frag_ping",         NO_CPID, XPD(0, 0), _("^K1%sYou typefragged ^BG%s^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing^BG%s")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE,            1, 3, "s1 frag_stats",                          NO_CPID, XPD(0, 0), _("^K1You were typefragged by ^BG%s^BG%s"), _("^K1You were scored against by ^BG%s^K1 while typing^BG%s")) \
-       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE,                     1, 1, "s1",                                                     NO_CPID, XPD(0, 0), _("^K3First blood! You fragged ^BG%s"), _("^K3First score! You scored against ^BG%s")) \
-       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE,          1, 3, "s1",                                                     NO_CPID, XPD(0, 0), _("^K1First victim! You were fragged by ^BG%s"), _("^K1First casualty! You were scored against by ^BG%s")) \
-       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE,         1, 1, "s1",                                                     NO_CPID, XPD(0, 0), _("^K1First blood! You typefragged ^BG%s"), _("^K1First score! You scored against ^BG%s^K1 while they were typing")) \
-       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE,      1, 3, "s1",                                                     NO_CPID, XPD(0, 0), _("^K1First victim! You were typefragged by ^BG%s"), _("^K1First casualty! You were scored against by ^BG%s^K1 while typing!")) \
+       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE,                     1, 1, "s1 frag_ping",                           NO_CPID, XPD(0, 0), _("^K3First blood! You fragged ^BG%s^BG%s"), _("^K3First score! You scored against ^BG%s^BG%s")) \
+       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE,          1, 3, "s1 frag_stats",                          NO_CPID, XPD(0, 0), _("^K1First victim! You were fragged by ^BG%s^BG%s"), _("^K1First casualty! You were scored against by ^BG%s^BG%s")) \
+       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE,         1, 1, "s1 frag_ping",                           NO_CPID, XPD(0, 0), _("^K1First blood! You typefragged ^BG%s^BG%s"), _("^K1First score! You scored against ^BG%s^K1 while they were typing^BG%s")) \
+       MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE,      1, 3, "s1 frag_stats",                          NO_CPID, XPD(0, 0), _("^K1First victim! You were typefragged by ^BG%s^BG%s"), _("^K1First casualty! You were scored against by ^BG%s^K1 while typing!^BG%s")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAG,                                         1, 0, "s1",                                                     NO_CPID, XPD(0, 0), _("^K1Moron! You fragged ^BG%s^K1, a team mate!"), _("^K1Moron! You went against ^BG%s^K1, a team mate!")) \
        MSG_CENTER_NOTIF(1, CENTER_DEATH_TEAMKILL_FRAGGED,                                      1, 0, "s1",                                                     NO_CPID, XPD(0, 0), _("^K1You were fragged by ^BG%s^K1, a team mate"), _("^K1You were scored against by ^BG%s^K1, a team mate")) \
        MSG_CENTER_NOTIF(1, CENTER_DISCONNECT_IDLING,                           0, 1, "",                                       CPID_IDLING,                    XPD(0, f1), _("^K1Stop idling!\n^BGDisconnecting in ^COUNT..."), "") \
@@ -527,25 +526,33 @@ void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration,
        MSG_DEATH_NOTIF(1, DEATH_MURDER_VH_RAPT_FRAGMENT,               INFO_DEATH_MURDER_VH_RAPT_FRAGMENT,             NO_MSG) \
        MSG_DEATH_NOTIF(1, DEATH_MURDER_VH_RAPT_DEATH,                  INFO_DEATH_MURDER_VH_RAPT_DEATH,                NO_MSG) \
        MSG_DEATH_NOTIF(1, DEATH_MURDER_VH_BUMB_GUN,                    INFO_DEATH_MURDER_VH_BUMB_GUN,                  NO_MSG) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_VH_BUMB_DEATH,                  INFO_DEATH_MURDER_VH_BUMB_DEATH,                NO_MSG) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAG,                                                   NO_MSG,                                                 CENTER_DEATH_MURDER_FRAG) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAGGED,                                                NO_MSG,                                                 CENTER_DEATH_MURDER_FRAGGED) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAG,                                               NO_MSG,                                                 CENTER_DEATH_MURDER_TYPEFRAG) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAGGED,                                    NO_MSG,                                                 CENTER_DEATH_MURDER_TYPEFRAGGED) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAG_FIRST,                                             INFO_DEATH_FIRSTBLOOD,                  CENTER_DEATH_MURDER_FRAG_FIRST) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAGGED_FIRST,                                  NO_MSG,                                                 CENTER_DEATH_MURDER_FRAGGED_FIRST) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAG_FIRST,                                 INFO_DEATH_FIRSTBLOOD,                  CENTER_DEATH_MURDER_TYPEFRAG_FIRST) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAGGED_FIRST,                              NO_MSG,                                                 CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAG_VERBOSE,                                   NO_MSG,                                                 CENTER_DEATH_MURDER_FRAG_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAGGED_VERBOSE,                                NO_MSG,                                                 CENTER_DEATH_MURDER_FRAGGED_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAG_VERBOSE,                               NO_MSG,                                                 CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAGGED_VERBOSE,                    NO_MSG,                                                 CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAG_FIRST_VERBOSE,                             INFO_DEATH_FIRSTBLOOD,                  CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_FRAGGED_FIRST_VERBOSE,                  NO_MSG,                                                 CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE,                 INFO_DEATH_FIRSTBLOOD,                  CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE,              NO_MSG,                                                 CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE) \
-       MSG_DEATH_NOTIF(1, DEATH_TEAMKILL_FRAG,                                                 NO_MSG,                                                 CENTER_DEATH_TEAMKILL_FRAG) \
-       MSG_DEATH_NOTIF(1, DEATH_TEAMKILL_FRAGGED,                                              NO_MSG,                                                 CENTER_DEATH_TEAMKILL_FRAGGED)
+       MSG_DEATH_NOTIF(1, DEATH_MURDER_VH_BUMB_DEATH,                  INFO_DEATH_MURDER_VH_BUMB_DEATH,                NO_MSG) 
+
+
+// ===========================
+//  Special CVAR Declarations
+// ===========================
+
+// MAKE SURE THIS IS ALWAYS SYNCHRONIZED WITH THE DUMP
+// NOTIFICATIONS FUNCTION IN THE .QC FILE!
+
+#define NOTIF_ADD_AUTOCVAR(name,default) var float autocvar_notification_##name = default;
+
+var float autocvar_notification_version = NOTIF_VERSION;
+var float autocvar_notification_show_sprees = TRUE;
+var float autocvar_notification_show_sprees_info_newline = TRUE;
+var float autocvar_notification_show_sprees_info_specialonly = TRUE;
+var float autocvar_notification_errors_are_fatal = TRUE;
+
+#ifdef SVQC
+.float FRAG_VERBOSE;
+void Notification_GetCvars(void);
+var float autocvar_notification_version_mismatch_server_error = TRUE;
+#else
+var float autocvar_notification_allow_chatboxprint = TRUE;
+var float autocvar_notification_frag_verbose = TRUE;
+var float autocvar_notification_version_mismatch_client_error = FALSE;
+#endif
 
 
 // ============================
@@ -598,6 +605,65 @@ string arg_slot[NOTIF_MAX_ARGS];
 
 #define IS_SPREE_NUM(n) ((n == 3) || (n == 5) || (n == 10) || (n == 15) || (n == 20) || (n == 25) || (n == 30))
 
+#define KILL_SPREE_LIST \
+       SPREE_ITEM(3, 03, _("%s^K1 made a TRIPLE FRAG! %s^BG"), _("%s^K1 made a TRIPLE SCORE! %s^BG")) \
+       SPREE_ITEM(5, 05, _("%s^K1 unlocked RAGE! %s^BG"), _("%s^K1 made FIVE SCORES IN A ROW! %s^BG")) \
+       SPREE_ITEM(10, 10, _("%s^K1 started a MASSACRE! %s^BG"), _("%s^K1 made TEN SCORES IN A ROW! %s^BG")) \
+       SPREE_ITEM(15, 15, _("%s^K1 executed MAYHEM! %s^BG"), _("%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG")) \
+       SPREE_ITEM(20, 20, _("%s^K1 is a BERSERKER! %s^BG"), _("%s^K1 made TWENTY SCORES IN A ROW! %s^BG")) \
+       SPREE_ITEM(25, 25, _("%s^K1 inflicts CARNAGE! %s^BG"), _("%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG")) \
+       SPREE_ITEM(30, 30, _("%s^K1 unleashes ARMAGEDDON! %s^BG"), _("%s^K1 made THIRTY SCORES IN A ROW! %s^BG"))
+       
+string notif_arg_spree_inf(string player, float spree)
+{
+       #define SPREE_NEWLINE (autocvar_notification_show_sprees_info_newline ? "\n" : "")
+       
+       if(spree > 1)
+       {
+               #define SPREE_ITEM(counta,countb,normal,gentle) \
+                       case counta: { return sprintf(CCR(normal_or_gentle(normal, gentle)), player, SPREE_NEWLINE); }
+               
+               switch(spree)
+               {
+                       KILL_SPREE_LIST
+                       default:
+                       {
+                               if not(autocvar_notification_show_sprees_info_specialonly)
+                               {
+                                       return
+                                               sprintf(
+                                                       CCR(normal_or_gentle(
+                                                               _("%s^K1 has %d frags in a row! %s^BG"),
+                                                               _("%s^K1 made %d scores in a row! %s^BG")
+                                                       )),
+                                                       player,
+                                                       spree,
+                                                       SPREE_NEWLINE
+                                               );
+                               }
+                               else { return ""; } // don't show spree information if it isn't an achievement 
+                       }
+               }
+
+               #undef SPREE_ITEM
+       }
+       else if(spree == -1)
+       {
+               return
+                       sprintf(
+                               CCR(normal_or_gentle(
+                                       _("%s^K1 drew first blood! %s^BG"),
+                                       _("%s^K1 got the first score! %s^BG")
+                               )),
+                               player,
+                               SPREE_NEWLINE
+                       );
+       }
+
+       #undef SPREE_NEWLINE
+       return "";
+}
+
 #define NOTIF_ARGUMENT_LIST \
        ARG_CASE(ARG_TRIPLE, "s1",                              s1) \
        ARG_CASE(ARG_TRIPLE, "s2",                              s2) \
@@ -614,41 +680,17 @@ string arg_slot[NOTIF_MAX_ARGS];
        ARG_CASE(ARG_CSQC, "frag_stats",                sprintf(CCR(_("\n(Health ^1%d^BG / Armor ^2%d^BG)%s")), f1, f2, ((f3 != NO_MSG) ? sprintf(CCR(_(" (Ping ^2%d^BG)")), f3) : ""))) \
        /*ARG_CASE(ARG_CSQC, "frag_pos",                ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))*/ \
        ARG_CASE(ARG_CSQC, "spree_cen",                 ((autocvar_notification_show_sprees && IS_SPREE_NUM(f1)) ? sprintf(normal_or_gentle(_("%d frag spree! "), _("%d score spree! ")), f1) : "")) \
-       ARG_CASE(ARG_CSQC, "spree_inf",                 ((autocvar_notification_show_sprees && IS_SPREE_NUM(f2)) ? sprintf(CCR(normal_or_gentle(_("%s^K1 is on a %d frag spree!\n^BG"), _("%s^K1 is on a %d score spree!\n^BG"))), s2, f2) : "")) \
+       ARG_CASE(ARG_CSQC, "spree_inf",                 (autocvar_notification_show_sprees ? notif_arg_spree_inf(s2, f2) : "")) \
        ARG_CASE(ARG_CSQC, "spree_end",                 ((autocvar_notification_show_sprees && (f1 >= 3)) ? sprintf(normal_or_gentle(_(", ending their %d frag spree"), _(", ending their %d score spree")), f1) : "")) \
        ARG_CASE(ARG_CSQC, "spree_lost",                ((autocvar_notification_show_sprees && (f1 >= 3)) ? sprintf(normal_or_gentle(_(", losing their %d frag spree"), _(", losing their %d score spree")), f1) : "")) \
        ARG_CASE(ARG_CSQC, "death_team",                Team_ColoredFullName(f1 - 1)) \
        ARG_CASE(ARG_CSQC, "weapon_name",               ftos(f1)) \
-       ARG_CASE(ARG_SVQC, "spree_inf",                 ((autocvar_notification_show_sprees && IS_SPREE_NUM(f2)) ? sprintf(CCR(normal_or_gentle(_("%s^K1 is on a %d frag spree!\n^BG"), _("%s^K1 is on a %d score spree!\n^BG"))), s2, f2) : "")) \
+       ARG_CASE(ARG_SVQC, "spree_inf",                 (autocvar_notification_show_sprees ? notif_arg_spree_inf(s2, f2) : "")) \
        ARG_CASE(ARG_SVQC, "spree_end",                 ((autocvar_notification_show_sprees && (f1 >= 3)) ? sprintf(normal_or_gentle(_(", ending their %d frag spree"), _(", ending their %d score spree")), f1) : "")) \
        ARG_CASE(ARG_SVQC, "spree_lost",                ((autocvar_notification_show_sprees && (f1 >= 3)) ? sprintf(normal_or_gentle(_(", losing their %d frag spree"), _(", losing their %d score spree")), f1) : "")) \
        ARG_CASE(ARG_SVQC, "death_team",                Team_ColoredFullName(f1)) \
        ARG_CASE(ARG_SVQC, "weapon_name",               ftos(f1))
-
-
-// ===========================
-//  Special CVAR Declarations
-// ===========================
-
-// MAKE SURE THIS IS ALWAYS SYNCHRONIZED WITH THE DUMP
-// NOTIFICATIONS FUNCTION IN THE .QC FILE!
-
-#define NOTIF_ADD_AUTOCVAR(name,default) var float autocvar_notification_##name = default;
-
-var float autocvar_notification_version = NOTIF_VERSION;
-var float autocvar_notification_show_sprees = TRUE;
-var float autocvar_notification_errors_are_fatal = TRUE;
-
-#ifdef SVQC
-.float FRAG_VERBOSE;
-void Notification_GetCvars(void);
-var float autocvar_notification_version_mismatch_server_error = TRUE;
-#else
-var float autocvar_notification_allow_chatboxprint = TRUE;
-var float autocvar_notification_frag_verbose = TRUE;
-var float autocvar_notification_version_mismatch_client_error = FALSE;
-#endif
-
+       
 
 // ====================================
 //  Initialization/Create Declarations
index ad2b99044615ca491b5ed6673395560818fbfbb7..9923ef2d03f4897ff87c3c766f552f9c12ecd656 100644 (file)
@@ -436,8 +436,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
 
                        attacker.killcount = 0;
                        
-                       Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_TEAMKILL_FRAG, s2);
-                       Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_TEAMKILL_FRAGGED, s1);
+                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, s2);
+                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, s1);
                        Send_Notification(NOTIF_ANY, world, MSG_INFO, APP_TEAM_NUM_4(targ.team, INFO_DEATH_TEAMKILL_), s2, s1, targ.killcount);
 
                        // In this case, the death message will ALWAYS be "foo was betrayed by bar"
@@ -450,26 +450,20 @@ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
 
                        attacker.taunt_soundtime = time + 1;
                        attacker.killcount = attacker.killcount + 1;
-                       
-                       #define ADD_ACHIEVEMENT_CASE(numa,numb) \
-                               case numa: \
+
+                       #define SPREE_ITEM(counta,countb,normal,gentle) \
+                               case counta: \
                                { \
-                                       AnnounceTo(attacker, strcat(#numb, "kills")); \
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##numa, 1); \
+                                       AnnounceTo(attacker, strcat(#countb, "kills")); \
+                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
                                        break; \
                                }
                        switch(attacker.killcount)
                        {
-                               ADD_ACHIEVEMENT_CASE(3, 03)
-                               ADD_ACHIEVEMENT_CASE(5, 05)
-                               ADD_ACHIEVEMENT_CASE(10, 10)
-                               ADD_ACHIEVEMENT_CASE(15, 15)
-                               ADD_ACHIEVEMENT_CASE(20, 20)
-                               ADD_ACHIEVEMENT_CASE(25, 25)
-                               ADD_ACHIEVEMENT_CASE(30, 30)
+                               KILL_SPREE_LIST
                                default: break;
                        }
-                       #undef ADD_ACHIEVEMENT_CASE
+                       #undef SPREE_ITEM
 
                        if(!checkrules_firstblood)
                        {
@@ -484,59 +478,62 @@ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
                                if(targ.istypefrag)
                                {
                                        if(attacker.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE, s2, s1, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE, targ.netname, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_TYPEFRAG_FIRST, s2, s1);
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG_FIRST, targ.netname);
 
                                        if(targ.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE, s1, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE, attacker.netname, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_TYPEFRAGGED_FIRST, s1);
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED_FIRST, attacker.netname);
                                }
                                else
                                {
                                        if(attacker.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_FRAG_FIRST_VERBOSE, s2, s1, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG_FIRST_VERBOSE, targ.netname, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_FRAG_FIRST, s2, s1);
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG_FIRST, targ.netname);
 
                                        if(targ.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_FRAGGED_FIRST_VERBOSE, s1, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED_FIRST_VERBOSE, attacker.netname, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_FRAGGED_FIRST, s1);
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED_FIRST, attacker.netname);
                                }
+
+                               // -1 means firstblood
+                               if not(Obituary_WeaponDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, -1, -1))
+                                       Obituary_SpecialDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, -1, -1, 0);
                        }
                        else // normal frags, kill sprees listed
                        {
                                if(targ.istypefrag)
                                {
                                        if(attacker.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_TYPEFRAG_VERBOSE, s2, attacker.killcount, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, targ.netname, attacker.killcount, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_TYPEFRAG, s2, attacker.killcount);
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG, targ.netname, attacker.killcount);
 
                                        if(targ.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_TYPEFRAGGED_VERBOSE, s1, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, attacker.netname, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_TYPEFRAGGED, s1);
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED, attacker.netname);
                                }
                                else
                                {
                                        if(attacker.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_FRAG_VERBOSE, s2, attacker.killcount, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG_VERBOSE, targ.netname, attacker.killcount, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, attacker, MSG_DEATH, DEATH_MURDER_FRAG, s2, attacker.killcount);
+                                               Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG, targ.netname, attacker.killcount);
 
                                        if(targ.FRAG_VERBOSE)
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_FRAGGED_VERBOSE, s1, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED_VERBOSE, attacker.netname, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
                                        else
-                                               Send_Notification(NOTIF_ONE, targ, MSG_DEATH, DEATH_MURDER_FRAGGED, s1);
+                                               Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED, attacker.netname);
                                }
-                       }
 
-                       //print("targ_killcount = ", ftos(targ.killcount), ", attacker_killcount = ", ftos(attacker.killcount), ".\n");
-                       if not(Obituary_WeaponDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, targ.killcount, attacker.killcount))
-                               Obituary_SpecialDeath(targ, TRUE, deathtype, s2, s1, targ.killcount, attacker.killcount, 0);
+                               if not(Obituary_WeaponDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, targ.killcount, attacker.killcount))
+                                       Obituary_SpecialDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, targ.killcount, attacker.killcount, 0);
+                       }
                }
        }