]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/master' into samual/spawn_weapons
authorSamual <samual@xonotic.org>
Thu, 24 May 2012 16:09:09 +0000 (12:09 -0400)
committerSamual <samual@xonotic.org>
Thu, 24 May 2012 16:09:09 +0000 (12:09 -0400)
Conflicts:
effectinfo.txt
qcsrc/common/util.qc
qcsrc/common/util.qh

1  2 
balanceXonotic.cfg
effectinfo.txt
qcsrc/client/Main.qc
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/server/autocvars.qh
qcsrc/server/w_common.qc

diff --combined balanceXonotic.cfg
index 108ed3aa8e6c5de3c471405e53781f8c5d442573,52c8a74d84cecfe381db5adbb156bc778f7da233..007619985905c47954e971c03c4df2c0ef5b17e2
@@@ -162,6 -162,7 +162,7 @@@ set g_projectiles_damage 
  // 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 normally
+ set g_projectiles_keep_owner 0
  set g_projectiles_newton_style 2
  // possible values:
  // 0: absolute velocity projectiles (like Quake)
@@@ -230,9 -231,9 +231,9 @@@ set g_balance_grapplehook_damagedbycont
  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
diff --combined effectinfo.txt
index 2213c126de75c7089d7d8f891a560f4f9485e9c2,5e06d075e6bf292b1c41e3889b90412272a78dd0..38a14489d07172fe6aa3dd95852698a18759d7bc
@@@ -7410,83 -7410,3 +7410,83 @@@ velocityjitter 64 64 6
  //lightradiusfade 50
  //lightcolor 1 0.9 0.7
  //lightshadow 1
- velocityjitter 256 256 256
 +
 +// 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
diff --combined qcsrc/client/Main.qc
index 48669671753cb7374882ed9530dc53753a571761,ec258e27d708af15be8fe763a3d6477900063dfa..fe9fd6dd38a5b4aa8e736136864f40c0416e8d8e
@@@ -178,7 -178,7 +178,7 @@@ void CSQC_Init(void
        DamageInfo_Precache();
        Vehicles_Precache();
        turrets_precache();
-   Announcer_Precache();
+     Announcer_Precache();
        Tuba_Precache();
        
        if(autocvar_cl_reticle)
@@@ -1185,10 -1185,6 +1185,10 @@@ float CSQC_Parse_TempEntity(
                        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;
diff --combined qcsrc/common/util.qc
index da78733c7166a15bb9c942a222c6266eb0868ccd,6e534ffc19464a92777b956353b926f48ddd578e..f99312b5b2eae92a96b025d1e9d8ecc15a8dbcd5
@@@ -463,11 -463,6 +463,11 @@@ string ScoreString(float pFlags, float 
        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
@@@ -2370,194 -2365,54 +2370,246 @@@ void queue_to_execute_next_frame(strin
        to_execute_next_frame = strzone(s);
  }
  
+ float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x)
+ {
+       return
+               (((     startspeedfactor + endspeedfactor - 2
+               ) * x - 2 * startspeedfactor - endspeedfactor + 3
+               ) * x + startspeedfactor
+               ) * x;
+ }
+ float cubic_speedfunc_is_sane(float startspeedfactor, float endspeedfactor)
+ {
+       if(startspeedfactor < 0 || endspeedfactor < 0)
+               return FALSE;
+       /*
+       // if this is the case, the possible zeros of the first derivative are outside
+       // 0..1
+       We can calculate this condition as condition 
+       if(se <= 3)
+               return TRUE;
+       */
+       // better, see below:
+       if(startspeedfactor <= 3 && endspeedfactor <= 3)
+               return TRUE;
+       // if this is the case, the first derivative has no zeros at all
+       float se = startspeedfactor + endspeedfactor;
+       float s_e = startspeedfactor - endspeedfactor;
+       if(3 * (se - 4) * (se - 4) + s_e * s_e <= 12) // an ellipse
+               return TRUE;
+       // Now let s <= 3, s <= 3, s+e >= 3 (triangle) then we get se <= 6 (top right corner).
+       // we also get s_e <= 6 - se
+       // 3 * (se - 4)^2 + (6 - se)^2
+       // is quadratic, has value 12 at 3 and 6, and value < 12 in between.
+       // Therefore, above "better" check works!
+       return FALSE;
+       // known good cases:
+       // (0, [0..3])
+       // (0.5, [0..3.8])
+       // (1, [0..4])
+       // (1.5, [0..3.9])
+       // (2, [0..3.7])
+       // (2.5, [0..3.4])
+       // (3, [0..3])
+       // (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
diff --combined qcsrc/common/util.qh
index 050bb2b4f85a8cc7757b1f7ce987bfa84ee07393,3ce173bf638e95d705a70042fc6bfae62f4838aa..8abd36ece058ad5aab4e9a8499141a462722833b
@@@ -79,7 -79,6 +79,7 @@@ string mmssss(float t)
  
  string ScoreString(float vflags, float value);
  
 +float dotproduct(vector a, vector b);
  vector cross(vector a, vector b);
  
  void compressShortVector_init();
@@@ -322,6 -321,16 +322,18 @@@ void queue_to_execute_next_frame(strin
  // 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
+ // f'(0) = startspeedfactor
+ // f'(1) = endspeedfactor
+ float cubic_speedfunc(float startspeedfactor, float endspeedfactor, float x);
+ // checks whether f'(x) = 0 anywhere from 0 to 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
index a56449816152ebc21e5656b0d6e28044dd11c5a3,dbb790a883b9c131d1b3aa18c6458abba2e7873a..ee01e21d19b78f227255dd76d2daee76d3b912d0
@@@ -435,13 -435,11 +435,13 @@@ float autocvar_g_balance_laser_primary_
  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;
@@@ -930,6 -928,7 +930,7 @@@ float autocvar_g_playerclip_collisions
  string autocvar_g_playerstats_uri;
  float autocvar_g_powerups;
  float autocvar_g_projectiles_damage;
+ float autocvar_g_projectiles_keep_owner;
  float autocvar_g_projectiles_newton_style;
  float autocvar_g_projectiles_newton_style_2_maxfactor;
  float autocvar_g_projectiles_newton_style_2_minfactor;
diff --combined qcsrc/server/w_common.qc
index 8da19cbec28f10bde4b1f3399bda4e3571c9b830,a2f23956eed6f4f3f7b0389d523e8062555fb2d1..9dde1c7106dfcfca9f6b3f0cf89bf4cb757a48ac
@@@ -148,7 -148,7 +148,7 @@@ void FireRailgunBullet (vector start, v
  
                // 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;
@@@ -243,31 -243,58 +243,58 @@@ void W_BallisticBullet_LeaveSolid_think
        UpdateCSQCProjectile(self);
  }
  
- float W_BallisticBullet_LeaveSolid(entity e, vector vel, float constant)
+ float W_BallisticBullet_LeaveSolid(float eff)
  {
        // move the entity along its velocity until it's out of solid, then let it resume
+       vector vel = self.velocity;
        float dt, dst, velfactor, v0, vs;
        float maxdist;
        float E0_m, Es_m;
+       float constant = self.dmg_radius * (other.ballistics_density ? other.ballistics_density : 1);
  
        // outside the world? forget it
        if(self.origin_x > world.maxs_x || self.origin_y > world.maxs_y || self.origin_z > world.maxs_z || self.origin_x < world.mins_x || self.origin_y < world.mins_y || self.origin_z < world.mins_z)
                return 0;
  
+       // special case for zero density and zero bullet constant: 
+       if(self.dmg_radius == 0)
+       {
+               if(other.ballistics_density < 0)
+                       constant = 0; // infinite travel distance
+               else
+                       return 0; // no penetration
+       }
+       else
+       {
+               if(other.ballistics_density < 0)
+                       constant = 0; // infinite travel distance
+               else if(other.ballistics_density == 0)
+                       constant = self.dmg_radius;
+               else
+                       constant = self.dmg_radius * other.ballistics_density;
+       }
        // E(s) = E0 - constant * s, constant = area of bullet circle * material constant / mass
        v0 = vlen(vel);
  
        E0_m = 0.5 * v0 * v0;
-       maxdist = E0_m / constant;
-       // maxdist = 0.5 * v0 * v0 / constant
-       // dprint("max dist = ", ftos(maxdist), "\n");
  
-       if(maxdist <= autocvar_g_ballistics_mindistance)
-               return 0;
+       if(constant)
+       {
+               maxdist = E0_m / constant;
+               // maxdist = 0.5 * v0 * v0 / constant
+               // dprint("max dist = ", ftos(maxdist), "\n");
  
-       traceline_inverted (self.origin, self.origin + normalize(vel) * maxdist, MOVE_NORMAL, self);
+               if(maxdist <= autocvar_g_ballistics_mindistance)
+                       return 0;
+       }
+       else
+       {
+               maxdist = vlen(other.maxs - other.mins) + 1; // any distance, as long as we leave the entity
+       }
  
+       traceline_inverted (self.origin, self.origin + normalize(vel) * maxdist, MOVE_NORMAL, self, TRUE);
        if(trace_fraction == 1) // 1: we never got out of solid
                return 0;
  
        self.flags |= FL_ONGROUND; // prevent moving
        self.W_BallisticBullet_LeaveSolid_velocity = vel;
  
+       if(eff >= 0)
+               if(vlen(trace_endpos - self.origin) > 4)
+               {
+                       endzcurveparticles();
+                       trailparticles(self, eff, self.origin, trace_endpos);
+               }
        return 1;
  }
  
@@@ -313,6 -347,12 +347,12 @@@ void W_BallisticBullet_Touch (void
        PROJECTILE_TOUCH;
        W_BallisticBullet_Hit ();
  
+       if(self.dmg_radius < 0) // these NEVER penetrate solid
+       {
+               remove(self);
+               return;
+       }
        // if we hit "weapclip", bail out
        //
        // rationale of this check:
                return;
        }
  
-       density = other.ballistics_density;
-       if(density == 0)
-               density = 1;
        // go through solid!
-       if(!W_BallisticBullet_LeaveSolid(self, self.velocity, self.dmg_radius * density))
+       if(!W_BallisticBullet_LeaveSolid(-1))
        {
                remove(self);
                return;
@@@ -386,7 -422,12 +422,12 @@@ void fireBallisticBullet(vector start, 
        proj.nextthink = time + lifetime; // min(pLifetime, vlen(world.maxs - world.mins) / pSpeed);
        W_SetupProjectileVelocityEx(proj, dir, v_up, pSpeed, 0, 0, spread, antilagging);
        proj.angles = vectoangles(proj.velocity);
-       proj.dmg_radius = autocvar_g_ballistics_materialconstant / bulletconstant;
+       if(bulletconstant > 0)
+               proj.dmg_radius = autocvar_g_ballistics_materialconstant / bulletconstant;
+       else if(bulletconstant == 0)
+               proj.dmg_radius = 0;
+       else
+               proj.dmg_radius = -1;
        // so: bulletconstant = bullet mass / area of bullet circle
        setorigin(proj, start);
        proj.flags = FL_PROJECTILE;
                                W_BallisticBullet_Hit();
                        }
  
+                       if(proj.dmg_radius < 0) // these NEVER penetrate solid
+                               break;
                        // if we hit "weapclip", bail out
                        //
                        // rationale of this check:
                        if not(trace_dphitcontents & DPCONTENTS_OPAQUE)
                                break;
  
-                       density = other.ballistics_density;
-                       if(density == 0)
-                               density = 1;
                        // go through solid!
-                       if(!W_BallisticBullet_LeaveSolid(self, self.velocity, self.dmg_radius * density))
+                       if(!W_BallisticBullet_LeaveSolid((other && (other.solid != SOLID_BSP)) ? eff : -1))
                                break;
  
                        W_BallisticBullet_LeaveSolid_think();
+                       self.projectiledeathtype |= HITTYPE_BOUNCE;
                }
                frametime = savetime;
                self = oldself;
@@@ -588,7 -630,7 +630,7 @@@ void W_PrepareExplosionByDamage(entity 
        self.takedamage = DAMAGE_NO;
        self.event_damage = SUB_Null;
        
-       if not(g_ca)
+       if((attacker.flags & FL_CLIENT) && !autocvar_g_projectiles_keep_owner)
        {
                self.owner = attacker;
                self.realowner = attacker;