X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fg_damage.qc;h=70e037bcb5d958ab926c7a5a49e827b7656b5e12;hb=63a6745a882b05be961cae415c674552cd439973;hp=b2a0e99e3bff92990614ca2d77c22699961317c9;hpb=97a2c79ffa43cd7183acdd28dc87efa16fe41dfb;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index b2a0e99e3..70e037bcb 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -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,287 @@ 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) +void Obituary_SpecialDeath(entity notif_target, float murder, float deathtype, string s1, string s2, float f1, float f2, float f3) { - /*if(deathtype) + float handled, hits; + 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(notif_target, MSG_ONE, MSG_DEATH, msg_death, s1, s2, f1, f2, f3); \ + Send_Notification_ToAll(notif_target, TRUE, MSG_INFO, INFO_##msg_death, s1, s2, f1, f2, f3); \ + ++handled; \ + } \ + #endif \ + #if msg_death_by != NO_MSG \ + if(murder) \ + { \ + Send_Notification(notif_target, MSG_ONE, MSG_DEATH, msg_death_by, s1, s2, f1, f2, f3); \ + Send_Notification_ToAll(notif_target, TRUE, 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; +void Obituary_WeaponDeath(float murder, float deathtype, string s1, string s2) { - string s, a, msg; - float w, type; - - string s1, s2, s3; + float death_weapon = DEATH_WEAPONOF(deathtype); - 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) : ""); - - // no "killed your own dumb self" message in CTS - if(!g_cts) { Obituary_Notification(targ, s1, "", "", deathtype); } - - if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET) - { - LogDeath("suicide", deathtype, targ, targ); - GiveFrags(attacker, targ, -1, deathtype); - } - - 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); } - - Obituary_Notification(world, s1, s2, "", deathtype); - //Send_KillNotification(s, s2, ftos(w), deathtype, MSG_SUICIDE); - } - else if (attacker.classname == "player") - { - if(!IsDifferentTeam(attacker, targ)) - { - //type = ((attacker.team == COLOR_TEAM1) ? KILL_TEAM_FRAG_RED : KILL_TEAM_FRAG_BLUE); + if(death_message) { Send_Notification(world, MSG_ALL, 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)); } + } +} - GiveFrags(attacker, targ, -1, deathtype); +.float FRAG_VERBOSE; - //Send_CSQC_KillCenterprint(attacker, s, "", type); +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; } - if (targ.killcount > 2) - msg = ftos(targ.killcount); - else - msg = ""; + // Declarations + string s, a, msg; + float w, type; - if (attacker.killcount > 2) { - msg = ftos(attacker.killcount); - type = KILL_TEAM_SPREE; - } - Send_KillNotification(a, s, msg, type, MSG_KILL); + 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; - attacker.killcount = 0; + //dprint(sprintf("Obituary(): Deathtype = %s (%d), Attacker = %s, Inflictor = %s, Target = %s...\n", Deathtype_Name(deathtype), deathtype, attacker.netname, inflictor.netname, targ.netname)); - LogDeath("tk", deathtype, attacker, targ); + // ======= + // SUICIDE + // ======= + if(targ == attacker) + { + if(DEATH_ISSPECIAL(deathtype)) + { + if(deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) + { + 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(DEATH_WEAPONOF(deathtype)) + { + Obituary_WeaponDeath(FALSE, deathtype, targ.netname, NO_STR_ARG); + } + else + { + 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(attacker, MSG_ONE, MSG_DEATH, DEATH_TEAMKILL_FRAG, s2, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG); + Send_Notification(targ, MSG_ONE, MSG_DEATH, DEATH_TEAMKILL_FRAGGED, s1, NO_STR_ARG, NO_FL_ARG, NO_FL_ARG, NO_FL_ARG); + Send_Notification(world, MSG_ALL, 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(attacker, MSG_ONE, 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(targ, MSG_ONE, 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(attacker, MSG_ONE, 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(targ, MSG_ONE, 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(attacker, MSG_ONE, 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(targ, MSG_ONE, 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); - } - else if (attacker.killcount > 2) { - Send_KillNotification(a, ftos(attacker.killcount), "", KILL_SPREE, MSG_SPREE); + Send_Notification(attacker, MSG_ONE, 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(targ, MSG_ONE, 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)); } - LogDeath("frag", deathtype, attacker, targ); } + + if(DEATH_WEAPONOF(deathtype)) { Obituary_WeaponDeath(TRUE, deathtype, targ.netname, attacker.netname); } + else { 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 +633,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 +916,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