X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fdamage.qc;h=d5a9a20c760d352a7d6631ed2530eba9cf2faad4;hb=94d74449f36b5750f1d1450b02c3817f179211b1;hp=d0b3a288fb3011d5472d1d5df49a2d58ea217399;hpb=82e5c474d4af81e54797d363adcf331548262144;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/damage.qc b/qcsrc/server/damage.qc index d0b3a288f..d5a9a20c7 100644 --- a/qcsrc/server/damage.qc +++ b/qcsrc/server/damage.qc @@ -245,8 +245,10 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en if (MUTATOR_CALLHOOK(ClientObituary, inflictor, attacker, targ, deathtype, attacker.(weaponentity))) { CS(targ).killcount = 0; return; } notif_anonymous = M_ARGV(5, bool); + // TODO: Replace "???" with a translatable "Anonymous player" string + // https://gitlab.com/xonotic/xonotic-data.pk3dir/-/issues/2839 if(notif_anonymous) - attacker_name = "Anonymous player"; + attacker_name = "???"; #ifdef NOTIFICATIONS_DEBUG Debug_Notification( @@ -531,11 +533,11 @@ void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint) FOREACH_CLIENT(IS_PLAYER(it), { for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - if(it.(weaponentity).hook.aiment == targ) - RemoveHook(it.(weaponentity).hook); - } + { + .entity weaponentity = weaponentities[slot]; + if(it.(weaponentity).hook.aiment == targ) + RemoveHook(it.(weaponentity).hook); + } }); // add waypoint @@ -565,11 +567,11 @@ void Unfreeze(entity targ, bool reset_health) FOREACH_CLIENT(IS_PLAYER(it), { for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity weaponentity = weaponentities[slot]; - if(it.(weaponentity).hook.aiment == targ) - RemoveHook(it.(weaponentity).hook); - } + { + .entity weaponentity = weaponentities[slot]; + if(it.(weaponentity).hook.aiment == targ) + RemoveHook(it.(weaponentity).hook); + } }); // remove the ice block @@ -608,7 +610,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de // These are ALWAYS lethal // No damage modification here - // Instead, prepare the victim for his death... + // Instead, prepare the victim for their death... if(deathtype == DEATH_TEAMCHANGE.m_id || deathtype == DEATH_AUTOTEAMCHANGE.m_id) { SetResourceExplicit(targ, RES_ARMOR, 0); @@ -628,7 +630,10 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de if(deathtype != DEATH_TELEFRAG.m_id) if(IS_PLAYER(attacker)) { - if(IS_PLAYER(targ) && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ))) + // avoid dealing damage or force to other independent players + // and avoid dealing damage or force to things owned by other independent players + if((IS_PLAYER(targ) && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ))) || + (targ.realowner && IS_INDEPENDENT_PLAYER(targ.realowner) && attacker != targ.realowner)) { damage = 0; force = '0 0 0'; @@ -707,11 +712,11 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de if(IS_PLAYER(targ) && damage > 0 && attacker) { for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) - { - .entity went = weaponentities[slot]; - if(targ.(went).hook && targ.(went).hook.aiment == attacker) - RemoveHook(targ.(went).hook); - } + { + .entity went = weaponentities[slot]; + if(targ.(went).hook && targ.(went).hook.aiment == attacker) + RemoveHook(targ.(went).hook); + } } if(STAT(FROZEN, targ) && !ITEM_DAMAGE_NEEDKILL(deathtype) @@ -914,13 +919,17 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in if (((cantbe != targ) && !mustbe) || (mustbe == targ)) if (targ.takedamage) { - // measure distance from nearest point on target (not origin) - // to nearest point on inflictor (not origin) + // calculate distance from nearest point on target to nearest point on inflictor + // instead of origin to ensure full damage on impacts + vector nearest = targ.WarpZone_findradius_nearest; + + // optimize code by getting inflictororigin_wz from WarpZone_FindRadius calculations instead of + //vector inflictororigin_wz = WarpZone_TransformOrigin(targ, inflictororigin); + + vector inflictororigin_wz = targ.WarpZone_findradius_nearest + targ.WarpZone_findradius_dist; vector inflictornearest = NearestPointOnBoundingBox( - inflictororigin - (inflictor.maxs - inflictor.mins) * 0.5, - inflictororigin + (inflictor.maxs - inflictor.mins) * 0.5, - nearest); + inflictororigin_wz + inflictor.mins, inflictororigin_wz + inflictor.maxs, nearest); vector diff = inflictornearest - nearest; // round up a little on the damage to ensure full damage on impacts @@ -928,26 +937,68 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in float dist = max(0, vlen(diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS)); if (dist <= rad) { - float power = 1; - if (rad > 0) - power -= (dist / rad); - // at this point power can't be < 0 or > 1 - float finaldmg = coredamage * power + edgedamage * (1 - power); + float f = (rad > 0) ? 1 - (dist / rad) : 1; + // at this point f can't be < 0 or > 1 + float finaldmg = coredamage * f + edgedamage * (1 - f); if (finaldmg > 0) { float a; float c; vector hitloc; - vector myblastorigin; - vector center; - - myblastorigin = WarpZone_TransformOrigin(targ, inflictororigin); // if it's a player, use the view origin as reference - center = CENTER_OR_VIEWOFS(targ); + vector center = CENTER_OR_VIEWOFS(targ); + + if (autocvar_g_player_damageplayercenter) + { + if (targ != attacker) + { + // always use target's bbox centerpoint + center = targ.origin + ((targ.mins + targ.maxs) * 0.5); + } + else // targ == attacker + { + #if 0 + // code stolen from W_SetupShot_Dir_ProjectileSize_Range() + vector md = targ.(weaponentity).movedir; + vector dv = v_right * -md.y + v_up * md.z; + vector mi = '0 0 0', ma = '0 0 0'; + + if(IS_CLIENT(targ)) // no antilag for non-clients! + { + if(CS(targ).antilag_debug) + tracebox_antilag(targ, center, mi, ma, center + dv, MOVE_NORMAL, targ, CS(targ).antilag_debug); + else + tracebox_antilag(targ, center, mi, ma, center + dv, MOVE_NORMAL, targ, ANTILAG_LATENCY(targ)); + } + else + tracebox(center, mi, ma, center + dv, MOVE_NORMAL, targ); + + center.z = trace_endpos.z; + #else + // very cheap way but it skips move into solid checks which is fine most of the time for now AFAIK + // this should only really be an issue with some rare edge cases where + // shot origin was prevented from going into a ceiling but it still explodes at the ceiling + // shot origin wasn't raised as high as possible and the shooter gets upwards knockback + // TL;DR: no bugs if vertical shot origin is always within player bbox + center.z = center.z + targ.(weaponentity).movedir.z; + #endif + } + } - force = normalize(center - myblastorigin); - force = force * (finaldmg / coredamage) * forceintensity; + /* debug prints + print(sprintf("origin vec %v\n", targ.origin)); + print(sprintf("movedir vec %v\n", targ.(weaponentity).movedir)); + print(sprintf("old def vec %v\n", CENTER_OR_VIEWOFS(targ))); + print(sprintf("origin+vofs %v\n", targ.origin + targ.view_ofs)); + print(sprintf("bbox center %v\n", (targ.origin + ((targ.mins + targ.maxs) * 0.5)))); + print(sprintf("center vec %v\n", center)); + print(sprintf("shotorg vec %v\n", w_shotorg)); + print("\n"); + */ + + force = normalize(center - inflictororigin_wz); + force = force * (finaldmg / max(coredamage, edgedamage)) * forceintensity; hitloc = nearest; // apply special scaling along the z axis if set @@ -1017,14 +1068,15 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in if(autocvar_g_throughfloor_debug) LOG_INFOF(" D=%f F=%f", finaldmg, vlen(force)); + + /*if (targ == attacker) + { + print("hits ", ftos(hits), " / ", ftos(total)); + print(" finaldmg ", ftos(finaldmg), " force ", ftos(vlen(force))); + print(" (", vtos(force), ") (", ftos(a), ")\n"); + }*/ } - //if (targ == attacker) - //{ - // print("hits ", ftos(hits), " / ", ftos(total)); - // print(" finaldmg ", ftos(finaldmg), " force ", vtos(force)); - // print(" (", ftos(a), ")\n"); - //} if(finaldmg || force) { if(targ.iscreature) @@ -1049,14 +1101,14 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in RadiusDamage_running = 0; if(!DEATH_ISSPECIAL(deathtype)) - accuracy_add(attacker, DEATH_WEAPONOF(deathtype), 0, min(coredamage, stat_damagedone)); + accuracy_add(attacker, DEATH_WEAPONOF(deathtype), 0, min(max(coredamage, edgedamage), stat_damagedone)); return total_damage_to_creatures; } float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity) { - return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, + return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, 1, deathtype, weaponentity, directhitentity); }