]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_damage.qc
Merge remote-tracking branch 'origin/master' into samual/notification_rewrite
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_damage.qc
index b2a0e99e3bff92990614ca2d77c22699961317c9..428c6fe0ee8864bbbdfd1f0a5a6e3b07712a0406 100644 (file)
@@ -227,7 +227,7 @@ void GiveFrags (entity attacker, entity targ, float f, float deathtype)
                UpdateFrags(attacker, f);
 }
 
-string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information
+/*string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information
 {
        string health_output = string_null;
        string ping_output = string_null;
@@ -263,7 +263,7 @@ string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information
        }
        
        return output;
-}
+}*/
 
 string AppendItemcodes(string s, entity player)
 {
@@ -297,7 +297,7 @@ void LogDeath(string mode, float deathtype, entity killer, entity killed)
        s = strcat(":kill:", mode);
        s = strcat(s, ":", ftos(killer.playerid));
        s = strcat(s, ":", ftos(killed.playerid));
-       s = strcat(s, ":type=", ftos(deathtype));
+       s = strcat(s, ":type=", Deathtype_Name(deathtype));
        s = strcat(s, ":items=");
        s = AppendItemcodes(s, killer);
        if(killed != killer)
@@ -308,201 +308,286 @@ void LogDeath(string mode, float deathtype, entity killer, entity killed)
        GameLogEcho(s);
 }
 
-void Obituary_Notification(entity notif_target, string s1, string s2, string s3, float deathtype)
+#define INFO_NO_MSG 0
+
+void Obituary_SpecialDeath(entity notif_target, float murder, float deathtype, string s1, string s2, float f1, float f2, float f3)
 {
-       /*if(deathtype)
+       float handled = 0, hits = 0;
+       if(DEATH_ISSPECIAL(deathtype))
        {
-               #define DEATHTYPE(name,type,notification,first,last) \
-                       { if((deathtype == max(0, name)) && max(0, type) && max(0, notification)) { Send_Notification(type, notif_target, notification, s1, s2, s3); return; } }
+               #define DEATHTYPE(name,msg_death,msg_death_by,position) \
+                       { if(deathtype == max(0, name)) \
+                       { \
+                               #if msg_death != NO_MSG \
+                                       if not(murder) \
+                                       { \
+                                               Send_Notification_Legacy_Wrapper(NOTIF_ONE, notif_target, MSG_DEATH, msg_death, s1, s2, f1, f2, f3); \
+                                               Send_Notification_Legacy_Wrapper(NOTIF_ANY_EXCEPT, notif_target, MSG_INFO, INFO_##msg_death, s1, s2, f1, f2, f3); \
+                                               ++handled; \
+                                       } \
+                               #endif \
+                               #if msg_death_by != NO_MSG \
+                                       if(murder) \
+                                       { \
+                                               Send_Notification_Legacy_Wrapper(NOTIF_ONE, notif_target, MSG_DEATH, msg_death_by, s1, s2, f1, f2, f3); \
+                                               Send_Notification_Legacy_Wrapper(NOTIF_ANY_EXCEPT, notif_target, MSG_INFO, INFO_##msg_death_by, s1, s2, f1, f2, f3); \
+                                               ++handled; \
+                                       } \
+                               #endif \
+                               ++hits; \
+                       } }
 
                DEATHTYPES
-               backtrace("Unhandled deathtype. Please notify Samual!\n");
-       }*/
+               #undef DEATHTYPE
+               
+               if not(hits)
+               {
+                       backtrace("Obituary_SpecialDeath(): Unhandled deathtype- Please notify Samual!\n");
+               }
+               if not(handled)
+               {
+                       dprint(sprintf("Obituary_SpecialDeath(): ^1Deathtype ^7(%s-%d)^1 has no notification!\n", Deathtype_Name(deathtype), deathtype));
+                       return;
+               }
+       }
 }
 
-void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
+float w_deathtype;
+float Obituary_WeaponDeath(float murder, float deathtype, string s1, string s2)
 {
-       string  s, a, msg;
-       float w, type;
+       float death_weapon = DEATH_WEAPONOF(deathtype);
 
-       string s1, s2, s3;
-
-       if (targ.classname == "player")
+       if(death_weapon)
        {
-               s = targ.netname;
-               a = attacker.netname;
+               w_deathtype = deathtype;
+               float death_message = weapon_action(death_weapon, ((murder) ? WR_KILLMESSAGE : WR_SUICIDEMESSAGE));
+               w_deathtype = FALSE;
 
-               if (targ == attacker) // suicides
-               {
-                       s1 = ((deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) ? ColoredTeamName(targ.team) : "");
+               if(death_message) { Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_WEAPON, death_message, s1, s2, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG); }
+               else { dprint(sprintf("Obituary_WeaponDeath(): ^1Deathtype ^7(%s-%d)^1 has no notification for weapon %d!\n", Deathtype_Name(deathtype), deathtype, death_weapon)); }
 
-                       // no "killed your own dumb self" message in CTS
-            if(!g_cts) { Obituary_Notification(targ, s1, "", "", deathtype); }
+               return TRUE;
+       }
+       return FALSE;
+}
 
-                       if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET)
-                       {
-                               LogDeath("suicide", deathtype, targ, targ);
-                               GiveFrags(attacker, targ, -1, deathtype);
-                       }
+.float FRAG_VERBOSE;
+void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
+{
+       // Sanity check
+       if not(targ.classname == STR_PLAYER) { backtrace("Obituary called on non-player?!\n"); return; }
 
-                       s1 = targ.netname;
-                       s2 = ((targ.killcount > 2) ? ftos(targ.killcount) : "");
-                               
-                       //if(teamplay && deathtype == DEATH_MIRRORDAMAGE)
-                       //      { deathtype = ((attacker.team == COLOR_TEAM1) ? KILL_TEAM_SUICIDE_RED : KILL_TEAM_SUICIDE_BLUE); }
+       // Declarations
+       string s1 = NO_STR_ARG, s2 = NO_STR_ARG;
+       float f1 = NO_FL_ARG, f2 = NO_FL_ARG, f3 = NO_FL_ARG;
+       float notif_firstblood = FALSE;
 
-                       Obituary_Notification(world, s1, s2, "", deathtype);
-                       //Send_KillNotification(s, s2, ftos(w), deathtype, MSG_SUICIDE);
-               }
-               else if (attacker.classname == "player")
+       //dprint(sprintf("Obituary(): Deathtype = %s (%d), Attacker = %s, Inflictor = %s, Target = %s...\n", Deathtype_Name(deathtype), deathtype, attacker.netname, inflictor.netname, targ.netname));
+
+       // =======
+       // SUICIDE
+       // =======
+       if(targ == attacker)
+       {
+               if(DEATH_ISSPECIAL(deathtype))
                {
-                       if(!IsDifferentTeam(attacker, targ))
+                       if(deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
                        {
-                               //type = ((attacker.team == COLOR_TEAM1) ? KILL_TEAM_FRAG_RED : KILL_TEAM_FRAG_BLUE);
-
-                               GiveFrags(attacker, targ, -1, deathtype);
-
-                               //Send_CSQC_KillCenterprint(attacker, s, "", type);
-
-                               if (targ.killcount > 2)
-                                       msg = ftos(targ.killcount);
-                               else
-                                       msg = "";
-
-                               if (attacker.killcount > 2) {
-                                       msg = ftos(attacker.killcount);
-                                       type = KILL_TEAM_SPREE;
-                               }
-                               Send_KillNotification(a, s, msg, type, MSG_KILL);
-
-                               attacker.killcount = 0;
-
-                               LogDeath("tk", deathtype, attacker, targ);
+                               s1 = targ.netname;
+                               f1 = targ.team;
                        }
                        else
                        {
-                               if (!checkrules_firstblood)
+                               switch(deathtype)
                                {
-                                       checkrules_firstblood = TRUE;
-                                       Send_KillNotification(a, "", "", KILL_FIRST_BLOOD, MSG_KILL);
-                                       // TODO: make these print a newline if they dont
-                                       Send_CSQC_KillCenterprint(attacker, "", "", KILL_FIRST_BLOOD, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, "", "", KILL_FIRST_VICTIM, MSG_KILL);
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
-                                       PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
-                               }
-
-                               if(targ.istypefrag) {
-                                       Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_TYPEFRAG, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_TYPEFRAGGED, MSG_KILL);
-                               } else {
-                                       Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_FRAG, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_FRAGGED, MSG_KILL);
+                                       case DEATH_MIRRORDAMAGE:
+                                       {
+                                               s1 = targ.netname;
+                                               f1 = targ.killcount;
+                                               break;
+                                       }
+                                       
+                                       default:
+                                       {
+                                               s1 = targ.netname;
+                                               f1 = targ.killcount;
+                                               s2 = NO_STR_ARG;
+                                               f2 = f3 = NO_FL_ARG;
+                                               break;
+                                       }
                                }
+                               LogDeath("suicide", deathtype, targ, targ);
+                               GiveFrags(attacker, targ, -1, deathtype);
+                       }
+                       
+                       Obituary_SpecialDeath(targ, FALSE, deathtype, s1, s2, f1, f2, NO_FL_ARG);
+               }
+               else if not(Obituary_WeaponDeath(FALSE, deathtype, targ.netname, NO_STR_ARG))
+               {
+                       backtrace("SUICIDE: what the hell happened here?\n");
+               }
+       }
 
-                               attacker.taunt_soundtime = time + 1;
-
-                               if (deathtype == DEATH_HURTTRIGGER && inflictor.message2 != "")
-                                       msg = inflictor.message2;
-                               else if (deathtype == DEATH_CUSTOM)
-                                       msg = deathmessage;
-                               else
-                                       msg = "";
+       // ======
+       // MURDER
+       // ======
+       else if(attacker.classname == "player")
+       {
+               s1 = attacker.netname;
+               s2 = targ.netname;
 
-                               if(strstrofs(msg, "%", 0) < 0)
-                                       msg = strcat("%s ", msg, " by %s");
+               // TODO: ADD REAL CHECK HERE!
+               attacker.FRAG_VERBOSE = TRUE;
+               targ.FRAG_VERBOSE = TRUE;
+               
+               if(!IsDifferentTeam(attacker, targ))
+               {
+                       LogDeath("tk", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, -1, deathtype);
 
-                               Send_KillNotification(a, s, msg, deathtype, MSG_KILL);
+                       attacker.killcount = 0;
+                       
+                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, attacker, MSG_DEATH, DEATH_TEAMKILL_FRAG, s2, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
+                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, targ, MSG_DEATH, DEATH_TEAMKILL_FRAGGED, s1, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG);
+                       Send_Notification_Legacy_Wrapper(NOTIF_ANY, world, MSG_INFO, APP_TEAM_NUM_4(targ.team, INFO_DEATH_TEAMKILL_), s2, s1, targ.killcount, NO_FL_ARG, NO_FL_ARG);
 
-                               GiveFrags(attacker, targ, 1, deathtype);
+                       // In this case, the death message will ALWAYS be "foo was betrayed by bar"
+                       // No need for specific death/weapon messages...
+               }
+               else
+               {
+                       LogDeath("frag", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, 1, deathtype);
 
-                               if (targ.killcount > 2) {
-                                       Send_KillNotification(s, ftos(targ.killcount), a, KILL_END_SPREE, MSG_SPREE);
+                       attacker.taunt_soundtime = time + 1;
+                       attacker.killcount = attacker.killcount + 1;
+                       
+                       #define ADD_ACHIEVEMENT_CASE(numa,numb) \
+                               case numa: \
+                               { \
+                                       AnnounceTo(attacker, strcat(#numb, "kills")); \
+                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##numa, 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)
+                               default: break;
+                       }
+                       #undef ADD_ACHIEVEMENT_CASE
 
-                               attacker.killcount = attacker.killcount + 1;
+                       if(!checkrules_firstblood)
+                       {
+                               checkrules_firstblood = TRUE;
+                               notif_firstblood = TRUE; // modify the current messages so that they too show firstblood information
+                               PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
+                               PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
+                       }
 
-                               if (attacker.killcount == 3)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_3, MSG_SPREE);
-                                       AnnounceTo(attacker, "03kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3, 1);
-                               }
-                               else if (attacker.killcount == 5)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_5, MSG_SPREE);
-                                       AnnounceTo(attacker, "05kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5, 1);
-                               }
-                               else if (attacker.killcount == 10)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_10, MSG_SPREE);
-                                       AnnounceTo(attacker, "10kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10, 1);
-                               }
-                               else if (attacker.killcount == 15)
+                       if(notif_firstblood) // first blood, no kill sprees yet
+                       {
+                               if(targ.istypefrag)
                                {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_15, MSG_SPREE);
-                                       AnnounceTo(attacker, "15kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15, 1);
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, attacker, MSG_DEATH, (attacker.FRAG_VERBOSE ? DEATH_MURDER_TYPEFRAG_FIRST_VERBOSE : DEATH_MURDER_TYPEFRAG_FIRST),
+                                               s2, s1, (attacker.FRAG_VERBOSE ? ((clienttype(targ) == CLIENTTYPE_BOT) ? BOT_PING : targ.ping) : NO_FL_ARG), NO_FL_ARG, NO_FL_ARG);
+                                               
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, targ, MSG_DEATH, (targ.FRAG_VERBOSE ? DEATH_MURDER_TYPEFRAGGED_FIRST_VERBOSE : DEATH_MURDER_TYPEFRAGGED_FIRST),
+                                               s1, NO_STR_ARG, (targ.FRAG_VERBOSE ? attacker.health : NO_FL_ARG), (targ.FRAG_VERBOSE ? attacker.armorvalue : NO_FL_ARG), (targ.FRAG_VERBOSE ? ((clienttype(attacker) == CLIENTTYPE_BOT) ? BOT_PING : attacker.ping) : NO_FL_ARG));
                                }
-                               else if (attacker.killcount == 20)
+                               else
                                {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_20, MSG_SPREE);
-                                       AnnounceTo(attacker, "20kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20, 1);
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, attacker, MSG_DEATH, (attacker.FRAG_VERBOSE ? DEATH_MURDER_FRAG_FIRST_VERBOSE : DEATH_MURDER_FRAG_FIRST),
+                                               s2, s1, (attacker.FRAG_VERBOSE ? ((clienttype(targ) == CLIENTTYPE_BOT) ? BOT_PING : targ.ping) : NO_FL_ARG), NO_FL_ARG, NO_FL_ARG);
+                                               
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, targ, MSG_DEATH, (targ.FRAG_VERBOSE ? DEATH_MURDER_FRAGGED_FIRST_VERBOSE : DEATH_MURDER_FRAGGED_FIRST),
+                                               s1, NO_STR_ARG, (targ.FRAG_VERBOSE ? attacker.health : NO_FL_ARG), (targ.FRAG_VERBOSE ? attacker.armorvalue : NO_FL_ARG), (targ.FRAG_VERBOSE ? ((clienttype(attacker) == CLIENTTYPE_BOT) ? BOT_PING : attacker.ping) : NO_FL_ARG));
                                }
-                               else if (attacker.killcount == 25)
+                       }
+                       else // normal frags, kill sprees listed
+                       {
+                               if(targ.istypefrag)
                                {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_25, MSG_SPREE);
-                                       AnnounceTo(attacker, "25kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25, 1);
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, attacker, MSG_DEATH, (attacker.FRAG_VERBOSE ? DEATH_MURDER_TYPEFRAG_VERBOSE : DEATH_MURDER_TYPEFRAG),
+                                               s2, NO_STR_ARG, attacker.killcount, (attacker.FRAG_VERBOSE ? ((clienttype(targ) == CLIENTTYPE_BOT) ? BOT_PING : targ.ping) : NO_FL_ARG), NO_FL_ARG);
+                                               
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, targ, MSG_DEATH, (targ.FRAG_VERBOSE ? DEATH_MURDER_TYPEFRAGGED_VERBOSE : DEATH_MURDER_TYPEFRAGGED),
+                                               s1, NO_STR_ARG, (targ.FRAG_VERBOSE ? attacker.health : NO_FL_ARG), (targ.FRAG_VERBOSE ? attacker.armorvalue : NO_FL_ARG), (targ.FRAG_VERBOSE ? ((clienttype(attacker) == CLIENTTYPE_BOT) ? BOT_PING : attacker.ping) : NO_FL_ARG));
                                }
-                               else if (attacker.killcount == 30)
+                               else
                                {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_30, MSG_SPREE);
-                                       AnnounceTo(attacker, "30kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30, 1);
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, attacker, MSG_DEATH, (attacker.FRAG_VERBOSE ? DEATH_MURDER_FRAG_VERBOSE : DEATH_MURDER_FRAG),
+                                               s2, NO_STR_ARG, attacker.killcount, (attacker.FRAG_VERBOSE ? ((clienttype(targ) == CLIENTTYPE_BOT) ? BOT_PING : targ.ping) : NO_FL_ARG), NO_FL_ARG);
+                                               
+                                       Send_Notification_Legacy_Wrapper(NOTIF_ONE, targ, MSG_DEATH, (targ.FRAG_VERBOSE ? DEATH_MURDER_FRAGGED_VERBOSE : DEATH_MURDER_FRAGGED),
+                                               s1, NO_STR_ARG, (targ.FRAG_VERBOSE ? attacker.health : NO_FL_ARG), (targ.FRAG_VERBOSE ? attacker.armorvalue : NO_FL_ARG), (targ.FRAG_VERBOSE ? ((clienttype(attacker) == CLIENTTYPE_BOT) ? BOT_PING : attacker.ping) : NO_FL_ARG));
                                }
-                               else if (attacker.killcount > 2) {
-                                       Send_KillNotification(a, ftos(attacker.killcount), "", KILL_SPREE, MSG_SPREE);
-                               }
-                               LogDeath("frag", deathtype, attacker, targ);
                        }
+                       
+                       if not(Obituary_WeaponDeath(TRUE, deathtype, targ.netname, attacker.netname))
+                               Obituary_SpecialDeath(targ, TRUE, deathtype, s2, s1, targ.killcount, NO_FL_ARG, NO_FL_ARG);
                }
-               else
+       }
+
+       // =============
+       // ACCIDENT/TRAP
+       // =============
+       else
+       {
+               switch(deathtype)
                {
-                       Send_CSQC_KillCenterprint(targ, "", "", deathtype, MSG_KILL_ACTION);
-                       if (deathtype == DEATH_HURTTRIGGER && inflictor.message != "")
-                               msg = inflictor.message;
-                       else if (deathtype == DEATH_CUSTOM)
-                               msg = deathmessage;
-                       else
-                               msg = "";
-                       if(strstrofs(msg, "%", 0) < 0)
-                               msg = strcat("%s ", msg);
-
-                       GiveFrags(targ, targ, -1, deathtype);
-                       if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) {
-                               AnnounceTo(targ, "botlike");
-                               PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+                       // For now, we're just forcing HURTTRIGGER to behave as "DEATH_VOID" and giving it no special options...
+                       // Later on you will only be able to make custom messages using DEATH_CUSTOM,
+                       // and there will be a REAL DEATH_VOID implementation which mappers will use.
+                       /*case DEATH_HURTTRIGGER:
+                       {
+                               s1 = targ.netname;
+                               s2 = inflictor.message;
+                               if(strstrofs(s2, "%", 0) < 0) { s2 = strcat("%s ", s2); }
+                               break;
+                       }*/
+
+                       case DEATH_CUSTOM:
+                       {
+                               s1 = targ.netname;
+                               s2 = deathmessage;
+                               f1 = targ.killcount;
+                               if(strstrofs(s2, "%", 0) < 0) { s2 = strcat("%s ", s2); }
+                               f2 = f3 = NO_FL_ARG;
+                               break;
+                       }
+                       
+                       default:
+                       {
+                               s1 = targ.netname;
+                               f1 = targ.killcount;
+                               s2 = NO_STR_ARG;
+                               f2 = f3 = NO_FL_ARG;
+                               break;
                        }
-                       Send_KillNotification(s, msg, "", deathtype, MSG_KILL_ACTION);
+               }
 
-                       if (targ.killcount > 2)
-                               Send_KillNotification(s, ftos(targ.killcount), "", 0, MSG_KILL_ACTION_SPREE);
+               LogDeath("accident", deathtype, targ, targ);
+               GiveFrags(targ, targ, -1, deathtype);
 
-                       LogDeath("accident", deathtype, targ, targ);
+               if(PlayerScore_Add(targ, SP_SCORE, 0) == -5)
+               {
+                       AnnounceTo(targ, "botlike");
+                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
                }
 
-               targ.death_origin = targ.origin;
-               if(targ != attacker)
-                       targ.killer_origin = attacker.origin;
-
-               // FIXME: this should go in PutClientInServer
-               if (targ.killcount)
-                       targ.killcount = 0;
+               Obituary_SpecialDeath(targ, FALSE, deathtype, s1, s2, f1, f2, f3);
        }
+
+       // Set final information for the death
+       targ.death_origin = targ.origin;
+       if(targ != attacker) { targ.killer_origin = attacker.origin; }
+       if(targ.killcount) { targ.killcount = 0; }
 }
 
 // these are updated by each Damage call for use in button triggering and such
@@ -547,7 +632,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float
                        }
        }
 
-       if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE || deathtype == DEATH_QUIET)
+       if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
        {
                // These are ALWAYS lethal
                // No damage modification here
@@ -830,8 +915,6 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float
                                                        if(deathtype & HITTYPE_HEADSHOT)
                                                                headshot = 1;
                                                }
-                                               if(g_ca)
-                                                       PlayerScore_Add(attacker, SP_SCORE, damage * autocvar_g_ca_damage2score_multiplier);
                                        }
                                }
                                else