From 51336d201360f8afdf86c65c0f5f31bfb645ade6 Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Thu, 1 May 2025 21:50:54 +1000 Subject: [PATCH] Allow projectile<>projectile interactions to be disabled Adds cvar g_projectiles_interact which defaults to the traditional behaviour. --- balance-xonotic.cfg | 1 + qcsrc/common/checkextension.qc | 3 +++ qcsrc/common/weapons/weapon/blaster.qc | 11 +++++++++++ qcsrc/server/weapons/common.qc | 11 ++++++++++- qcsrc/server/weapons/common.qh | 12 +++++++++++- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/balance-xonotic.cfg b/balance-xonotic.cfg index 64f054caf0..6fe54405c3 100644 --- a/balance-xonotic.cfg +++ b/balance-xonotic.cfg @@ -205,6 +205,7 @@ set g_balance_firetransfer_damage 0.8 set g_throughfloor_damage 0.75 set g_throughfloor_force 0.75 set g_projectiles_damage -2 "\"-2\" = allow no damage to projectiles, \"-1\" = no damage other than the exceptions (electro combo, hagar join explode, ML mines), \"0\" = only damage from contents (lava/slime) or exceptions, \"1\" = only self damage or damage from contents or exceptions, \"2\" = allow all damage to projectiles" +set g_projectiles_interact 2 "\"0\" = projectiles don't interact with each other (noclip through), \"1\" = projectiles don't interact except that blaster bolts detonate when hitting another projectile (deflect it), \"2\" = normal projectiles detonate and bouncy projectiles bounce off when hitting another projectile" set g_projectiles_keep_owner 1 set g_projectiles_newton_style 0 "\"0\" = absolute velocity projectiles (like Quake), \"1\" = relative velocity projectiles, \"Newtonian\" (like Tribes 2), \"2\" = relative velocity projectiles, but aim is precorrected so projectiles hit the crosshair (NOTE: strafe rockets then are SLOWER than ones shot while standing, happens in 1 too when aiming correctly which is hard)" set g_projectiles_newton_style_2_minfactor 0.8 diff --git a/qcsrc/common/checkextension.qc b/qcsrc/common/checkextension.qc index 9f10501ef7..87e82862a3 100644 --- a/qcsrc/common/checkextension.qc +++ b/qcsrc/common/checkextension.qc @@ -52,6 +52,9 @@ void CheckEngineExtensions(void) if (!world.fullspawndata) LOG_WARN("Engine lacks entity fullspawndata, on Quake 3 maps some entities will malfunction."); + + if (!checkextension("DP_RM_CLIPGROUP")) + LOG_WARN("Engine lacks DP_RM_CLIPGROUP, g_projectiles_interact < 2 won't take effect."); #endif #ifdef GAMEQC diff --git a/qcsrc/common/weapons/weapon/blaster.qc b/qcsrc/common/weapons/weapon/blaster.qc index d426ae51e9..6ce90db494 100644 --- a/qcsrc/common/weapons/weapon/blaster.qc +++ b/qcsrc/common/weapons/weapon/blaster.qc @@ -11,6 +11,14 @@ void W_Blaster_Touch(entity this, entity toucher) vector force_xyzscale = '1 1 1'; force_xyzscale.z = WEP_CVAR_PRI(WEP_BLASTER, force_zscale); + // slightly hacky but probably not worth adding a parameter for this special case + bool zero_damageforcescale = false; + if (autocvar_g_projectiles_interact == 1 && (toucher.flags & FL_PROJECTILE) && !toucher.damageforcescale) + { + toucher.damageforcescale = 1; + zero_damageforcescale = true; + } + RadiusDamageForSource( this, (this.origin + (this.mins + this.maxs) * 0.5), @@ -29,6 +37,9 @@ void W_Blaster_Touch(entity this, entity toucher) toucher ); + if (zero_damageforcescale) + toucher.damageforcescale = 0; + delete(this); } diff --git a/qcsrc/server/weapons/common.qc b/qcsrc/server/weapons/common.qc index 252f83dc2a..09ad21ed4f 100644 --- a/qcsrc/server/weapons/common.qc +++ b/qcsrc/server/weapons/common.qc @@ -150,9 +150,18 @@ bool SUB_NoImpactCheck(entity this, entity toucher) bool WarpZone_Projectile_Touch_ImpactFilter_Callback(entity this, entity toucher) { - // owner check if(toucher && toucher == this.owner) return true; + + if(autocvar_g_projectiles_interact == 1 && toucher.classname == "blasterbolt") + { + if (this.movetype == MOVETYPE_BOUNCE || this.movetype == MOVETYPE_BOUNCEMISSILE) + // We'll bounce off it due to limitations so let it deflect us + // to hide the problem, see PROJECTILE_MAKETRIGGER. + gettouch(toucher)(toucher, this); + return true; + } + if(SUB_NoImpactCheck(this, toucher)) { if(this.classname == "nade") diff --git a/qcsrc/server/weapons/common.qh b/qcsrc/server/weapons/common.qh index 779226be3d..40b576108c 100644 --- a/qcsrc/server/weapons/common.qh +++ b/qcsrc/server/weapons/common.qh @@ -1,6 +1,7 @@ #pragma once int autocvar_g_projectiles_damage; +int autocvar_g_projectiles_interact = 2; bool autocvar_g_projectiles_keep_owner; float autocvar_sv_strengthsound_antispam_refire_threshold; float autocvar_sv_strengthsound_antispam_time; @@ -26,7 +27,16 @@ bool WarpZone_Projectile_Touch_ImpactFilter_Callback(entity this, entity toucher #define PROJECTILE_TOUCH(e,t) MACRO_BEGIN if (WarpZone_Projectile_Touch(e,t)) return; MACRO_END -#define PROJECTILE_MAKETRIGGER(e) (e).solid = SOLID_CORPSE; (e).dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE +// FIXME: some behaviours can't be achieved or would require kludges in physics code, +// eg we can't make electro bolts hit electro orbs only (without causing other problems) when g_projectiles_interact == 1, +// see also WarpZone_Projectile_Touch_ImpactFilter_Callback(). +// Ideally, extend engine to support any combination of 'hit a and b but not x or y' and 'take hits from c and d but not w or z'. +#define PROJECTILE_MAKETRIGGER(e) \ + (e).solid = SOLID_CORPSE; \ + (e).dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; \ + if (!autocvar_g_projectiles_interact || (autocvar_g_projectiles_interact == 1 && (e).classname != "blasterbolt")) \ + (e).clipgroup = FL_PROJECTILE + // when doing this, hagar can go through clones // #define PROJECTILE_MAKETRIGGER(e) (e).solid = SOLID_BBOX -- 2.39.5