X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fg_damage.qc;h=fe4df352fb5a2fc1c6cfd565d8985f72d05bf6d8;hb=89eff022dd8653e6b5965d35dd9fb9caa54fe72c;hp=b8c6d4cf04d397bcc326c2ca17c4c57c58ab2923;hpb=84de176ec42eeaeaa7f9b415b0f2b67adb1aa708;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index b8c6d4cf0..fe4df352f 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -41,8 +41,6 @@ void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad Net_LinkEntity(e, FALSE, 0.2, Damage_DamageInfo_SendEntity); } -#define DAMAGE_CENTERPRINT_SPACER NEWLINES - float checkrules_firstblood; float yoda; @@ -61,7 +59,7 @@ float damage_headshotbonus; // bonus multiplier for head shots, set to 0 after u float IsDifferentTeam(entity a, entity b) { - if(teams_matter) + if(teamplay) { if(a.team == b.team) return 0; @@ -102,7 +100,7 @@ void UpdateFrags(entity player, float f) // NOTE: f=0 means still count as a (positive) kill, but count no frags for it void W_SwitchWeapon_Force(entity e, float w); -void GiveFrags (entity attacker, entity targ, float f) +void GiveFrags (entity attacker, entity targ, float f, float deathtype) { float w; @@ -120,38 +118,55 @@ void GiveFrags (entity attacker, entity targ, float f) { // teamkill PlayerScore_Add(attacker, SP_KILLS, -1); // or maybe add a teamkills field? - PlayerStats_Event(attacker, PLAYERSTATS_KILLS, -1); } } else { // regular frag PlayerScore_Add(attacker, SP_KILLS, 1); - PlayerStats_Event(attacker, PLAYERSTATS_KILLS, 1); + if(targ.playerid) + PlayerStats_Event(attacker, sprintf("kills-%d", targ.playerid), 1); } PlayerScore_Add(targ, SP_DEATHS, 1); if(g_arena || g_ca) - if(cvar("g_arena_roundbased")) + if(autocvar_g_arena_roundbased) return; if(targ != attacker) // not for suicides if(g_weaponarena_random) { - // after a frag, choose another random weapon set - if(inWarmupStage) - w = warmup_start_weapons; - else - w = start_weapons; + // after a frag, exchange the current weapon (or the culprit, if detectable) by a new random weapon + float culprit; + culprit = DEATH_WEAPONOF(deathtype); + if(!culprit || !(attacker.weapons & W_WeaponBit(culprit))) + culprit = attacker.weapon; - attacker.weapons = randombits(w - (w & W_WeaponBit(attacker.weapon)), g_weaponarena_random, TRUE); - if(attacker.weapons < 0) + if(g_weaponarena_random_with_laser && culprit == WEPBIT_LASER) + { + // no exchange + } + else { - // error from randombits: no weapon available - // this means we can just give ALL weapons - attacker.weapons = w; + if(inWarmupStage) + w = warmup_start_weapons; + else + w = start_weapons; + + // all others (including the culprit): remove + w &~= attacker.weapons; + + // among the remaining ones, choose one by random + w = randombits(w, 1, FALSE); + if(w) + { + attacker.weapons |= w; + attacker.weapons &~= W_WeaponBit(culprit); + } } + + // after a frag, choose another random weapon set if not(attacker.weapons & W_WeaponBit(attacker.weapon)) W_SwitchWeapon_Force(attacker, w_getbestweapon(attacker)); } @@ -186,6 +201,8 @@ void GiveFrags (entity attacker, entity targ, float f) { if(!lms_next_place) lms_next_place = player_count; + else + lms_next_place = min(lms_next_place, player_count); PlayerScore_Add(targ, SP_LMS_RANK, lms_next_place); // won't ever spawn again --lms_next_place; } @@ -204,6 +221,42 @@ void GiveFrags (entity attacker, entity targ, float f) UpdateFrags(attacker, f); } +string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information +{ + string health_output; + string ping_output; + string handicap_output; + string output; + + // health/armor of attacker (person who killed you) + if(autocvar_sv_fraginfo_stats && (player.health >= 1)) + if((autocvar_sv_fraginfo_stats == 2) || !inWarmupStage) + 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(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(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(player.cvar_cl_handicap)); + } + + // format the string + output = strcat(health_output, (health_output ? " ^7(" : ((ping_output || handicap_output) ? "^7(" : "")), + ping_output, ((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; @@ -231,7 +284,7 @@ string AppendItemcodes(string s, entity player) void LogDeath(string mode, float deathtype, entity killer, entity killed) { string s; - if(!cvar("sv_eventlog")) + if(!autocvar_sv_eventlog) return; s = strcat(":kill:", mode); s = strcat(s, ":", ftos(killer.playerid)); @@ -250,8 +303,7 @@ void LogDeath(string mode, float deathtype, entity killer, entity killed) void Send_KillNotification (string s1, string s2, string s3, float msg, float type) { WriteByte(MSG_ALL, SVC_TEMPENTITY); - WriteByte(MSG_ALL, TE_CSQC_NOTIFY); - WriteByte(MSG_ALL, CSQC_KILLNOTIFY); + WriteByte(MSG_ALL, TE_CSQC_KILLNOTIFY); WriteString(MSG_ALL, s1); WriteString(MSG_ALL, s2); WriteString(MSG_ALL, s3); @@ -260,15 +312,14 @@ void Send_KillNotification (string s1, string s2, string s3, float msg, float ty } // 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_Centerprint(entity e, string s1, string s2, float msg, float type) +void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type) { if (clienttype(e) == CLIENTTYPE_REAL) { msg_entity = e; WRITESPECTATABLE_MSG_ONE({ WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_NOTIFY); - WriteByte(MSG_ONE, CSQC_CENTERPRINT); + WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT); WriteString(MSG_ONE, s1); WriteString(MSG_ONE, s2); WriteShort(MSG_ONE, msg); @@ -282,30 +333,27 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) string s, a, msg; float w, type; - if (targ.classname == "player" || targ.classname == "corpse") + if (targ.classname == "player") { - if (targ.classname == "corpse") - s = "A corpse"; - else - s = targ.netname; - + s = targ.netname; a = attacker.netname; if (targ == attacker) // suicides { if (deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE) msg = ColoredTeamName(targ.team); // TODO: check if needed? - Send_CSQC_Centerprint(targ, msg, "", deathtype, MSG_SUICIDE); + if(!g_cts) // no "killed your own dumb self" message in CTS + Send_CSQC_KillCenterprint(targ, msg, "", deathtype, MSG_SUICIDE); if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET) { LogDeath("suicide", deathtype, targ, targ); - GiveFrags(attacker, targ, -1); + GiveFrags(attacker, targ, -1, deathtype); } if (targ.killcount > 2) msg = ftos(targ.killcount); - if(teams_matter && deathtype == DEATH_MIRRORDAMAGE) + if(teamplay && deathtype == DEATH_MIRRORDAMAGE) { if(attacker.team == COLOR_TEAM1) deathtype = KILL_TEAM_RED; @@ -315,18 +363,18 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) Send_KillNotification(s, msg, ftos(w), deathtype, MSG_SUICIDE); } - else if (attacker.classname == "player" || attacker.classname == "gib") + else if (attacker.classname == "player") { - if(teams_matter && attacker.team == targ.team) + if(!IsDifferentTeam(attacker, targ)) { if(attacker.team == COLOR_TEAM1) type = KILL_TEAM_RED; else type = KILL_TEAM_BLUE; - GiveFrags(attacker, targ, -1); + GiveFrags(attacker, targ, -1, deathtype); - Send_CSQC_Centerprint(attacker, s, "", type, MSG_KILL); + Send_CSQC_KillCenterprint(attacker, s, "", type, MSG_KILL); if (targ.killcount > 2) { msg = ftos(targ.killcount); @@ -349,16 +397,18 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) checkrules_firstblood = TRUE; Send_KillNotification(a, "", "", KILL_FIRST_BLOOD, MSG_KILL); // TODO: make these print a newline if they dont - Send_CSQC_Centerprint(attacker, "", "", KILL_FIRST_BLOOD, MSG_KILL); - Send_CSQC_Centerprint(targ, "", "", KILL_FIRST_VICTIM, MSG_KILL); + 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((cvar("sv_fragmessage_information_typefrag")) && (targ.BUTTON_CHAT)) { - Send_CSQC_Centerprint(attacker, s, GetAdvancedDeathReports(targ), KILL_TYPEFRAG, MSG_KILL); - Send_CSQC_Centerprint(targ, a, GetAdvancedDeathReports(attacker), KILL_TYPEFRAGGED, MSG_KILL); + if((autocvar_sv_fraginfo_typefrag) && (targ.BUTTON_CHAT)) { + 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_Centerprint(attacker, s, GetAdvancedDeathReports(targ), KILL_FRAG, MSG_KILL); - Send_CSQC_Centerprint(targ, a, GetAdvancedDeathReports(attacker), KILL_FRAGGED, MSG_KILL); + 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; @@ -378,10 +428,10 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) { UpdateFrags(attacker, ctf_score_value("score_kill")); PlayerScore_Add(attacker, SP_CTF_FCKILLS, 1); - GiveFrags(attacker, targ, 0); // for logging + GiveFrags(attacker, targ, 0, deathtype); // for logging } else - GiveFrags(attacker, targ, 1); + GiveFrags(attacker, targ, 1, deathtype); if (targ.killcount > 2) { Send_KillNotification(s, ftos(targ.killcount), a, KILL_END_SPREE, MSG_SPREE); @@ -396,43 +446,50 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) { 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); } LogDeath("frag", deathtype, attacker, targ); } } else { - Send_CSQC_Centerprint(targ, "", "", deathtype, MSG_KILL_ACTION); + Send_CSQC_KillCenterprint(targ, "", "", deathtype, MSG_KILL_ACTION); if (deathtype == DEATH_HURTTRIGGER && inflictor.message != "") msg = inflictor.message; else if (deathtype == DEATH_CUSTOM) @@ -440,9 +497,10 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) if(strstrofs(msg, "%", 0) < 0) msg = strcat("%s ", msg); - GiveFrags(targ, targ, -1); + GiveFrags(targ, targ, -1, deathtype); if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) { AnnounceTo(targ, "botlike"); + PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1); } Send_KillNotification(s, msg, "", deathtype, MSG_KILL_ACTION); @@ -466,7 +524,6 @@ void Obituary (entity attacker, entity inflictor, entity targ, float deathtype) entity damage_targ; entity damage_inflictor; entity damage_attacker; -.float prevhitsound; void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { @@ -480,7 +537,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if (gameover || targ.killcount == -666) return; - local entity oldself; + entity oldself; oldself = self; self = targ; damage_targ = targ; @@ -522,12 +579,15 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float } else { + /* + skill based bot damage? gtfo. (tZork) if (targ.classname == "player") if (attacker.classname == "player") if (!targ.isbot) if (attacker.isbot) damage = damage * bound(0.1, (skill + 5) * 0.1, 1); - + */ + // nullify damage if teamplay is on if(deathtype != DEATH_TELEFRAG) if(attacker.classname == "player") @@ -537,33 +597,56 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float damage = 0; force = '0 0 0'; } - else if(attacker.team == targ.team) + else if(!IsDifferentTeam(attacker, targ)) { - if(teamplay == 1) + if(autocvar_teamplay_mode == 1) damage = 0; else if(attacker != targ) { - if(teamplay == 3) + if(autocvar_teamplay_mode == 3) damage = 0; - else if(teamplay == 4) + else if(autocvar_teamplay_mode == 4) { if(targ.classname == "player" && targ.deadflag == DEAD_NO) { - teamdamage0 = max(attacker.dmg_team, cvar("g_teamdamage_threshold")); + teamdamage0 = max(attacker.dmg_team, autocvar_g_teamdamage_threshold); attacker.dmg_team = attacker.dmg_team + damage; if(attacker.dmg_team > teamdamage0 && !g_ca) - mirrordamage = cvar("g_mirrordamage") * (attacker.dmg_team - teamdamage0); - mirrorforce = cvar("g_mirrordamage") * vlen(force); + mirrordamage = autocvar_g_mirrordamage * (attacker.dmg_team - teamdamage0); + mirrorforce = autocvar_g_mirrordamage * vlen(force); if(g_minstagib) { - if(cvar("g_friendlyfire") == 0) + if(autocvar_g_friendlyfire == 0) damage = 0; } else if(g_ca) damage = 0; else - damage = cvar("g_friendlyfire") * damage; + damage = autocvar_g_friendlyfire * damage; // mirrordamage will be used LATER + + if(autocvar_g_mirrordamage_virtual) + { + vector v; + v = healtharmor_applydamage(attacker.armorvalue, autocvar_g_balance_armor_blockpercent, mirrordamage); + attacker.dmg_take += v_x; + attacker.dmg_save += v_y; + attacker.dmg_inflictor = inflictor; + mirrordamage = 0; + mirrorforce = 0; + } + + if(autocvar_g_friendlyfire_virtual) + { + vector v; + v = healtharmor_applydamage(targ.armorvalue, autocvar_g_balance_armor_blockpercent, damage); + targ.dmg_take += v_x; + targ.dmg_save += v_y; + targ.dmg_inflictor = inflictor; + damage = 0; + if(!autocvar_g_friendlyfire_virtual_force) + force = '0 0 0'; + } } else damage = 0; @@ -576,8 +659,8 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if(attacker.classname == "player") if(attacker != targ) { - targ.lms_traveled_distance = cvar("g_lms_campcheck_distance"); - attacker.lms_traveled_distance = cvar("g_lms_campcheck_distance"); + targ.lms_traveled_distance = autocvar_g_lms_campcheck_distance; + attacker.lms_traveled_distance = autocvar_g_lms_campcheck_distance; } if(targ.classname == "player") @@ -597,7 +680,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if (targ.armorvalue && (deathtype == WEP_MINSTANEX) && damage) { targ.armorvalue -= 1; - centerprint(targ, strcat(DAMAGE_CENTERPRINT_SPACER, "^3Remaining extra lives: ",ftos(targ.armorvalue))); + centerprint(targ, strcat("^3Remaining extra lives: ",ftos(targ.armorvalue))); damage = 0; targ.hitsound += 1; attacker.hitsound += 1; // TODO change this to a future specific hitsound for armor hit @@ -605,12 +688,11 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if (DEATH_ISWEAPON(deathtype, WEP_LASER)) { damage = 0; + mirrordamage = 0; if (targ != attacker) { if ((targ.health >= 1) && (targ.classname == "player")) - centerprint(attacker, strcat(DAMAGE_CENTERPRINT_SPACER, "Secondary fire inflicts no damage!")); - damage = 0; - mirrordamage = 0; + centerprint(attacker, "Secondary fire inflicts no damage!"); force = '0 0 0'; // keep mirrorforce attacker = targ; @@ -631,6 +713,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float frag_target = targ; frag_damage = damage; frag_force = force; + frag_deathtype = deathtype; MUTATOR_CALLHOOK(PlayerDamage_Calculate); damage = frag_damage; force = frag_force; @@ -640,26 +723,26 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float { if(targ == attacker) { - damage = damage * cvar("g_balance_powerup_strength_selfdamage"); - force = force * cvar("g_balance_powerup_strength_selfforce"); + damage = damage * autocvar_g_balance_powerup_strength_selfdamage; + force = force * autocvar_g_balance_powerup_strength_selfforce; } else { - damage = damage * cvar("g_balance_powerup_strength_damage"); - force = force * cvar("g_balance_powerup_strength_force"); + damage = damage * autocvar_g_balance_powerup_strength_damage; + force = force * autocvar_g_balance_powerup_strength_force; } } // apply invincibility multiplier if (targ.items & IT_INVINCIBLE && !g_minstagib) - damage = damage * cvar("g_balance_powerup_invincible_takedamage"); + damage = damage * autocvar_g_balance_powerup_invincible_takedamage; if (targ == attacker) { - if(g_ca || (g_cts && !cvar("g_cts_selfdamage"))) + if(g_ca || (g_cts && !autocvar_g_cts_selfdamage)) damage = 0; else - damage = damage * cvar("g_balance_selfdamagepercent"); // Partial damage if the attacker hits himself + damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself } // CTF: reduce damage/force @@ -667,8 +750,8 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if(targ == attacker) if(targ.flagcarried) { - damage = damage * cvar("g_ctf_flagcarrier_selfdamage"); - force = force * cvar("g_ctf_flagcarrier_selfforce"); + damage = damage * autocvar_g_ctf_flagcarrier_selfdamage; + force = force * autocvar_g_ctf_flagcarrier_selfforce; } if(g_runematch) @@ -678,31 +761,31 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float { if(attacker.runes & CURSE_WEAK) // have both curse & rune { - damage = damage * cvar("g_balance_rune_strength_combo_damage"); - force = force * cvar("g_balance_rune_strength_combo_force"); + damage = damage * autocvar_g_balance_rune_strength_combo_damage; + force = force * autocvar_g_balance_rune_strength_combo_force; } else { - damage = damage * cvar("g_balance_rune_strength_damage"); - force = force * cvar("g_balance_rune_strength_force"); + damage = damage * autocvar_g_balance_rune_strength_damage; + force = force * autocvar_g_balance_rune_strength_force; } } else if (attacker.runes & CURSE_WEAK) { - damage = damage * cvar("g_balance_curse_weak_damage"); - force = force * cvar("g_balance_curse_weak_force"); + damage = damage * autocvar_g_balance_curse_weak_damage; + force = force * autocvar_g_balance_curse_weak_force; } // apply defense rune if (targ.runes & RUNE_DEFENSE) { if (targ.runes & CURSE_VULNER) // have both curse & rune - damage = damage * cvar("g_balance_rune_defense_combo_takedamage"); + damage = damage * autocvar_g_balance_rune_defense_combo_takedamage; else - damage = damage * cvar("g_balance_rune_defense_takedamage"); + damage = damage * autocvar_g_balance_rune_defense_takedamage; } else if (targ.runes & CURSE_VULNER) - damage = damage * cvar("g_balance_curse_vulner_takedamage"); + damage = damage * autocvar_g_balance_curse_vulner_takedamage; } // count the damage @@ -711,40 +794,48 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if(targ.takedamage == DAMAGE_AIM) if(targ != attacker) { - if(targ.classname == "player") + if(damage_headshotbonus > 0) { - // HEAD SHOT: - // find height of hit on player axis - // if above view_ofs and below maxs, and also in the middle half of the bbox, it is head shot - vector headmins, headmaxs, org; - org = antilag_takebackorigin(targ, time - ANTILAG_LATENCY(attacker)); - headmins = org + GetHeadshotMins(targ); - headmaxs = org + GetHeadshotMaxs(targ); - if(trace_hits_box(railgun_start, railgun_end, headmins, headmaxs)) + if(targ.classname == "player") + { + // HEAD SHOT: + // find height of hit on player axis + // if above view_ofs and below maxs, and also in the middle half of the bbox, it is head shot + vector headmins, headmaxs, org; + org = antilag_takebackorigin(targ, time - ANTILAG_LATENCY(attacker)); + headmins = org + GetHeadshotMins(targ); + headmaxs = org + GetHeadshotMaxs(targ); + if(trace_hits_box(railgun_start, railgun_end, headmins, headmaxs)) + { + deathtype |= HITTYPE_HEADSHOT; + } + } + else if(targ.classname == "turret_head") { deathtype |= HITTYPE_HEADSHOT; } + if(deathtype & HITTYPE_HEADSHOT) + damage *= 1 + damage_headshotbonus; } - else if(targ.classname == "turret_head") - { - deathtype |= HITTYPE_HEADSHOT; - } - if(deathtype & HITTYPE_HEADSHOT) - damage *= 1 + damage_headshotbonus; - if(targ.classname == "player") + entity victim; + if((targ.vehicle_flags & VHF_ISVEHICLE) && targ.owner) + victim = targ.owner; + else + victim = targ; + + if(victim.classname == "player" || victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET) { - if(IsDifferentTeam(targ, attacker)) + if(IsDifferentTeam(victim, attacker)) { if(damage > 0) { - if(attacker.weapon != WEP_ELECTRO && attacker.weapon != WEP_LASER || ((attacker.weapon == WEP_ELECTRO && cvar("g_balance_electro_lightning") || attacker.weapon == WEP_LASER) && attacker.prevhitsound + cvar("sv_hitsound_antispam_time") < time)) + if(deathtype != DEATH_FIRE) { - if(targ.BUTTON_CHAT) + if(victim.BUTTON_CHAT) attacker.typehitsound += 1; else attacker.hitsound += 1; - attacker.prevhitsound = time; } damage_goodhits += 1; @@ -752,25 +843,28 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if not(DEATH_ISSPECIAL(deathtype)) { + if(targ.classname == "player") // don't do this for vehicles if(!g_minstagib) - if(IsFlying(targ)) + if(IsFlying(victim)) yoda = 1; if(g_minstagib) - if(targ.items & IT_STRENGTH) + if(victim.items & IT_STRENGTH) yoda = 1; if(deathtype & HITTYPE_HEADSHOT) headshot = 1; } if(g_ca) - PlayerScore_Add(attacker, SP_SCORE, damage * cvar("g_ca_damage2score_multiplier")); + PlayerScore_Add(attacker, SP_SCORE, damage * autocvar_g_ca_damage2score_multiplier); } } else { if(deathtype != DEATH_FIRE) + { attacker.typehitsound += 1; + } if(mirrordamage > 0) if(time > attacker.teamkill_complain) { @@ -788,7 +882,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float if (vlen(force)) if (self.classname != "player" || time >= self.spawnshieldtime || g_midair) { - self.velocity = self.velocity + self.damageforcescale * force; + self.velocity = self.velocity + damage_explosion_calcpush(self.damageforcescale * force, self.velocity, autocvar_g_balance_damagepush_speedfactor); self.flags &~= FL_ONGROUND; UpdateCSQCProjectile(self); } @@ -807,28 +901,28 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float // apply vampire rune if (attacker.runes & CURSE_EMPATHY) // have the curse too { - //attacker.health = attacker.health + damage * cvar("g_balance_rune_vampire_combo_absorb"); + //attacker.health = attacker.health + damage * autocvar_g_balance_rune_vampire_combo_absorb; attacker.health = bound( - cvar("g_balance_curse_empathy_minhealth"), // LA: was 3, now 40 - attacker.health + damage * cvar("g_balance_rune_vampire_combo_absorb"), - cvar("g_balance_rune_vampire_maxhealth")); // LA: was 1000, now 500 + autocvar_g_balance_curse_empathy_minhealth, // LA: was 3, now 40 + attacker.health + damage * autocvar_g_balance_rune_vampire_combo_absorb, + autocvar_g_balance_rune_vampire_maxhealth); // LA: was 1000, now 500 } else { - //attacker.health = attacker.health + damage * cvar("g_balance_rune_vampire_absorb"); + //attacker.health = attacker.health + damage * autocvar_g_balance_rune_vampire_absorb; attacker.health = bound( attacker.health, // LA: was 3, but changed so that you can't lose health // empathy won't let you gain health in the same way... - attacker.health + damage * cvar("g_balance_rune_vampire_absorb"), - cvar("g_balance_rune_vampire_maxhealth")); // LA: was 1000, now 500 + attacker.health + damage * autocvar_g_balance_rune_vampire_absorb, + autocvar_g_balance_rune_vampire_maxhealth); // LA: was 1000, now 500 } } // apply empathy curse else if (attacker.runes & CURSE_EMPATHY) { attacker.health = bound( - cvar("g_balance_curse_empathy_minhealth"), // LA: was 3, now 20 - attacker.health + damage * cvar("g_balance_curse_empathy_takedamage"), + autocvar_g_balance_curse_empathy_minhealth, // LA: was 3, now 20 + attacker.health + damage * autocvar_g_balance_curse_empathy_takedamage, attacker.health); } } @@ -839,17 +933,18 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, float { attacker = attacker_save; if(g_minstagib) - if(mirrordamage > 0) + if(mirrordamage > 0) + { + // just lose extra LIVES, don't kill the player for mirror damage + if(attacker.armorvalue > 0) { - // just lose extra LIVES, don't kill the player for mirror damage - if(attacker.armorvalue > 0) - { - attacker.armorvalue = attacker.armorvalue - 1; - centerprint(attacker, strcat(DAMAGE_CENTERPRINT_SPACER, "^3Remaining extra lives: ",ftos(attacker.armorvalue))); - attacker.hitsound += 1; - } - mirrordamage = 0; + attacker.armorvalue = attacker.armorvalue - 1; + centerprint(attacker, strcat("^3Remaining extra lives: ",ftos(attacker.armorvalue))); + attacker.hitsound += 1; } + mirrordamage = 0; + } + force = normalize(attacker.origin + attacker.view_ofs - hitloc) * mirrorforce; Damage(attacker, inflictor, attacker, mirrordamage, DEATH_MIRRORDAMAGE, attacker.origin, force); } @@ -876,21 +971,14 @@ float RadiusDamage (entity inflictor, entity attacker, float coredamage, float e if(RadiusDamage_running) { - string save; - print("RadiusDamage called recursively!\n"); - print("Expect stuff to go HORRIBLY wrong.\n"); - print("Causing a stack trace...\n"); - save = cvar_string("prvm_backtraceforwarnings"); - cvar_set("prvm_backtraceforwarnings", "1"); - fclose(-1); // calls VM_Warning - cvar_set("prvm_backtraceforwarnings", save); + backtrace("RadiusDamage called recursively! Expect stuff to go HORRIBLY wrong."); return 0; } RadiusDamage_running = 1; - tfloordmg = cvar("g_throughfloor_damage"); - tfloorforce = cvar("g_throughfloor_force"); + tfloordmg = autocvar_g_throughfloor_damage; + tfloorforce = autocvar_g_throughfloor_force; blastorigin = (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5); total_damage_to_creatures = 0; @@ -936,13 +1024,13 @@ float RadiusDamage (entity inflictor, entity attacker, float coredamage, float e finaldmg = coredamage * power + edgedamage * (1 - power); if (finaldmg > 0) { - local float a; - local float c; - local float hits; - local float total; - local float hitratio; - local vector hitloc; - local vector myblastorigin; + float a; + float c; + float hits; + float total; + float hitratio; + vector hitloc; + vector myblastorigin; myblastorigin = WarpZone_TransformOrigin(targ, blastorigin); center = targ.origin + (targ.mins + targ.maxs) * 0.5; // if it's a player, use the view origin as reference @@ -986,33 +1074,47 @@ float RadiusDamage (entity inflictor, entity attacker, float coredamage, float e // laser force adjustments :P if(DEATH_WEAPONOF(deathtype) == WEP_LASER) { - vector vel; - - float force_zscale; - float force_velocitybiasramp; - float force_velocitybias; - - force_velocitybiasramp = cvar("sv_maxspeed"); - if(deathtype & HITTYPE_SECONDARY) - { - force_zscale = cvar("g_balance_laser_secondary_force_zscale"); - force_velocitybias = cvar("g_balance_laser_secondary_force_velocitybias"); - } - else - { - force_zscale = cvar("g_balance_laser_primary_force_zscale"); - force_velocitybias = cvar("g_balance_laser_primary_force_velocitybias"); - } - - vel = targ.velocity; - vel_z = 0; - vel = normalize(vel) * bound(0, vlen(vel) / force_velocitybiasramp, 1) * force_velocitybias; - force = - vlen(force) - * - normalize(normalize(force) + vel); - - force_z *= force_zscale; + if (targ == attacker) + { + vector vel; + + float force_zscale; + float force_velocitybiasramp; + float force_velocitybias; + + force_velocitybiasramp = autocvar_sv_maxspeed; + if(deathtype & HITTYPE_SECONDARY) + { + force_zscale = autocvar_g_balance_laser_secondary_force_zscale; + force_velocitybias = autocvar_g_balance_laser_secondary_force_velocitybias; + } + else + { + force_zscale = autocvar_g_balance_laser_primary_force_zscale; + force_velocitybias = autocvar_g_balance_laser_primary_force_velocitybias; + } + + vel = targ.velocity; + vel_z = 0; + vel = normalize(vel) * bound(0, vlen(vel) / force_velocitybiasramp, 1) * force_velocitybias; + force = + vlen(force) + * + normalize(normalize(force) + vel); + + force_z *= force_zscale; + } + else + { + if(deathtype & HITTYPE_SECONDARY) + { + force *= autocvar_g_balance_laser_secondary_force_other_scale; + } + else + { + force *= autocvar_g_balance_laser_primary_force_other_scale; + } + } } //if (targ == attacker) @@ -1185,6 +1287,10 @@ void Fire_ApplyDamage(entity e) if(e.watertype != CONTENT_LAVA) e.fire_endtime = 0; + // ice stops fire + if(e.freezetag_frozen) + e.fire_endtime = 0; + t = min(frametime, e.fire_endtime - time); d = e.fire_damagepersec * t; @@ -1206,8 +1312,8 @@ void Fire_ApplyDamage(entity e) if not(IS_INDEPENDENT_PLAYER(other)) if(boxesoverlap(e.absmin, e.absmax, other.absmin, other.absmax)) { - t = cvar("g_balance_firetransfer_time") * (e.fire_endtime - time); - d = cvar("g_balance_firetransfer_damage") * e.fire_damagepersec * t; + t = autocvar_g_balance_firetransfer_time * (e.fire_endtime - time); + d = autocvar_g_balance_firetransfer_damage * e.fire_damagepersec * t; Fire_AddDamage(other, o, d, t, DEATH_FIRE); } }