X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fg_damage.qc;h=38a9d5a468f9ef35dab5ebe4ded42e91a7c4e5cf;hb=fb1dd3c24d6b306d07262e6e4b1171b3b30b1c5e;hp=1340137723fa7c1b75781d2565db5744ce934664;hpb=56e60e1840a6b020edfcd6bbf2c8d8ae97297fa0;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index 134013772..38a9d5a46 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -216,44 +216,6 @@ void GiveFrags (entity attacker, entity targ, float f, float deathtype) UpdateFrags(attacker, f); } -string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information -{ - string health_output = string_null; - string ping_output = string_null; - string handicap_output = string_null; - string output = string_null; - - if(autocvar_sv_fraginfo && ((autocvar_sv_fraginfo == 2) || inWarmupStage)) - { - // health/armor of attacker (person who killed you) - if(autocvar_sv_fraginfo_stats && (player.health >= 1)) - health_output = strcat("^7(Health ^1", ftos(rint(player.health)), "^7 / Armor ^2", ftos(rint(player.armorvalue)), "^7)"); - - // ping display - if(autocvar_sv_fraginfo_ping) - ping_output = ((clienttype(player) == CLIENTTYPE_BOT) ? "^2Bot" : strcat("Ping ", ((player.ping >= 150) ? "^1" : "^2"), ftos(rint(player.ping)), "ms")); - - // handicap display - if(autocvar_sv_fraginfo_handicap) - { - if(autocvar_sv_fraginfo_handicap == 2) - handicap_output = strcat(output, strcat("Handicap ^2", ((player.cvar_cl_handicap <= 1) ? "Off" : ftos(rint(player.cvar_cl_handicap))))); - else if(player.cvar_cl_handicap) // with _handicap 1, only show this if there actually is a handicap enabled. - handicap_output = strcat("Handicap ^2", ftos(rint(player.cvar_cl_handicap))); - } - - // format the string - output = strcat(health_output, (health_output ? ((ping_output || handicap_output) ? " ^7(" : "") : ((ping_output || handicap_output) ? "^7(" : "")), - ping_output, (handicap_output ? "^7 / " : ""), - handicap_output, ((ping_output || handicap_output) ? "^7)" : "")); - - // add new line to the beginning if there is a message - if(output) { output = strcat("\n", output); } - } - - return output; -} - string AppendItemcodes(string s, entity player) { float w; @@ -286,7 +248,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) @@ -297,225 +259,272 @@ void LogDeath(string mode, float deathtype, entity killer, entity killed) GameLogEcho(s); } -void Send_KillNotification (string s1, string s2, string s3, float msg, float type) -{ - WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); - WriteByte(MSG_BROADCAST, TE_CSQC_KILLNOTIFY); - WriteString(MSG_BROADCAST, s1); - WriteString(MSG_BROADCAST, s2); - WriteString(MSG_BROADCAST, s3); - WriteShort(MSG_BROADCAST, msg); - WriteByte(MSG_BROADCAST, type); -} +#define INFO_NO_MSG 0 -// Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases) -void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type) +void Obituary_SpecialDeath(entity notif_target, float murder, float deathtype, string s1, string s2, string s3, float f1, float f2, float f3) { - if (clienttype(e) == CLIENTTYPE_REAL) + float handled = 0, hits = 0; + if(DEATH_ISSPECIAL(deathtype)) { - msg_entity = e; - WRITESPECTATABLE_MSG_ONE({ - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT); - WriteString(MSG_ONE, s1); - WriteString(MSG_ONE, s2); - WriteShort(MSG_ONE, msg); - WriteByte(MSG_ONE, type); - }); + #define DEATHTYPE(name,msg_death,msg_death_by,position) \ + { if(deathtype == max(0, name)) \ + { \ + #if msg_death != NO_MSG \ + if not(murder) \ + { \ + Send_Notification_WOVA(NOTIF_ONE, notif_target, MSG_MULTI, msg_death, s1, s2, s3, "", f1, f2, f3, 0); \ + Send_Notification_WOVA(NOTIF_ANY_EXCEPT, notif_target, MSG_INFO, INFO_##msg_death, s1, s2, s3, "", f1, f2, f3, 0); \ + ++handled; \ + } \ + #endif \ + #if msg_death_by != NO_MSG \ + if(murder) \ + { \ + Send_Notification_WOVA(NOTIF_ONE, notif_target, MSG_MULTI, msg_death_by, s1, s2, s3, "", f1, f2, f3, 0); \ + Send_Notification_WOVA(NOTIF_ANY_EXCEPT, notif_target, MSG_INFO, INFO_##msg_death_by, s1, s2, s3, "", f1, f2, f3, 0); \ + ++handled; \ + } \ + #endif \ + ++hits; \ + } } + + DEATHTYPES + #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(entity notif_target, float murder, float deathtype, string s1, string s2, string s3, float f1, float f2) { - string s, a, msg; - float type; - - if (targ.classname == "player") + float death_weapon = DEATH_WEAPONOF(deathtype); + 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 + if(death_message) { - if (deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) - msg = ColoredTeamName(targ.team); // TODO: check if needed? - else - msg = ""; - if(!g_cts) // no "killed your own dumb self" message in CTS - Send_CSQC_KillCenterprint(targ, msg, "", deathtype, MSG_SUICIDE); + Send_Notification_WOVA(NOTIF_ONE, notif_target, MSG_MULTI, death_message, s1, s2, s3, "", f1, f2, 0, 0); + Send_Notification_WOVA(NOTIF_ANY_EXCEPT, notif_target, MSG_INFO, msg_multi_notifs[death_message - 1].nent_msginfo.nent_id, s1, s2, s3, "", f1, f2, 0, 0); + } + else { dprint(sprintf("Obituary_WeaponDeath(): ^1Deathtype ^7(%s-%d)^1 has no notification for weapon %d!\n", Deathtype_Name(deathtype), deathtype, death_weapon)); } - if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET) + return TRUE; + } + return FALSE; +} + +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; } + + // Declarations + float notif_firstblood = FALSE; + float kill_count_to_attacker, kill_count_to_target; + + // Set final information for the death + targ.death_origin = targ.origin; + if(targ != attacker) { targ.killer_origin = attacker.origin; } + string deathlocation = NearestLocation(targ.death_origin); + + #ifdef NOTIFICATIONS_DEBUG + dprint( + sprintf("Obituary(%s, %s, %s, %s = %d);\n", + attacker.netname, + inflictor.netname, + targ.netname, + Deathtype_Name(deathtype), + deathtype + ) + ); + #endif + + // ======= + // SUICIDE + // ======= + if(targ == attacker) + { + if(DEATH_ISSPECIAL(deathtype)) + { + if(deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) { - LogDeath("suicide", deathtype, targ, targ); - GiveFrags(attacker, targ, -1, deathtype); + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0); } - - if (targ.killcount > 2) - msg = ftos(targ.killcount); else - msg = ""; - if(teamplay && deathtype == DEATH_MIRRORDAMAGE) { - if(attacker.team == COLOR_TEAM1) - deathtype = KILL_TEAM_RED; - else - deathtype = KILL_TEAM_BLUE; + switch(deathtype) + { + case DEATH_MIRRORDAMAGE: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0); + break; + } + + default: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0); + break; + } + } + LogDeath("suicide", deathtype, targ, targ); + GiveFrags(attacker, targ, -1, deathtype); } - - Send_KillNotification(s, msg, "", deathtype, MSG_SUICIDE); } - else if (attacker.classname == "player") + else if not(Obituary_WeaponDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0)) { - if(!IsDifferentTeam(attacker, targ)) - { - if(attacker.team == COLOR_TEAM1) - type = KILL_TEAM_RED; - else - type = KILL_TEAM_BLUE; - - GiveFrags(attacker, targ, -1, deathtype); + backtrace("SUICIDE: what the hell happened here?\n"); + } + } - Send_CSQC_KillCenterprint(attacker, s, "", type, MSG_KILL); + // ====== + // MURDER + // ====== + else if(attacker.classname == "player") + { + if(!IsDifferentTeam(attacker, targ)) + { + LogDeath("tk", deathtype, attacker, targ); + GiveFrags(attacker, targ, -1, deathtype); - if (targ.killcount > 2) - msg = ftos(targ.killcount); - else - msg = ""; + attacker.killcount = 0; + + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, targ.netname); + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker.netname); + Send_Notification(NOTIF_ANY, world, MSG_INFO, APP_TEAM_NUM_4(targ.team, INFO_DEATH_TEAMKILL_), targ.netname, attacker.netname, targ.killcount); - if (attacker.killcount > 2) { - msg = ftos(attacker.killcount); - type = KILL_TEAM_SPREE; + // 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); + + attacker.taunt_soundtime = time + 1; + attacker.killcount = attacker.killcount + 1; + + #define SPREE_ITEM(counta,countb,center,normal,gentle) \ + case counta: \ + { \ + AnnounceTo(attacker, strcat(#countb, "kills")); \ + PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \ + break; \ } - Send_KillNotification(a, s, msg, type, MSG_KILL); - - attacker.killcount = 0; + switch(attacker.killcount) + { + KILL_SPREE_LIST + default: break; + } + #undef SPREE_ITEM - LogDeath("tk", deathtype, attacker, targ); + 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); + + // tell spree_inf and spree_cen that this is a first-blood and first-victim event + kill_count_to_attacker = -1; + kill_count_to_target = -2; } else { - if (!checkrules_firstblood) - { - 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); - } - - attacker.taunt_soundtime = time + 1; + kill_count_to_attacker = attacker.killcount; + kill_count_to_target = 0; + } - if (deathtype == DEATH_HURTTRIGGER && inflictor.message2 != "") - msg = inflictor.message2; - else if (deathtype == DEATH_CUSTOM) - msg = deathmessage; + if(targ.istypefrag) + { + if(attacker.FRAG_VERBOSE) + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping)); else - msg = ""; - - if(strstrofs(msg, "%", 0) < 0) - msg = strcat("%s ", msg, " by %s"); + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG, targ.netname, kill_count_to_attacker); - Send_KillNotification(a, s, msg, deathtype, MSG_KILL); + if(targ.FRAG_VERBOSE) + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping)); + else + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED, attacker.netname, kill_count_to_target); + } + else + { + if(attacker.FRAG_VERBOSE) + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping)); + else + Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG, targ.netname, kill_count_to_attacker); - GiveFrags(attacker, targ, 1, deathtype); + if(targ.FRAG_VERBOSE) + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping)); + else + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED, attacker.netname, kill_count_to_target); + } - if (targ.killcount > 2) { - Send_KillNotification(s, ftos(targ.killcount), a, KILL_END_SPREE, MSG_SPREE); - } + if not(Obituary_WeaponDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker)) + Obituary_SpecialDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker, 0); + } + } - attacker.killcount = attacker.killcount + 1; + // ============= + // ACCIDENT/TRAP + // ============= + else + { + switch(deathtype) + { + // 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; + }*/ - 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) - { - Send_KillNotification(a, "", "", KILL_SPREE_15, MSG_SPREE); - AnnounceTo(attacker, "15kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15, 1); - } - else if (attacker.killcount == 20) - { - Send_KillNotification(a, "", "", KILL_SPREE_20, MSG_SPREE); - AnnounceTo(attacker, "20kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20, 1); - } - else if (attacker.killcount == 25) - { - Send_KillNotification(a, "", "", KILL_SPREE_25, MSG_SPREE); - AnnounceTo(attacker, "25kills"); - PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25, 1); - } - else if (attacker.killcount == 30) - { - 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); - } - LogDeath("frag", deathtype, attacker, targ); + case DEATH_CUSTOM: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, + targ.netname, + ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage), + deathlocation, + targ.killcount, + 0, + 0); + break; } - } - else - { - 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); + + default: + { + Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0); + 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); } - targ.death_origin = targ.origin; - if(targ != attacker) - targ.killer_origin = attacker.origin; + LogDeath("accident", deathtype, targ, targ); + GiveFrags(targ, targ, -1, deathtype); - // FIXME: this should go in PutClientInServer - if (targ.killcount) - targ.killcount = 0; + if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) + { + AnnounceTo(targ, "botlike"); + PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1); + } } + + // reset target kill count + if(targ.killcount) { targ.killcount = 0; } } // these are updated by each Damage call for use in button triggering and such @@ -527,7 +536,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float { float mirrordamage; float mirrorforce; - float complainteamdamage; + float complainteamdamage = 0; entity attacker_save; mirrordamage = 0; mirrorforce = 0; @@ -560,7 +569,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