set g_balance_laser_primary_damage 25
set g_balance_laser_primary_edgedamage 12.5
set g_balance_laser_primary_force 300
-set g_balance_laser_primary_radius 70
+set g_balance_laser_primary_radius 4000
set g_balance_laser_primary_speed 6000
-set g_balance_laser_primary_spread 0
+set g_balance_laser_primary_spread 0.12
set g_balance_laser_primary_refire 0.7
set g_balance_laser_primary_animtime 0.2
set g_balance_laser_primary_lifetime 5
//lightradiusfade 50
//lightcolor 1 0.9 0.7
//lightshadow 1
+
+// laser_shockwave_attack
+// used nowhere in code
+effect laser_shockwave_attack
+// glow and light
+//countabsolute 1
+//type smoke
+//color 0xcc0000 0xff0000
+//tex 65 65
+//size 10 15
+//alpha 256 512 6280
+//airfriction 10
+//sizeincrease 1.5
+//stretchfactor 2
+//lightradius 200
+//lightradiusfade 2000
+//lightcolor 3 0.1 0.1
+// electricity
+effect laser_shockwave_attack
+count 1
+type spark
+color 0xb44215 0xff0000
+tex 43 43
+size 5 7
+bounce 0
+alpha 4096 4096 20000
+airfriction 1
+originjitter 2 2 2
+velocityjitter 10 10 10
+velocitymultiplier 10
+sizeincrease 1.5
+stretchfactor 2.3
+rotate -180 180 4000 -4000
+// fire
+effect laser_shockwave_attack
+count 1
+type spark
+color 0xff4200 0xff0000
+tex 8 15
+size 7 9
+bounce 0
+alpha 4096 4096 20000
+airfriction 1
+originjitter 2 2 2
+velocityjitter 10 10 10
+velocitymultiplier 10
+sizeincrease 1.5
+stretchfactor 2
+
+// new_laser_impact
+// used nowhere in code
+// decal
+effect new_laser_impact
+countabsolute 1
+type decal
+tex 8 16
+size 72 72
+alpha 256 256 0
+originjitter 2 2 2
+// flare effect
+//effect new_laser_impact
+//countabsolute 1
+//type static
+//tex 39 39
+//color 0xFF2010 0xFF2010
+//alpha 256 256 1024
+//size 24 24
+// sparks that rapidly expand and rapidly slow down to form an interesting spherical effect
+effect new_laser_impact
+count 128
+type spark
+color 0x800000 0xFF8020
+alpha 256 256 1024
+size 4 4
+bounce 1.5
+gravity 0.5
+airfriction 1
+liquidfriction 1
+originjitter 20 20 20
+velocityjitter 256 256 256
\ No newline at end of file
cl_notice_read();
bHandled = true;
break;
+ case TE_CSQC_SHOCKWAVEPARTICLE:
+ Net_ReadShockwaveParticle();
+ bHandled = true;
+ break;
default:
// No special logic for this temporary entity; return 0 so the engine can handle it
bHandled = false;
else
WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum("nex_beam"), shotorg, endpos, charge, 1);
}
+
+void Net_ReadShockwaveParticle()
+{
+ vector shotorg, endpos, deviation;
+ shotorg_x = ReadCoord(); shotorg_y = ReadCoord(); shotorg_z = ReadCoord();
+ endpos_x = ReadCoord(); endpos_y = ReadCoord(); endpos_z = ReadCoord();
+ float spread = ReadByte() / 255.0;
+
+ float counter, shots;
+
+ shots = 10;
+
+ vector shotdir = normalize(endpos - shotorg);
+ makevectors(shotdir);
+ vector right = v_right;
+ vector up = v_up;
+
+ for(counter = 0; counter < shots; ++counter)
+ {
+ deviation = '0 0 0';
+ makevectors('0 360 0' * (0.75 + (counter - 0.5) / shots));
+ deviation_y = v_forward_x;
+ deviation_z = v_forward_y;
+ deviation = deviation * spread;
+ print("v_forward = ", vtos(deviation), ".\n");
+ deviation = ((shotdir + (right * deviation_y) + (up * deviation_z)) * 1000);
+
+ //deviation = W_CalculateSpread(shotdir, spread, 1, cvar("g_projectiles_spread_style"));
+ //print("deviation = ", vtos(deviation), ".\n");
+
+ pointparticles(particleeffectnum("laser_shockwave_attack"), shotorg, deviation, 1);
+ }
+
+ for(counter = 0; counter < shots; ++counter)
+ {
+ //deviation = '0 0 0';
+ //makevectors('0 360 0' * (0.75 + (counter - 0.5) / (shots - 1)));
+ //deviation_y = v_forward_x;
+ //deviation_z = v_forward_y;
+ //deviation = deviation * spread;
+ //print("v_forward = ", vtos(deviation), ".\n");
+ //deviation = ((shotdir + (right * deviation_y) + (up * deviation_z)) * 1000);
+
+ deviation = W_CalculateSpread(shotdir, spread, 1, cvar("g_projectiles_spread_style"));
+ //print("deviation = ", vtos(deviation), ".\n");
+
+ pointparticles(particleeffectnum("laser_shockwave_attack"), shotorg, deviation * 1000, 1);
+ }
+
+ //print("definitely doing the effect.\n");
+
+ //WarpZone_TrailParticles(world, particleeffectnum("nex_beam"), shotorg, endpos);
+}
+
const float TE_CSQC_LIGHTNINGARC = 105;
const float TE_CSQC_TEAMNAGGER = 106;
const float TE_CSQC_PINGPLREPORT = 107;
+const float TE_CSQC_SHOCKWAVEPARTICLE = 121;
const float TE_CSQC_ANNOUNCE = 110;
const float TE_CSQC_TARGET_MUSIC = 111;
const float TE_CSQC_KILLNOTIFY = 112;
return valstr;
}
+float dotproduct(vector a, vector b)
+{
+ return a_x * b_x + a_y * b_y + a_z * b_z;
+}
+
vector cross(vector a, vector b)
{
return
// (3.5, [0.2..2.3])
// (4, 1)
}
+
+#ifndef MENUQC
+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;
+ p_x = v_z;
+ p_y = -v_x;
+ p_z = v_y;
+ return normalize(cliptoplane(p, v));
+}
+
+vector W_CalculateSpread(vector forward, float spread, float spreadfactor, float spreadstyle)
+{
+ float sigma;
+ vector v1, v2;
+ float dx, dy, r;
+ float sstyle;
+ spread *= spreadfactor; //g_weaponspreadfactor;
+ if(spread <= 0)
+ return forward;
+ sstyle = spreadstyle; //autocvar_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;
+ }
+ else if(sstyle == 1)
+ {
+ // same thing, basically
+ return normalize(forward + cliptoplane(randomvec() * spread, forward));
+ }
+ else if(sstyle == 2)
+ {
+ // circle spread... has at sigma=1 a standard deviation of sqrt(1/2)
+ sigma = spread * 0.89442719099991587855; // 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(r);
+ return normalize(forward + (v1 * dx + v2 * dy) * r * sigma);
+ }
+ else if(sstyle == 3) // gauss 3d
+ {
+ sigma = spread * 0.44721359549996; // match baseline stddev
+ // note: 2D gaussian has sqrt(2) times the stddev of 1D, so this factor is right
+ v1 = forward;
+ v1_x += gsl_ran_gaussian(sigma);
+ v1_y += gsl_ran_gaussian(sigma);
+ v1_z += gsl_ran_gaussian(sigma);
+ return v1;
+ }
+ else if(sstyle == 4) // gauss 2d
+ {
+ sigma = spread * 0.44721359549996; // match baseline stddev
+ // note: 2D gaussian has sqrt(2) times the stddev of 1D, so this factor is right
+ v1_x = gsl_ran_gaussian(sigma);
+ v1_y = gsl_ran_gaussian(sigma);
+ v1_z = gsl_ran_gaussian(sigma);
+ return normalize(forward + cliptoplane(v1, forward));
+ }
+ else if(sstyle == 5) // 1-r
+ {
+ sigma = spread * 1.154700538379252; // 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 = 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 if(sstyle == 7) // (1-r) (2-r)
+ {
+ sigma = spread * 1.224744871391589; // 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 = 1 - sqrt(r);
+ r = 1 - sqrt(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), 6 (quadratic falloff), 7 (stronger falloff)!");
+ return '0 0 0';
+ /*
+ * how to derive falloff functions:
+ * rho(r) := (2-r) * (1-r);
+ * a : 0;
+ * b : 1;
+ * rhor(r) := r * rho(r);
+ * cr(t) := integrate(rhor(r), r, a, t);
+ * scr(t) := integrate(rhor(r) * r^2, r, a, t);
+ * variance : scr(b) / cr(b);
+ * solve(cr(r) = rand * cr(b), r), programmmode:false;
+ * sqrt(0.4 / variance), numer;
+ */
+}
+#endif
string ScoreString(float vflags, float value);
+float dotproduct(vector a, vector b);
vector cross(vector a, vector b);
void compressShortVector_init();
// for marking written-to values as unused where it's a good idea to do this
noref float unused_float;
-
-
// a function f with:
// f(0) = 0
// f(1) = 1
// because if this is the case, the function is not usable for platforms
// as it may exceed 0..1 bounds, or go in reverse
float cubic_speedfunc_is_sane(float startspeedfactor, float endspeedfactor);
+
+#ifndef MENUQC
+vector W_CalculateSpread(vector forward, float spread, float spreadfactor, float spreadstyle)
+#endif
//self = self.owner;
setorigin(self,self.owner.origin + v_forward * 32);
- RadiusDamage(self, self.owner, autocvar_g_monster_zombie_attack_stand_damage,autocvar_g_monster_zombie_attack_stand_damage,16,self, autocvar_g_monster_zombie_attack_stand_force,DEATH_TURRET,world);
- //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)
+ RadiusDamage(self, self.owner, autocvar_g_monster_zombie_attack_stand_damage,autocvar_g_monster_zombie_attack_stand_damage,16,self, world, autocvar_g_monster_zombie_attack_stand_force,DEATH_TURRET,world);
+ //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, float deathtype, entity directhitentity)
//self = oldself;
float autocvar_g_balance_laser_primary_force_other_scale;
float autocvar_g_balance_laser_primary_force_velocitybias;
float autocvar_g_balance_laser_primary_force_zscale;
+var float autocvar_g_balance_laser_primary_jumpradius = 150;
float autocvar_g_balance_laser_primary_lifetime;
float autocvar_g_balance_laser_primary_radius;
float autocvar_g_balance_laser_primary_refire;
float autocvar_g_balance_laser_primary_shotangle;
float autocvar_g_balance_laser_primary_speed;
+var float autocvar_g_balance_laser_primary_spread = 0.15;
float autocvar_g_balance_laser_secondary;
float autocvar_g_balance_laser_secondary_animtime;
float autocvar_g_balance_laser_secondary_damage;
setorigin(e2, org);
pointparticles(particleeffectnum("rocket_explode"), org, '0 0 0', 1);
sound(e2, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
- RadiusDamage(e2, e, 1000, 0, 128, e, 500, DEATH_CHEAT, world);
+ RadiusDamage(e2, e, 1000, 0, 128, e, world, 500, DEATH_CHEAT, world);
remove(e2);
}
print("404 Sportsmanship not found.\n");
entity e;
e = spawn();
setorigin(e, org);
- RadiusDamage(e, world, g_touchexplode_damage, g_touchexplode_edgedamage, g_touchexplode_radius, world, g_touchexplode_force, DEATH_TOUCHEXPLODE, world);
+ RadiusDamage(e, world, g_touchexplode_damage, g_touchexplode_edgedamage, g_touchexplode_radius, world, world, g_touchexplode_force, DEATH_TOUCHEXPLODE, world);
remove(e);
}
}
}
-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;
- p_x = v_z;
- p_y = -v_x;
- p_z = v_y;
- return normalize(cliptoplane(p, v));
-}
-
-vector W_CalculateProjectileSpread(vector forward, float spread)
-{
- float sigma;
- vector v1, v2;
- float dx, dy, r;
- float sstyle;
- spread *= g_weaponspreadfactor;
- if(spread <= 0)
- return forward;
- sstyle = autocvar_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;
- }
- else if(sstyle == 1)
- {
- // same thing, basically
- return normalize(forward + cliptoplane(randomvec() * spread, forward));
- }
- else if(sstyle == 2)
- {
- // circle spread... has at sigma=1 a standard deviation of sqrt(1/2)
- sigma = spread * 0.89442719099991587855; // 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(r);
- return normalize(forward + (v1 * dx + v2 * dy) * r * sigma);
- }
- else if(sstyle == 3) // gauss 3d
- {
- sigma = spread * 0.44721359549996; // match baseline stddev
- // note: 2D gaussian has sqrt(2) times the stddev of 1D, so this factor is right
- v1 = forward;
- v1_x += gsl_ran_gaussian(sigma);
- v1_y += gsl_ran_gaussian(sigma);
- v1_z += gsl_ran_gaussian(sigma);
- return v1;
- }
- else if(sstyle == 4) // gauss 2d
- {
- sigma = spread * 0.44721359549996; // match baseline stddev
- // note: 2D gaussian has sqrt(2) times the stddev of 1D, so this factor is right
- v1_x = gsl_ran_gaussian(sigma);
- v1_y = gsl_ran_gaussian(sigma);
- v1_z = gsl_ran_gaussian(sigma);
- return normalize(forward + cliptoplane(v1, forward));
- }
- else if(sstyle == 5) // 1-r
- {
- sigma = spread * 1.154700538379252; // 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 = 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 if(sstyle == 7) // (1-r) (2-r)
- {
- sigma = spread * 1.224744871391589; // 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 = 1 - sqrt(r);
- r = 1 - sqrt(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), 6 (quadratic falloff), 7 (stronger falloff)!");
- return '0 0 0';
- /*
- * how to derive falloff functions:
- * rho(r) := (2-r) * (1-r);
- * a : 0;
- * b : 1;
- * rhor(r) := r * rho(r);
- * cr(t) := integrate(rhor(r), r, a, t);
- * scr(t) := integrate(rhor(r) * r^2, r, a, t);
- * variance : scr(b) / cr(b);
- * solve(cr(r) = rand * cr(b), r), programmmode:false;
- * sqrt(0.4 / variance), numer;
- */
-}
-
#if 0
float mspercallsum;
float mspercallsstyle;
}
mspercallsum -= gettime(GETTIME_HIRES);
#endif
- dir = W_CalculateProjectileSpread(dir, spread);
+ dir = W_CalculateSpread(dir, spread, g_weaponspreadfactor, autocvar_g_projectiles_spread_style);
#if 0
mspercallsum += gettime(GETTIME_HIRES);
mspercallcount += 1;
sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
if(self.dmg)
- RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, self.dmg_force, DEATH_HURTTRIGGER, world);
+ RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER, world);
if(self.cnt)
pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
}
float RadiusDamage_running;
-float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, float deathtype, entity directhitentity)
// Returns total damage applies to creatures
{
entity targ;
- vector blastorigin;
vector force;
float total_damage_to_creatures;
entity next;
tfloordmg = autocvar_g_throughfloor_damage;
tfloorforce = autocvar_g_throughfloor_force;
- blastorigin = (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5);
total_damage_to_creatures = 0;
if(deathtype != (WEP_HOOK | HITTYPE_SECONDARY | HITTYPE_BOUNCE)) // only send gravity bomb damage once
if(DEATH_WEAPONOF(deathtype) != WEP_TUBA) // do not send tuba damage (bandwidth hog)
{
- force = inflictor.velocity;
+ force = inflictorvelocity;
if(vlen(force) == 0)
force = '0 0 -1';
else
force = normalize(force);
if(forceintensity >= 0)
- Damage_DamageInfo(blastorigin, coredamage, edgedamage, rad, forceintensity * force, deathtype, 0, attacker);
+ Damage_DamageInfo(inflictororigin, coredamage, edgedamage, rad, forceintensity * force, deathtype, 0, attacker);
else
- Damage_DamageInfo(blastorigin, coredamage, edgedamage, -rad, (-forceintensity) * force, deathtype, 0, attacker);
+ Damage_DamageInfo(inflictororigin, coredamage, edgedamage, -rad, (-forceintensity) * force, deathtype, 0, attacker);
}
stat_damagedone = 0;
- targ = WarpZone_FindRadius (blastorigin, rad + MAX_DAMAGEEXTRARADIUS, FALSE);
+ targ = WarpZone_FindRadius (inflictororigin, rad + MAX_DAMAGEEXTRARADIUS, FALSE);
while (targ)
{
next = targ.chain;
- if (targ != inflictor)
- if (ignore != targ) if(targ.takedamage)
+ if ((targ != inflictor) || inflictorselfdamage)
+ if (((cantbe != targ) && !mustbe) || (mustbe == targ))
+ if (targ.takedamage)
+ {
+ vector nearest;
+ vector diff;
+ float power;
+
+ // LordHavoc: measure distance to nearest point on target (not origin)
+ // (this guarentees 100% damage on a touch impact)
+ nearest = targ.WarpZone_findradius_nearest;
+ diff = targ.WarpZone_findradius_dist;
+ // round up a little on the damage to ensure full damage on impacts
+ // and turn the distance into a fraction of the radius
+ power = 1 - ((vlen (diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
+ //bprint(" ");
+ //bprint(ftos(power));
+ //if (targ == attacker)
+ // print(ftos(power), "\n");
+ if (power > 0)
{
- vector nearest;
- vector diff;
- float power;
-
- // LordHavoc: measure distance to nearest point on target (not origin)
- // (this guarentees 100% damage on a touch impact)
- nearest = targ.WarpZone_findradius_nearest;
- diff = targ.WarpZone_findradius_dist;
- // round up a little on the damage to ensure full damage on impacts
- // and turn the distance into a fraction of the radius
- power = 1 - ((vlen (diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
- //bprint(" ");
- //bprint(ftos(power));
- //if (targ == attacker)
- // print(ftos(power), "\n");
- if (power > 0)
+ float finaldmg;
+ if (power > 1)
+ power = 1;
+ finaldmg = coredamage * power + edgedamage * (1 - power);
+ if (finaldmg > 0)
{
- float finaldmg;
- if (power > 1)
- power = 1;
- finaldmg = coredamage * power + edgedamage * (1 - power);
- if (finaldmg > 0)
- {
- float a;
- float c;
- vector hitloc;
- vector myblastorigin;
- vector center;
+ float a;
+ float c;
+ vector hitloc;
+ vector myblastorigin;
+ vector center;
- myblastorigin = WarpZone_TransformOrigin(targ, blastorigin);
+ myblastorigin = WarpZone_TransformOrigin(targ, inflictororigin);
- // if it's a player, use the view origin as reference
- if (targ.classname == "player")
- center = targ.origin + targ.view_ofs;
- else
- center = targ.origin + (targ.mins + targ.maxs) * 0.5;
+ // if it's a player, use the view origin as reference
+ if (targ.classname == "player")
+ center = targ.origin + targ.view_ofs;
+ else
+ center = targ.origin + (targ.mins + targ.maxs) * 0.5;
- force = normalize(center - myblastorigin);
- force = force * (finaldmg / coredamage) * forceintensity;
- hitloc = nearest;
+ force = normalize(center - myblastorigin);
+ force = force * (finaldmg / coredamage) * forceintensity;
+ hitloc = nearest;
- if(targ != directhitentity)
- {
- float hits;
- float total;
- float hitratio;
- float mininv_f, mininv_d;
+ if(targ != directhitentity)
+ {
+ float hits;
+ float total;
+ float hitratio;
+ float mininv_f, mininv_d;
- // test line of sight to multiple positions on box,
- // and do damage if any of them hit
- hits = 0;
+ // test line of sight to multiple positions on box,
+ // and do damage if any of them hit
+ hits = 0;
- // we know: max stddev of hitratio = 1 / (2 * sqrt(n))
- // so for a given max stddev:
- // n = (1 / (2 * max stddev of hitratio))^2
+ // we know: max stddev of hitratio = 1 / (2 * sqrt(n))
+ // so for a given max stddev:
+ // n = (1 / (2 * max stddev of hitratio))^2
- mininv_d = (finaldmg * (1-tfloordmg)) / autocvar_g_throughfloor_damage_max_stddev;
- mininv_f = (vlen(force) * (1-tfloorforce)) / autocvar_g_throughfloor_force_max_stddev;
+ mininv_d = (finaldmg * (1-tfloordmg)) / autocvar_g_throughfloor_damage_max_stddev;
+ mininv_f = (vlen(force) * (1-tfloorforce)) / autocvar_g_throughfloor_force_max_stddev;
- if(autocvar_g_throughfloor_debug)
- print(sprintf("THROUGHFLOOR: D=%f F=%f max(dD)=1/%f max(dF)=1/%f", finaldmg, vlen(force), mininv_d, mininv_f));
+ if(autocvar_g_throughfloor_debug)
+ print(sprintf("THROUGHFLOOR: D=%f F=%f max(dD)=1/%f max(dF)=1/%f", finaldmg, vlen(force), mininv_d, mininv_f));
- total = 0.25 * pow(max(mininv_f, mininv_d), 2);
+ total = 0.25 * pow(max(mininv_f, mininv_d), 2);
- if(autocvar_g_throughfloor_debug)
- print(sprintf(" steps=%f", total));
+ if(autocvar_g_throughfloor_debug)
+ print(sprintf(" steps=%f", total));
- if (targ.classname == "player")
- total = ceil(bound(autocvar_g_throughfloor_min_steps_player, total, autocvar_g_throughfloor_max_steps_player));
- else
- total = ceil(bound(autocvar_g_throughfloor_min_steps_other, total, autocvar_g_throughfloor_max_steps_other));
+ if (targ.classname == "player")
+ total = ceil(bound(autocvar_g_throughfloor_min_steps_player, total, autocvar_g_throughfloor_max_steps_player));
+ else
+ total = ceil(bound(autocvar_g_throughfloor_min_steps_other, total, autocvar_g_throughfloor_max_steps_other));
- if(autocvar_g_throughfloor_debug)
- print(sprintf(" steps=%f dD=%f dF=%f", total, finaldmg * (1-tfloordmg) / (2 * sqrt(total)), vlen(force) * (1-tfloorforce) / (2 * sqrt(total))));
+ if(autocvar_g_throughfloor_debug)
+ print(sprintf(" steps=%f dD=%f dF=%f", total, finaldmg * (1-tfloordmg) / (2 * sqrt(total)), vlen(force) * (1-tfloorforce) / (2 * sqrt(total))));
- for(c = 0; c < total; ++c)
+ for(c = 0; c < total; ++c)
+ {
+ //traceline(targ.WarpZone_findradius_findorigin, nearest, MOVE_NOMONSTERS, inflictor);
+ WarpZone_TraceLine(inflictororigin, WarpZone_UnTransformOrigin(targ, nearest), MOVE_NOMONSTERS, inflictor);
+ if (trace_fraction == 1 || trace_ent == targ)
{
- //traceline(targ.WarpZone_findradius_findorigin, nearest, MOVE_NOMONSTERS, inflictor);
- WarpZone_TraceLine(blastorigin, WarpZone_UnTransformOrigin(targ, nearest), MOVE_NOMONSTERS, inflictor);
- if (trace_fraction == 1 || trace_ent == targ)
- {
- ++hits;
- if (hits > 1)
- hitloc = hitloc + nearest;
- else
- hitloc = nearest;
- }
- nearest_x = targ.origin_x + targ.mins_x + random() * targ.size_x;
- nearest_y = targ.origin_y + targ.mins_y + random() * targ.size_y;
- nearest_z = targ.origin_z + targ.mins_z + random() * targ.size_z;
+ ++hits;
+ if (hits > 1)
+ hitloc = hitloc + nearest;
+ else
+ hitloc = nearest;
}
+ nearest_x = targ.origin_x + targ.mins_x + random() * targ.size_x;
+ nearest_y = targ.origin_y + targ.mins_y + random() * targ.size_y;
+ nearest_z = targ.origin_z + targ.mins_z + random() * targ.size_z;
+ }
- nearest = hitloc * (1 / max(1, hits));
- hitratio = (hits / total);
- a = bound(0, tfloordmg + (1-tfloordmg) * hitratio, 1);
- finaldmg = finaldmg * a;
- a = bound(0, tfloorforce + (1-tfloorforce) * hitratio, 1);
- force = force * a;
+ nearest = hitloc * (1 / max(1, hits));
+ hitratio = (hits / total);
+ a = bound(0, tfloordmg + (1-tfloordmg) * hitratio, 1);
+ finaldmg = finaldmg * a;
+ a = bound(0, tfloorforce + (1-tfloorforce) * hitratio, 1);
+ force = force * a;
- if(autocvar_g_throughfloor_debug)
- print(sprintf(" D=%f F=%f\n", finaldmg, vlen(force)));
- }
+ if(autocvar_g_throughfloor_debug)
+ print(sprintf(" D=%f F=%f\n", finaldmg, vlen(force)));
+ }
- // laser force adjustments :P
- if(DEATH_WEAPONOF(deathtype) == WEP_LASER)
+ // laser force adjustments :P
+ if(DEATH_WEAPONOF(deathtype) == WEP_LASER)
+ {
+ if (targ == attacker)
{
- if (targ == attacker)
+ vector vel;
+
+ float force_zscale;
+ float force_velocitybiasramp;
+ float force_velocitybias;
+
+ force_velocitybiasramp = autocvar_sv_maxspeed;
+ if(deathtype & HITTYPE_SECONDARY)
{
- 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;
+ force_zscale = autocvar_g_balance_laser_secondary_force_zscale;
+ force_velocitybias = autocvar_g_balance_laser_secondary_force_velocitybias;
}
else
{
- if(deathtype & HITTYPE_SECONDARY)
- {
- force *= autocvar_g_balance_laser_secondary_force_other_scale;
- }
- else
- {
- force *= autocvar_g_balance_laser_primary_force_other_scale;
- }
+ force_zscale = autocvar_g_balance_laser_primary_force_zscale;
+ force_velocitybias = autocvar_g_balance_laser_primary_force_velocitybias;
}
- }
- //if (targ == attacker)
- //{
- // print("hits ", ftos(hits), " / ", ftos(total));
- // print(" finaldmg ", ftos(finaldmg), " force ", vtos(force));
- // print(" (", ftos(a), ")\n");
- //}
- if(finaldmg || vlen(force))
+ 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(targ.iscreature)
+ if(deathtype & HITTYPE_SECONDARY)
{
- total_damage_to_creatures += finaldmg;
-
- if(accuracy_isgooddamage(attacker, targ))
- stat_damagedone += finaldmg;
+ force *= autocvar_g_balance_laser_secondary_force_other_scale;
}
-
- if(targ == directhitentity || DEATH_ISSPECIAL(deathtype))
- Damage (targ, inflictor, attacker, finaldmg, deathtype, nearest, force);
else
- Damage (targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, nearest, force);
+ {
+ force *= autocvar_g_balance_laser_primary_force_other_scale;
+ }
}
}
+
+ //if (targ == attacker)
+ //{
+ // print("hits ", ftos(hits), " / ", ftos(total));
+ // print(" finaldmg ", ftos(finaldmg), " force ", vtos(force));
+ // print(" (", ftos(a), ")\n");
+ //}
+ if(finaldmg || vlen(force))
+ {
+ if(targ.iscreature)
+ {
+ total_damage_to_creatures += finaldmg;
+
+ if(accuracy_isgooddamage(attacker, targ))
+ stat_damagedone += finaldmg;
+ }
+
+ if(targ == directhitentity || DEATH_ISSPECIAL(deathtype))
+ Damage (targ, inflictor, attacker, finaldmg, deathtype, nearest, force);
+ else
+ Damage (targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, nearest, force);
+ }
}
}
+ }
targ = next;
}
return total_damage_to_creatures;
}
+float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, float deathtype, entity directhitentity)
+{
+ return RadiusDamageForSource (inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, FALSE, forceintensity, deathtype, directhitentity);
+}
+
.float fire_damagepersec;
.float fire_endtime;
.float fire_deathtype;
self.event_damage = SUB_Null;
#ifdef TURRET_DEBUG
float d;
- d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
+ d = RadiusDamage (self, self.owner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d;
self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
#else
- RadiusDamage (self, self.realowner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
+ RadiusDamage (self, self.realowner, self.owner.shot_dmg, 0, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
#endif
remove(self);
}
#ifdef TURRET_DEBUG
float d;
- d = RadiusDamage (self, self.owner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
+ d = RadiusDamage (self, self.owner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
self.owner.tur_dbg_dmg_t_h = self.owner.tur_dbg_dmg_t_h + d;
self.owner.tur_dbg_dmg_t_f = self.owner.tur_dbg_dmg_t_f + self.owner.shot_dmg;
#else
- RadiusDamage (self, self.realowner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, self.owner.shot_force, self.totalfrags, world);
+ RadiusDamage (self, self.realowner, self.owner.shot_dmg, self.owner.shot_dmg, self.owner.shot_radius, self, world, self.owner.shot_force, self.totalfrags, world);
#endif
remove(self);
}
}
void walker_rocket_explode()
{
- RadiusDamage (self, self.owner, autocvar_g_turrets_unit_walker_std_rocket_dmg, 0, autocvar_g_turrets_unit_walker_std_rocket_radius, self, autocvar_g_turrets_unit_walker_std_rocket_force, DEATH_TURRET_WALKER_ROCKET, world);
+ RadiusDamage (self, self.owner, autocvar_g_turrets_unit_walker_std_rocket_dmg, 0, autocvar_g_turrets_unit_walker_std_rocket_radius, self, world, autocvar_g_turrets_unit_walker_std_rocket_force, DEATH_TURRET_WALKER_ROCKET, world);
remove (self);
}
RadiusDamage (self, self, autocvar_g_vehicle_racer_blowup_coredamage,
autocvar_g_vehicle_racer_blowup_edgedamage,
- autocvar_g_vehicle_racer_blowup_radius, world,
+ autocvar_g_vehicle_racer_blowup_radius, world, world,
autocvar_g_vehicle_racer_blowup_forceintensity,
DEATH_WAKIBLOWUP, world);
{
RadiusDamage (self, self.realowner, autocvar_g_vehicle_raptor_bomblet_damage,
autocvar_g_vehicle_raptor_bomblet_edgedamage,
- autocvar_g_vehicle_raptor_bomblet_radius, world,
+ autocvar_g_vehicle_raptor_bomblet_radius, world, world,
autocvar_g_vehicle_raptor_bomblet_force, DEATH_RAPTOR_BOMB, world);
remove(self);
}
{
self.deadflag = DEAD_DEAD;
self.vehicle_exit(VHEF_NORMAL);
- RadiusDamage (self, self, 250, 15, 250, world, 250, DEATH_WAKIBLOWUP, world);
+ RadiusDamage (self, self, 250, 15, 250, world, world, 250, DEATH_WAKIBLOWUP, world);
self.alpha = -1;
self.movetype = MOVETYPE_NONE;
SUB_SetFade(g1, time, min(autocvar_g_vehicle_spiderbot_respawntime, 10));
SUB_SetFade(g2, time, min(autocvar_g_vehicle_spiderbot_respawntime, 10));
- RadiusDamage (self, self, 250, 15, 250, world, 250, DEATH_SBBLOWUP, world);
+ RadiusDamage (self, self, 250, 15, 250, world, world, 250, DEATH_SBBLOWUP, world);
self.alpha = self.tur_head.alpha = self.gun1.alpha = self.gun2.alpha = -1;
self.movetype = MOVETYPE_NONE;
PROJECTILE_TOUCH;
self.event_damage = SUB_Null;
- RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, self.shot_force, self.totalfrags, other);
+ RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, world, self.shot_force, self.totalfrags, other);
remove (self);
}
// create a small explosion to throw gibs around (if applicable)
//setorigin (explosion, hitloc);
- //RadiusDamage (explosion, self, 10, 0, 50, world, 300, deathtype);
+ //RadiusDamage (explosion, self, 10, 0, 50, world, world, 300, deathtype);
ent.railgunhitloc = '0 0 0';
ent.railgunhitsolidbackup = SOLID_NOT;
e.realowner.crylink_lastgroup = world;
if(e.projectiledeathtype & HITTYPE_SECONDARY)
- RadiusDamage (e, e.realowner, autocvar_g_balance_crylink_secondary_damage * a, autocvar_g_balance_crylink_secondary_edgedamage * a, autocvar_g_balance_crylink_secondary_radius, world, autocvar_g_balance_crylink_secondary_force * a, e.projectiledeathtype, other);
+ RadiusDamage (e, e.realowner, autocvar_g_balance_crylink_secondary_damage * a, autocvar_g_balance_crylink_secondary_edgedamage * a, autocvar_g_balance_crylink_secondary_radius, world, world, autocvar_g_balance_crylink_secondary_force * a, e.projectiledeathtype, other);
else
- RadiusDamage (e, e.realowner, autocvar_g_balance_crylink_primary_damage * a, autocvar_g_balance_crylink_primary_edgedamage * a, autocvar_g_balance_crylink_primary_radius, world, autocvar_g_balance_crylink_primary_force * a, e.projectiledeathtype, other);
+ RadiusDamage (e, e.realowner, autocvar_g_balance_crylink_primary_damage * a, autocvar_g_balance_crylink_primary_edgedamage * a, autocvar_g_balance_crylink_primary_radius, world, world, autocvar_g_balance_crylink_primary_force * a, e.projectiledeathtype, other);
W_Crylink_LinkExplode(e.queuenext, e2);
n = n / autocvar_g_balance_crylink_secondary_shots;
RadiusDamage (e, e.realowner, autocvar_g_balance_crylink_secondary_joinexplode_damage * n,
autocvar_g_balance_crylink_secondary_joinexplode_edgedamage * n,
- autocvar_g_balance_crylink_secondary_joinexplode_radius * n, e.realowner,
+ autocvar_g_balance_crylink_secondary_joinexplode_radius * n, e.realowner, world,
autocvar_g_balance_crylink_secondary_joinexplode_force * n, e.projectiledeathtype, other);
pointparticles(particleeffectnum("crylink_joinexplode"), self.origin, '0 0 0', n);
n = n / autocvar_g_balance_crylink_primary_shots;
RadiusDamage (e, e.realowner, autocvar_g_balance_crylink_primary_joinexplode_damage * n,
autocvar_g_balance_crylink_primary_joinexplode_edgedamage * n,
- autocvar_g_balance_crylink_primary_joinexplode_radius * n, e.realowner,
+ autocvar_g_balance_crylink_primary_joinexplode_radius * n, e.realowner, world,
autocvar_g_balance_crylink_primary_joinexplode_force * n, e.projectiledeathtype, other);
pointparticles(particleeffectnum("crylink_joinexplode"), self.origin, '0 0 0', n);
f = autocvar_g_balance_crylink_primary_bouncedamagefactor;
if(a)
f *= a;
- if (RadiusDamage (self, self.realowner, autocvar_g_balance_crylink_primary_damage * f, autocvar_g_balance_crylink_primary_edgedamage * f, autocvar_g_balance_crylink_primary_radius, world, autocvar_g_balance_crylink_primary_force * f, self.projectiledeathtype, other) && autocvar_g_balance_crylink_primary_linkexplode)
+ if (RadiusDamage (self, self.realowner, autocvar_g_balance_crylink_primary_damage * f, autocvar_g_balance_crylink_primary_edgedamage * f, autocvar_g_balance_crylink_primary_radius, world, world, autocvar_g_balance_crylink_primary_force * f, self.projectiledeathtype, other) && autocvar_g_balance_crylink_primary_linkexplode)
{
if(self == self.realowner.crylink_lastgroup)
self.realowner.crylink_lastgroup = world;
f = autocvar_g_balance_crylink_secondary_bouncedamagefactor;
if(a)
f *= a;
- if (RadiusDamage (self, self.realowner, autocvar_g_balance_crylink_secondary_damage * f, autocvar_g_balance_crylink_secondary_edgedamage * f, autocvar_g_balance_crylink_secondary_radius, world, autocvar_g_balance_crylink_secondary_force * f, self.projectiledeathtype, other) && autocvar_g_balance_crylink_secondary_linkexplode)
+ if (RadiusDamage (self, self.realowner, autocvar_g_balance_crylink_secondary_damage * f, autocvar_g_balance_crylink_secondary_edgedamage * f, autocvar_g_balance_crylink_secondary_radius, world, world, autocvar_g_balance_crylink_secondary_force * f, self.projectiledeathtype, other) && autocvar_g_balance_crylink_secondary_linkexplode)
{
if(self == self.realowner.crylink_lastgroup)
self.realowner.crylink_lastgroup = world;
self.takedamage = DAMAGE_NO;
if (self.movetype == MOVETYPE_BOUNCE)
{
- RadiusDamage (self, self.realowner, autocvar_g_balance_electro_secondary_damage, autocvar_g_balance_electro_secondary_edgedamage, autocvar_g_balance_electro_secondary_radius, world, autocvar_g_balance_electro_secondary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_electro_secondary_damage, autocvar_g_balance_electro_secondary_edgedamage, autocvar_g_balance_electro_secondary_radius, world, world, autocvar_g_balance_electro_secondary_force, self.projectiledeathtype, other);
}
else
{
W_Plasma_TriggerCombo(self.origin, autocvar_g_balance_electro_primary_comboradius, self.realowner);
- RadiusDamage (self, self.realowner, autocvar_g_balance_electro_primary_damage, autocvar_g_balance_electro_primary_edgedamage, autocvar_g_balance_electro_primary_radius, world, autocvar_g_balance_electro_primary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_electro_primary_damage, autocvar_g_balance_electro_primary_edgedamage, autocvar_g_balance_electro_primary_radius, world, world, autocvar_g_balance_electro_primary_force, self.projectiledeathtype, other);
}
remove (self);
W_Plasma_TriggerCombo(self.origin, autocvar_g_balance_electro_combo_comboradius, self.realowner);
self.event_damage = SUB_Null;
- RadiusDamage (self, self.realowner, autocvar_g_balance_electro_combo_damage, autocvar_g_balance_electro_combo_edgedamage, autocvar_g_balance_electro_combo_radius, world, autocvar_g_balance_electro_combo_force, WEP_ELECTRO | HITTYPE_BOUNCE, world); // use THIS type for a combo because primary can't bounce
+ RadiusDamage (self, self.realowner, autocvar_g_balance_electro_combo_damage, autocvar_g_balance_electro_combo_edgedamage, autocvar_g_balance_electro_combo_radius, world, world, autocvar_g_balance_electro_combo_force, WEP_ELECTRO | HITTYPE_BOUNCE, world); // use THIS type for a combo because primary can't bounce
remove (self);
}
// 1. dist damage
d = (self.realowner.health + self.realowner.armorvalue);
- RadiusDamage (self, self.realowner, autocvar_g_balance_fireball_primary_damage, autocvar_g_balance_fireball_primary_edgedamage, autocvar_g_balance_fireball_primary_radius, world, autocvar_g_balance_fireball_primary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_fireball_primary_damage, autocvar_g_balance_fireball_primary_edgedamage, autocvar_g_balance_fireball_primary_radius, world, world, autocvar_g_balance_fireball_primary_force, self.projectiledeathtype, other);
if(self.realowner.health + self.realowner.armorvalue >= d)
if(!self.cnt)
{
if(self.movetype == MOVETYPE_NONE)
self.velocity = self.oldvelocity;
- RadiusDamage (self, self.realowner, autocvar_g_balance_grenadelauncher_primary_damage, autocvar_g_balance_grenadelauncher_primary_edgedamage, autocvar_g_balance_grenadelauncher_primary_radius, world, autocvar_g_balance_grenadelauncher_primary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_grenadelauncher_primary_damage, autocvar_g_balance_grenadelauncher_primary_edgedamage, autocvar_g_balance_grenadelauncher_primary_radius, world, world, autocvar_g_balance_grenadelauncher_primary_force, self.projectiledeathtype, other);
remove (self);
}
if(self.movetype == MOVETYPE_NONE)
self.velocity = self.oldvelocity;
- RadiusDamage (self, self.realowner, autocvar_g_balance_grenadelauncher_secondary_damage, autocvar_g_balance_grenadelauncher_secondary_edgedamage, autocvar_g_balance_grenadelauncher_secondary_radius, world, autocvar_g_balance_grenadelauncher_secondary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_grenadelauncher_secondary_damage, autocvar_g_balance_grenadelauncher_secondary_edgedamage, autocvar_g_balance_grenadelauncher_secondary_radius, world, world, autocvar_g_balance_grenadelauncher_secondary_force, self.projectiledeathtype, other);
remove (self);
}
void W_Hagar_Explode (void)
{
self.event_damage = SUB_Null;
- RadiusDamage (self, self.realowner, autocvar_g_balance_hagar_primary_damage, autocvar_g_balance_hagar_primary_edgedamage, autocvar_g_balance_hagar_primary_radius, world, autocvar_g_balance_hagar_primary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_hagar_primary_damage, autocvar_g_balance_hagar_primary_edgedamage, autocvar_g_balance_hagar_primary_radius, world, world, autocvar_g_balance_hagar_primary_force, self.projectiledeathtype, other);
remove (self);
}
void W_Hagar_Explode2 (void)
{
self.event_damage = SUB_Null;
- RadiusDamage (self, self.realowner, autocvar_g_balance_hagar_secondary_damage, autocvar_g_balance_hagar_secondary_edgedamage, autocvar_g_balance_hagar_secondary_radius, world, autocvar_g_balance_hagar_secondary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_hagar_secondary_damage, autocvar_g_balance_hagar_secondary_edgedamage, autocvar_g_balance_hagar_secondary_radius, world, world, autocvar_g_balance_hagar_secondary_force, self.projectiledeathtype, other);
remove (self);
}
self.event_damage = SUB_Null;
if(self.projectiledeathtype & HITTYPE_SECONDARY)
- RadiusDamage (self, self.realowner, autocvar_g_balance_hlac_secondary_damage, autocvar_g_balance_hlac_secondary_edgedamage, autocvar_g_balance_hlac_secondary_radius, world, autocvar_g_balance_hlac_secondary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_hlac_secondary_damage, autocvar_g_balance_hlac_secondary_edgedamage, autocvar_g_balance_hlac_secondary_radius, world, world, autocvar_g_balance_hlac_secondary_force, self.projectiledeathtype, other);
else
- RadiusDamage (self, self.realowner, autocvar_g_balance_hlac_primary_damage, autocvar_g_balance_hlac_primary_edgedamage, autocvar_g_balance_hlac_primary_radius, world, autocvar_g_balance_hlac_primary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_hlac_primary_damage, autocvar_g_balance_hlac_primary_edgedamage, autocvar_g_balance_hlac_primary_radius, world, world, autocvar_g_balance_hlac_primary_force, self.projectiledeathtype, other);
remove (self);
}
f = self.dmg_last - dmg_remaining_next;
self.dmg_last = dmg_remaining_next;
- RadiusDamage (self, self.realowner, self.dmg * f, self.dmg_edge * f, self.dmg_radius, self.realowner, self.dmg_force * f, self.projectiledeathtype, world);
+ RadiusDamage (self, self.realowner, self.dmg * f, self.dmg_edge * f, self.dmg_radius, self.realowner, world, self.dmg_force * f, self.projectiledeathtype, world);
self.projectiledeathtype |= HITTYPE_BOUNCE;
- //RadiusDamage (self, world, self.dmg * f, self.dmg_edge * f, self.dmg_radius, world, self.dmg_force * f, self.projectiledeathtype, world);
+ //RadiusDamage (self, world, self.dmg * f, self.dmg_edge * f, self.dmg_radius, world, world, self.dmg_force * f, self.projectiledeathtype, world);
if(dt < self.dmg_duration)
self.nextthink = time + 0.05; // soon
void(float imp) W_SwitchWeapon;
void() W_LastWeapon;
+void SendCSQCShockwaveParticle(float spread, vector endpos)
+{
+ //WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
+ WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
+ WriteByte(MSG_BROADCAST, TE_CSQC_SHOCKWAVEPARTICLE);
+ WriteCoord(MSG_BROADCAST, w_shotorg_x);
+ WriteCoord(MSG_BROADCAST, w_shotorg_y);
+ WriteCoord(MSG_BROADCAST, w_shotorg_z);
+ WriteCoord(MSG_BROADCAST, endpos_x);
+ WriteCoord(MSG_BROADCAST, endpos_y);
+ WriteCoord(MSG_BROADCAST, endpos_z);
+ WriteByte(MSG_BROADCAST, bound(0, 255 * spread, 255));
+}
+
void W_Laser_Touch (void)
{
PROJECTILE_TOUCH;
self.event_damage = SUB_Null;
if (self.dmg)
- RadiusDamage (self, self.realowner, autocvar_g_balance_laser_secondary_damage, autocvar_g_balance_laser_secondary_edgedamage, autocvar_g_balance_laser_secondary_radius, world, autocvar_g_balance_laser_secondary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_laser_secondary_damage, autocvar_g_balance_laser_secondary_edgedamage, autocvar_g_balance_laser_secondary_radius, world, world, autocvar_g_balance_laser_secondary_force, self.projectiledeathtype, other);
else
- RadiusDamage (self, self.realowner, autocvar_g_balance_laser_primary_damage, autocvar_g_balance_laser_primary_edgedamage, autocvar_g_balance_laser_primary_radius, world, autocvar_g_balance_laser_primary_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_laser_primary_damage, autocvar_g_balance_laser_primary_edgedamage, autocvar_g_balance_laser_primary_radius, world, world, autocvar_g_balance_laser_primary_force, self.projectiledeathtype, other);
remove (self);
}
CSQCProjectile(self, TRUE, PROJECTILE_LASER, TRUE);
}
+void W_Laser_Shockwave (void)
+{
+ // declarations
+ float final_damage, final_spread;
+ entity head, next, aim_ent;
+ vector nearest, attack_hitpos, angle_to_head, angle_to_attack, final_force, center;
+
+ // set up the shot direction
+ vector wanted_shot_direction = (v_forward * cos(autocvar_g_balance_laser_primary_shotangle * DEG2RAD) + v_up * sin(autocvar_g_balance_laser_primary_shotangle * DEG2RAD));
+ W_SetupShot_Dir(self, wanted_shot_direction, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_balance_laser_primary_damage);
+ vector attack_endpos = (w_shotorg + (w_shotdir * autocvar_g_balance_laser_primary_radius));
+
+ // find out what we're pointing at
+ WarpZone_TraceLine(w_shotorg, attack_endpos, FALSE, self);
+ aim_ent = trace_ent;
+ attack_hitpos = trace_endpos;
+
+ // do the jump explosion now (also handles the impact effect)
+ RadiusDamageForSource(self, trace_endpos, '0 0 0', self, autocvar_g_balance_laser_primary_damage, autocvar_g_balance_laser_primary_edgedamage, autocvar_g_balance_laser_primary_jumpradius, world, self, TRUE, autocvar_g_balance_laser_primary_force, WEP_LASER, world);
+
+ // also do the firing effect now
+ SendCSQCShockwaveParticle(autocvar_g_balance_laser_primary_spread, attack_hitpos);
+
+ // did we hit a player directly?
+ if(aim_ent.takedamage)
+ {
+ // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+ if (aim_ent.classname == "player")
+ center = aim_ent.origin + aim_ent.view_ofs;
+ else
+ center = aim_ent.origin + (aim_ent.mins + aim_ent.maxs) * 0.5;
+
+ final_force = (normalize(center - attack_hitpos) * autocvar_g_balance_laser_primary_force);
+ Damage(aim_ent, self, self, autocvar_g_balance_laser_primary_damage, WEP_LASER, w_shotorg, final_force);
+ print("Player hit directly via aim!\n");
+ }
+
+ // now figure out if I hit anything else than what my aim directly pointed at...
+ head = WarpZone_FindRadius(w_shotorg, autocvar_g_balance_laser_primary_radius, FALSE);
+ while(head)
+ {
+ next = head.chain;
+
+ if((head != self && head != aim_ent) && (head.takedamage))
+ {
+ // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+ if (head.classname == "player")
+ center = head.origin + head.view_ofs;
+ else
+ center = head.origin + (head.mins + head.maxs) * 0.5;
+
+ // find the closest point on the enemy to the center of the attack
+ float h = vlen(center - self.origin);
+ float ang = acos(dotproduct(normalize(center - self.origin), w_shotdir));
+ float a = h * cos(ang);
+
+ // ang = angle between shotdir and h
+ // h = hypotenuse, which is the distance between attacker to head
+ // a = adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
+
+ nearest = WarpZoneLib_NearestPointOnBox(center + head.mins, center + head.maxs, w_shotorg + a * w_shotdir);
+
+ if(vlen(w_shotorg - nearest) <= autocvar_g_balance_laser_primary_radius)
+ {
+ // is it within the limit of the spread?
+ nearest = head.WarpZone_findradius_nearest;
+ angle_to_head = normalize(nearest - w_shotorg);
+ angle_to_attack = w_shotdir;
+ final_spread = vlen(angle_to_head - angle_to_attack);
+ if(final_spread <= autocvar_g_balance_laser_primary_spread)
+ {
+ // TODO! we MUST check this, otherwise you can shoot through walls!
+ // just how to make sure that if a small part of the player is visible, we'll hit him?
+ // we can just do it the cheap way of tracing from shotorg to nearest, but what if there's an obstruction between those points, but the player still sees the enemy...?
+
+ // is it visible to the weapon?
+ //WarpZone_TraceLine(w_shotorg, nearest, MOVE_WORLDONLY, self);
+ //if(trace_fraction == 1)
+ //{
+ // finally lets do some damage bitches!
+ if(autocvar_g_balance_laser_primary_spread)
+ final_damage = (final_spread / autocvar_g_balance_laser_primary_spread);
+ else
+ final_damage = 1;
+
+ //final_force = (normalize(nearest - w_shotorg) * autocvar_g_balance_laser_primary_force); // we dont want to use nearest here, because that would result in some rather weird force dirs for the attacker...
+ print(strcat("head.origin: ", vtos(head.origin), ", (w_shotorg + a * w_shotdir): ", vtos(w_shotorg + a * w_shotdir), ".\n"));
+ print("a = ", ftos(a), " h = ", ftos(h), " ang = ", ftos(ang), "\n");
+ final_force = (normalize(center - (w_shotorg + a * w_shotdir)) * autocvar_g_balance_laser_primary_force);
+ final_damage = (autocvar_g_balance_laser_primary_damage * final_damage + autocvar_g_balance_laser_primary_edgedamage * (1 - final_damage));
+
+ print(strcat("damage: ", ftos(final_damage), ", force: ", vtos(final_force), ".\n"));
+
+ Damage(head, self, self, final_damage, WEP_LASER, head.origin, final_force);
+
+ print(strcat(vtos(angle_to_head), " - ", vtos(angle_to_attack), ": ", ftos(vlen(angle_to_head - angle_to_attack)), ".\n"));
+ //te_lightning2(world, nearest, w_shotorg);
+
+ //pointparticles(particleeffectnum("rocket_guide"), w_shotorg, w_shotdir * 1000, 1);
+ //SendCSQCShockwaveParticle(autocvar_g_balance_laser_primary_spread, trace_endpos);
+ //}
+ }
+ }
+ }
+ head = next;
+ }
+}
+
void W_Laser_Attack (float issecondary)
{
entity missile;
{
W_DecreaseAmmo(ammo_none, 1, TRUE);
- W_Laser_Attack(0);
+ W_Laser_Shockwave();
weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_laser_primary_animtime, w_ready);
}
}
{
vector org2;
org2 = w_org + w_backoff * 6;
- pointparticles(particleeffectnum("laser_impact"), org2, w_backoff * 1000, 1);
+ pointparticles(particleeffectnum("new_laser_impact"), org2, w_backoff * 1000, 1);
if(!w_issilent)
sound(self, CH_SHOTS, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
}
self.event_damage = SUB_Null;
self.takedamage = DAMAGE_NO;
- RadiusDamage (self, self.realowner, autocvar_g_balance_minelayer_damage, autocvar_g_balance_minelayer_edgedamage, autocvar_g_balance_minelayer_radius, world, autocvar_g_balance_minelayer_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_minelayer_damage, autocvar_g_balance_minelayer_edgedamage, autocvar_g_balance_minelayer_radius, world, world, autocvar_g_balance_minelayer_force, self.projectiledeathtype, other);
if (self.realowner.weapon == WEP_MINE_LAYER)
{
if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
self.velocity = self.oldvelocity;
- RadiusDamage (self, self.realowner, autocvar_g_balance_minelayer_remote_damage, autocvar_g_balance_minelayer_remote_edgedamage, autocvar_g_balance_minelayer_remote_radius, world, autocvar_g_balance_minelayer_remote_force, self.projectiledeathtype | HITTYPE_BOUNCE, world);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_minelayer_remote_damage, autocvar_g_balance_minelayer_remote_edgedamage, autocvar_g_balance_minelayer_remote_radius, world, world, autocvar_g_balance_minelayer_remote_force, self.projectiledeathtype | HITTYPE_BOUNCE, world);
if (self.realowner.weapon == WEP_MINE_LAYER)
{
self.event_damage = SUB_Null;
self.takedamage = DAMAGE_NO;
- RadiusDamage (self, self.realowner, autocvar_g_balance_rocketlauncher_damage, autocvar_g_balance_rocketlauncher_edgedamage, autocvar_g_balance_rocketlauncher_radius, world, autocvar_g_balance_rocketlauncher_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_rocketlauncher_damage, autocvar_g_balance_rocketlauncher_edgedamage, autocvar_g_balance_rocketlauncher_radius, world, world, autocvar_g_balance_rocketlauncher_force, self.projectiledeathtype, other);
if (self.realowner.weapon == WEP_ROCKET_LAUNCHER)
{
self.event_damage = SUB_Null;
self.takedamage = DAMAGE_NO;
- RadiusDamage (self, self.realowner, autocvar_g_balance_rocketlauncher_remote_damage, autocvar_g_balance_rocketlauncher_remote_edgedamage, autocvar_g_balance_rocketlauncher_remote_radius, world, autocvar_g_balance_rocketlauncher_remote_force, self.projectiledeathtype | HITTYPE_BOUNCE, world);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_rocketlauncher_remote_damage, autocvar_g_balance_rocketlauncher_remote_edgedamage, autocvar_g_balance_rocketlauncher_remote_radius, world, world, autocvar_g_balance_rocketlauncher_remote_force, self.projectiledeathtype | HITTYPE_BOUNCE, world);
if (self.realowner.weapon == WEP_ROCKET_LAUNCHER)
{
void Seeker_Missile_Explode ()
{
self.event_damage = SUB_Null;
- RadiusDamage (self, self.realowner, autocvar_g_balance_seeker_missile_damage, autocvar_g_balance_seeker_missile_edgedamage, autocvar_g_balance_seeker_missile_radius, world, autocvar_g_balance_seeker_missile_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_seeker_missile_damage, autocvar_g_balance_seeker_missile_edgedamage, autocvar_g_balance_seeker_missile_radius, world, world, autocvar_g_balance_seeker_missile_force, self.projectiledeathtype, other);
remove (self);
}
{
self.event_damage = SUB_Null;
- RadiusDamage (self, self.realowner, autocvar_g_balance_seeker_flac_damage, autocvar_g_balance_seeker_flac_edgedamage, autocvar_g_balance_seeker_flac_radius, world, autocvar_g_balance_seeker_flac_force, self.projectiledeathtype, other);
+ RadiusDamage (self, self.realowner, autocvar_g_balance_seeker_flac_damage, autocvar_g_balance_seeker_flac_edgedamage, autocvar_g_balance_seeker_flac_radius, world, world, autocvar_g_balance_seeker_flac_force, self.projectiledeathtype, other);
remove (self);
}
self.tuba_note.teleport_time = time + autocvar_g_balance_tuba_refire * 2 * W_WeaponRateFactor(); // so it can get prolonged safely
//sound(self, c, TUBA_NOTE(n), bound(0, VOL_BASE * cvar("g_balance_tuba_volume"), 1), autocvar_g_balance_tuba_attenuation);
- RadiusDamage(self, self, autocvar_g_balance_tuba_damage, autocvar_g_balance_tuba_edgedamage, autocvar_g_balance_tuba_radius, world, autocvar_g_balance_tuba_force, hittype | WEP_TUBA, world);
+ RadiusDamage(self, self, autocvar_g_balance_tuba_damage, autocvar_g_balance_tuba_edgedamage, autocvar_g_balance_tuba_radius, world, world, autocvar_g_balance_tuba_force, hittype | WEP_TUBA, world);
o = gettaginfo(self.exteriorweaponentity, 0);
if(time > self.tuba_smoketime)