From 64089d583d5be541d7a829146879c3bc61d1930e Mon Sep 17 00:00:00 2001 From: div0 Date: Sun, 8 Nov 2009 08:45:44 +0000 Subject: [PATCH] now with REAL linear falloff (old formula was wrong) git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8238 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/balance.cfg | 3 +- data/balance25.cfg | 3 +- data/balanceHavoc.cfg | 3 +- data/balanceNexrun.cfg | 3 +- data/balanceSamual.cfg | 3 +- data/qcsrc/common/mathlib.qc | 2 +- data/qcsrc/server/cl_weaponsystem.qc | 164 ++++++++++++++++----------- 7 files changed, 107 insertions(+), 74 deletions(-) diff --git a/data/balance.cfg b/data/balance.cfg index 951691c13..93857ab28 100644 --- a/data/balance.cfg +++ b/data/balance.cfg @@ -184,7 +184,8 @@ set g_projectiles_spread_style 0 // 2: forward + solid circle // 3: forward + normal distribution 3D - varies velocity // 4: forward + normal distribution on a plane -// 5: forward + circle with linear falloff +// 5: forward + circle with 1-r falloff +// 6: forward + circle with 1-r^2 falloff set g_balance_falldamage_deadminspeed 150 set g_balance_falldamage_minspeed 1400 set g_balance_falldamage_factor 0.15 diff --git a/data/balance25.cfg b/data/balance25.cfg index 0d7e29281..51edf6ffc 100644 --- a/data/balance25.cfg +++ b/data/balance25.cfg @@ -184,7 +184,8 @@ set g_projectiles_spread_style 0 // 2: forward + solid circle // 3: forward + normal distribution 3D - varies velocity // 4: forward + normal distribution on a plane -// 5: forward + circle with linear falloff +// 5: forward + circle with 1-r falloff +// 6: forward + circle with 1-r^2 falloff set g_balance_falldamage_deadminspeed 150 set g_balance_falldamage_minspeed 1400 set g_balance_falldamage_factor 0.15 diff --git a/data/balanceHavoc.cfg b/data/balanceHavoc.cfg index 5711b61fb..b4cd15d72 100644 --- a/data/balanceHavoc.cfg +++ b/data/balanceHavoc.cfg @@ -184,7 +184,8 @@ set g_projectiles_spread_style 0 // 2: forward + solid circle // 3: forward + normal distribution 3D - varies velocity // 4: forward + normal distribution on a plane -// 5: forward + circle with linear falloff +// 5: forward + circle with 1-r falloff +// 6: forward + circle with 1-r^2 falloff set g_balance_falldamage_deadminspeed 150 set g_balance_falldamage_minspeed 1400 set g_balance_falldamage_factor 0.15 diff --git a/data/balanceNexrun.cfg b/data/balanceNexrun.cfg index bd9a5d770..16c3d2abe 100644 --- a/data/balanceNexrun.cfg +++ b/data/balanceNexrun.cfg @@ -185,7 +185,8 @@ set g_projectiles_spread_style 4 // 2: forward + solid circle // 3: forward + normal distribution 3D - varies velocity // 4: forward + normal distribution on a plane -// 5: forward + circle with linear falloff +// 5: forward + circle with 1-r falloff +// 6: forward + circle with 1-r^2 falloff set g_balance_falldamage_deadminspeed 150 set g_balance_falldamage_minspeed 675 set g_balance_falldamage_factor 0.25 diff --git a/data/balanceSamual.cfg b/data/balanceSamual.cfg index e087f720c..8827f55ba 100644 --- a/data/balanceSamual.cfg +++ b/data/balanceSamual.cfg @@ -185,7 +185,8 @@ set g_projectiles_spread_style 0 // 2: forward + solid circle // 3: forward + normal distribution 3D - varies velocity // 4: forward + normal distribution on a plane -// 5: forward + circle with linear falloff +// 5: forward + circle with 1-r falloff +// 6: forward + circle with 1-r^2 falloff set g_balance_falldamage_deadminspeed 150 set g_balance_falldamage_minspeed 1400 set g_balance_falldamage_factor 0.15 diff --git a/data/qcsrc/common/mathlib.qc b/data/qcsrc/common/mathlib.qc index 33168e764..978fa8dd2 100644 --- a/data/qcsrc/common/mathlib.qc +++ b/data/qcsrc/common/mathlib.qc @@ -158,7 +158,7 @@ float scalbn(float x, int n) float cbrt(float x) { - return pow(x, 1.0/3.0); + return copysign(pow(fabs(x), 1.0/3.0), x); } float hypot(float x, float y) { diff --git a/data/qcsrc/server/cl_weaponsystem.qc b/data/qcsrc/server/cl_weaponsystem.qc index 1434712e2..67a982373 100644 --- a/data/qcsrc/server/cl_weaponsystem.qc +++ b/data/qcsrc/server/cl_weaponsystem.qc @@ -1266,6 +1266,64 @@ vector cliptoplane(vector v, vector p) return v - (v * p) * p; } +vector solve_cubic_pq(float p, float q) +{ + float D, u, v, a; + D = q*q/4.0 + p*p*p/27.0; + if(D < 0) + { + // irreducibilis + a = 1.0/3.0 * acos(-q/2.0 * sqrt(-27.0/(p*p*p))); + u = sqrt(-4.0/3.0 * p); + // a in range 0..pi/3 + // cos(a) + // cos(a + 2pi/3) + // cos(a + 4pi/3) + return + u * + ( + '1 0 0' * cos(a + 2.0/3.0*M_PI) + + + '0 1 0' * cos(a + 4.0/3.0*M_PI) + + + '0 0 1' * cos(a) + ); + } + else if(D == 0) + { + // simple + if(p == 0) + return '0 0 0'; + u = 3*q/p; + v = -u/2; + if(u >= v) + return '1 1 0' * v + '0 0 1' * u; + else + return '0 1 1' * v + '1 0 0' * u; + } + else + { + // cardano + u = cbrt(-q/2.0 + sqrt(D)); + v = cbrt(-q/2.0 - sqrt(D)); + return '1 1 1' * (u + v); + } +} +vector solve_cubic_abcd(float a, float b, float c, float d) +{ + // y = 3*a*x + b + // x = (y - b) / 3a + float p, q; + vector v; + p = (9*a*c - 3*b*b); + q = (27*a*a*d - 9*a*b*c + 2*b*b*b); + v = solve_cubic_pq(p, q); + v = (v - b * '1 1 1') * (1.0 / (3.0 * a)); + if(a < 0) + v += '1 0 -1' * (v_z - v_x); // swap x, z + return v; +} + vector findperpendicular(vector v) { vector p; @@ -1279,30 +1337,18 @@ vector W_CalculateProjectileSpread(vector forward, float spread) { float sigma; vector v1, v2; - float dx, dy, r, t; + float dx, dy, r; float sstyle; if(spread <= 0) return forward; sstyle = cvar("g_projectiles_spread_style"); + if(sstyle == 0) { // this is the baseline for the spread value! // standard deviation: sqrt(2/5) + // density function: sqrt(1-r^2) return forward + randomvec() * spread; - /* - (%i1) integrate(r^2 * 2*%pi*r * sqrt(1-r^2), r, 0, 1); - 4 %pi - (%o1) ----- - 15 - (%i2) integrate(2*%pi*r * sqrt(1-r^2), r, 0, 1); - 2 %pi - (%o2) ----- - 3 - (%i3) %o1/%o2; - 2 - (%o3) - - 5 - */ } else if(sstyle == 1) { @@ -1315,27 +1361,16 @@ vector W_CalculateProjectileSpread(vector forward, float spread) sigma = spread * 0.89442719099991587855; // match baseline stddev v1 = findperpendicular(forward); v2 = cross(forward, v1); - do - { - dx = -1 + 2 * random(); - dy = -1 + 2 * random(); - } - while(dx * dx + dy * dy >= 1); - return normalize(forward + (v1 * dx + v2 * dy) * sigma); - /* - (%i4) integrate(r^2 * 2*%pi*r, r, 0, 1); - %pi - (%o4) --- - 2 - (%i5) integrate(2*%pi*r, r, 0, 1); - (%o5) %pi - (%i6) %o4 / %o5; - 1 - (%o6) - - 2 - */ + // random point on unit circle + dx = random() * 2 * M_PI; + dy = sin(dx); + dx = cos(dx); + // radius in our dist function + r = random(); + r = sqrt(r); + return normalize(forward + (v1 * dx + v2 * dy) * r * sigma); } - else if(sstyle == 3) + else if(sstyle == 3) // gauss 3d { sigma = spread * 0.63245553203368; // match baseline stddev v1 = forward; @@ -1344,7 +1379,7 @@ vector W_CalculateProjectileSpread(vector forward, float spread) v1_z += gsl_ran_gaussian(sigma); return v1; } - else if(sstyle == 4) + else if(sstyle == 4) // gauss 2d { sigma = spread * 0.63245553203368; // match baseline stddev v1_x = gsl_ran_gaussian(sigma); @@ -1352,44 +1387,37 @@ vector W_CalculateProjectileSpread(vector forward, float spread) v1_z = gsl_ran_gaussian(sigma); return normalize(forward + cliptoplane(v1, forward)); } - else if(sstyle == 5) + else if(sstyle == 5) // 1-r { sigma = spread * 1.154700538379252; // match baseline stddev v1 = findperpendicular(forward); v2 = cross(forward, v1); - do - { - dx = -1 + 2 * random(); - dy = -1 + 2 * random(); - } - while(dx * dx + dy * dy >= 1); - // now we want a LINEAR falloff, though... - // i.e. radius X has a multiplied-in probability multiplier of 1-X - r = sqrt(dx * dx + dy * dy); - if(r > 0) - { - t = 1 - sqrt(1 - r); - dx *= t/r; - dy *= t/r; - } - return normalize(forward + (v1 * dx + v2 * dy) * sigma); - /* - (%i7) integrate(r^2 * 2*%pi*r * (1-r), r, 0, 1); - %pi - (%o7) --- - 10 - (%i8) integrate(2*%pi*r * (1-r), r, 0, 1); - %pi - (%o8) --- - 3 - (%i9) %o7 / %o8; - 3 - (%o9) -- - 10 - */ + // random point on unit circle + dx = random() * 2 * M_PI; + dy = sin(dx); + dx = cos(dx); + // radius in our dist function + r = random(); + r = solve_cubic_abcd(-2, 3, 0, -r) * '0 1 0'; + return normalize(forward + (v1 * dx + v2 * dy) * r * sigma); + } + else if(sstyle == 6) // 1-r^2 + { + sigma = spread * 1.095445115010332; // match baseline stddev + v1 = findperpendicular(forward); + v2 = cross(forward, v1); + // random point on unit circle + dx = random() * 2 * M_PI; + dy = sin(dx); + dx = cos(dx); + // radius in our dist function + r = random(); + r = sqrt(1 - r); + r = sqrt(1 - r); + return normalize(forward + (v1 * dx + v2 * dy) * r * sigma); } else - error("g_projectiles_spread_style must be 0 (sphere), 1 (flattened sphere), 2 (circle), 3 (gauss 3D), 4 (gauss plane), 5 (linear falloff)!"); + error("g_projectiles_spread_style must be 0 (sphere), 1 (flattened sphere), 2 (circle), 3 (gauss 3D), 4 (gauss plane), 5 (linear falloff), 6 (quadratic falloff)!"); return '0 0 0'; } -- 2.39.2