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

21 files changed:
balance25.cfg
balanceFruitieX.cfg
balanceXPM.cfg
balanceXonotic.cfg
defaultXonotic.cfg
effectinfo.txt
gfx/vehicles/vth-mover.tga [new file with mode: 0644]
gfx/vehicles/vth-stationary.tga [new file with mode: 0644]
qcsrc/client/Main.qc
qcsrc/client/autocvars.qh
qcsrc/client/tturrets.qc
qcsrc/client/vehicles/vehicles.qc
qcsrc/common/items.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/server/autocvars.qh
qcsrc/server/command/radarmap.qc
qcsrc/server/defs.qh
qcsrc/server/g_subs.qc
qcsrc/server/mutators/mutator_dodging.qc
qcsrc/server/w_common.qc

index bea9ad263a3243ef5904d70fe8de2eca52047a3b..aafb163b441941ea73ad9a0ba736837fcc0bc25f 100644 (file)
@@ -162,6 +162,7 @@ set g_projectiles_damage 2
 // 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)
index 16286fe0f8b85eb63c3529617bef7dc2cb259a74..1bb8989120df04a0f5f3b7864c66c23ab0df2f57 100644 (file)
@@ -162,6 +162,7 @@ set g_projectiles_damage 2
 // 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)
index d3478a969f292339c212b96bc934eb284e9adc2e..759551d8d2357a4a2e53f7f1125d229659802fe7 100644 (file)
@@ -162,6 +162,7 @@ set g_projectiles_damage 1
 // 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 0
 // possible values:
 // 0: absolute velocity projectiles (like Quake)
index 108ed3aa8e6c5de3c471405e53781f8c5d442573..007619985905c47954e971c03c4df2c0ef5b17e2 100644 (file)
@@ -162,6 +162,7 @@ set g_projectiles_damage 2
 // 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)
index 0c399bb183cde7a50c4ff80e690bd59764527ffc..ae552dd16db737b10c27d4f7f64f9519e3d01fac 100644 (file)
@@ -1645,6 +1645,9 @@ seta cl_casings_maxcount 100 "maximum amount of shell casings (must be at least
 seta cl_gibs_maxcount 100 "maximum amount of gibs (must be at least 1)"
 seta cl_vehicle_spiderbot_cross_alpha 0.6
 seta cl_vehicle_spiderbot_cross_size 1
+seta cl_vehicles_hudscale 0.5 
+seta cl_vehicles_hudalpha 0.75
+seta cl_vehicles_hud_tactical 1
 
 //cl_gunalign calculator
 seta menu_cl_gunalign 3 "Gun alignment; 1 = center (if allowed by g_shootfromclient) or right, 2 = center (if allowed by g_shootfromclient) or left, 3 = right only, 4 = left only"
index 2213c126de75c7089d7d8f891a560f4f9485e9c2..38a14489d07172fe6aa3dd95852698a18759d7bc 100644 (file)
@@ -7489,4 +7489,4 @@ gravity 0.5
 airfriction 1
 liquidfriction 1
 originjitter 20 20 20
-velocityjitter 256 256 256
+velocityjitter 256 256 256
\ No newline at end of file
diff --git a/gfx/vehicles/vth-mover.tga b/gfx/vehicles/vth-mover.tga
new file mode 100644 (file)
index 0000000..d831896
Binary files /dev/null and b/gfx/vehicles/vth-mover.tga differ
diff --git a/gfx/vehicles/vth-stationary.tga b/gfx/vehicles/vth-stationary.tga
new file mode 100644 (file)
index 0000000..31703bc
Binary files /dev/null and b/gfx/vehicles/vth-stationary.tga differ
index 48669671753cb7374882ed9530dc53753a571761..fe9fd6dd38a5b4aa8e736136864f40c0416e8d8e 100644 (file)
@@ -178,7 +178,7 @@ void CSQC_Init(void)
        DamageInfo_Precache();
        Vehicles_Precache();
        turrets_precache();
-  Announcer_Precache();
+    Announcer_Precache();
        Tuba_Precache();
        
        if(autocvar_cl_reticle)
index 344c3731c4561f1932d123df8a2032bc9f139934..1e938c26ae3d95c12b9056b484edde0c87fbee82 100644 (file)
@@ -67,6 +67,7 @@ float autocvar_cl_reticle_stretch;
 float autocvar_cl_stripcolorcodes;
 var float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6;
 var float autocvar_cl_vehicle_spiderbot_cross_size = 1;
+var float autocvar_cl_vehicles_hud_tactical = 1;
 float autocvar_cl_velocityzoom;
 var float autocvar_cl_velocityzoom_type = 3;
 float autocvar_cl_velocityzoom_speed;
index 2b9ec0297b2ef63411d210cc8a8597bc8438691f..d7abeb0919de42e95d278942f363cb9009336b96 100644 (file)
@@ -235,36 +235,46 @@ void turret_draw2d()
         return; 
 
        float dist = vlen(self.origin - view_origin);
+    float t = (GetPlayerColor(player_localnum) + 1);   
+
        vector o;
-       /*
-       // TODO: Vehicle tactical hud
-       o = project_3d_to_2d(self.origin + '0 0 32');
-       if(o_z < 0 
-       || o_x < (vid_conwidth * waypointsprite_edgeoffset_left) 
-       || o_y < (vid_conheight * waypointsprite_edgeoffset_top) 
-       || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))  
-       || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
-           return; // Dont draw wp's for turrets out of view
-    o_z = 0;
-    if(hud != HUD_NORMAL)
-    {        
-        switch(hud)
-        {
-            case HUD_SPIDERBOT:
-            case HUD_WAKIZASHI:
-            case HUD_RAPTOR:
-                vector pz = drawgetimagesize("gfx/vehicles/axh-bracket.tga") * 0.25;
-                drawpic(o - pz * 0.5 , "gfx/vehicles/axh-bracket.tga", pz , '1 1 1', 0.75, DRAWFLAG_NORMAL);
-                break;
+       string txt;
+       
+       if(autocvar_cl_vehicles_hud_tactical)
+       if(dist < 10240 && t != self.team)
+       {
+        // TODO: Vehicle tactical hud
+        o = project_3d_to_2d(self.origin + '0 0 32');
+        if(o_z < 0 
+        || o_x < (vid_conwidth * waypointsprite_edgeoffset_left) 
+        || o_y < (vid_conheight * waypointsprite_edgeoffset_top) 
+        || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))  
+        || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
+            return; // Dont draw wp's for turrets out of view
+        o_z = 0;
+        if(hud != HUD_NORMAL)
+        {        
+            switch(hud)
+            {
+                case HUD_SPIDERBOT:
+                case HUD_WAKIZASHI:
+                case HUD_RAPTOR:
+                    if(self.turret_type == TID_EWHEEL || self.turret_type == TID_WALKER)
+                        txt = "gfx/vehicles/vth-mover.tga";
+                    else
+                        txt = "gfx/vehicles/vth-stationary.tga";
+                        
+                    vector pz = drawgetimagesize(txt) * 0.25;
+                    drawpic(o - pz * 0.5, txt, pz , '1 1 1', 0.75, DRAWFLAG_NORMAL);
+                    break;
+            }
         }
-    }
-    */
+       }
     
        if(dist > self.maxdistance)
         return;
 
        string spriteimage = self.netname;
-       float t = (GetPlayerColor(player_localnum) + 1);        
        float a = self.alpha * autocvar_hud_panel_fg_alpha;
        vector rgb = spritelookupcolor(spriteimage, self.teamradar_color);
 
@@ -280,7 +290,7 @@ void turret_draw2d()
                print(sprintf("WARNING: sprite of name %s has no color, using pink so you notice it\n", spriteimage)); 
        }
 
-       string txt = self.netname;
+       txt = self.netname;
        if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
                txt = _("Spam");
        else
@@ -540,37 +550,38 @@ entity turret_gibtoss(string _model, vector _from, vector _to, vector _cmod, flo
 
 void turret_die()
 {    
-    entity headgib;
     
     sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
     pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
     turret_tid2info(self.turret_type);
-    
-    // Base
-    if(self.turret_type == TID_EWHEEL)
-        turret_gibtoss(tid2info_base, self.origin + '0 0 18', self.velocity + '0 0 400' + '0.1 0.1 1' * (random() * 400), '-1 -1 -1', TRUE);
-    else if (self.turret_type == TID_WALKER)
-        turret_gibtoss(tid2info_base, self.origin + '0 0 18', self.velocity + '0 0 300' + '0.1 0.1 1' * (random() * 200), '-1 -1 -1', TRUE);
-    else if (self.turret_type == TID_TESLA)
-        turret_gibtoss(tid2info_base, self.origin + '0 0 18', '0 0 200', '-1 -1 -1', FALSE);
-    else
-    {        
-        if (random() > 0.5)
-        {            
-            turret_gibtoss("models/turrets/base-gib2.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
-            turret_gibtoss("models/turrets/base-gib3.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
-            turret_gibtoss("models/turrets/base-gib4.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
-        }
+    if (!autocvar_cl_nogibs)
+    {
+        // Base
+        if(self.turret_type == TID_EWHEEL)
+            turret_gibtoss(tid2info_base, self.origin + '0 0 18', self.velocity + '0 0 400' + '0.1 0.1 1' * (random() * 400), '-1 -1 -1', TRUE);
+        else if (self.turret_type == TID_WALKER)
+            turret_gibtoss(tid2info_base, self.origin + '0 0 18', self.velocity + '0 0 300' + '0.1 0.1 1' * (random() * 200), '-1 -1 -1', TRUE);
+        else if (self.turret_type == TID_TESLA)
+            turret_gibtoss(tid2info_base, self.origin + '0 0 18', '0 0 200', '-1 -1 -1', FALSE);
         else
-            turret_gibtoss("models/turrets/base-gib1.md3", self.origin + '0 0 8', '0 0 0', '0 0 0', TRUE);
-
-        headgib = turret_gibtoss(tid2info_head, self.origin + '0 0 32', '0 0 200' + randomvec() * 200, '-1 -1 -1', TRUE);
-        if(headgib)
-        {
-            headgib.angles = headgib.move_angles = self.tur_head.angles;
-            headgib.avelocity = headgib.move_avelocity = self.tur_head.move_avelocity + randomvec() * 45;
-            headgib.avelocity_y = headgib.move_avelocity_y = headgib.move_avelocity_y * 5;
-            headgib.gravity = 0.5;        
+        {        
+            if (random() > 0.5)
+            {            
+                turret_gibtoss("models/turrets/base-gib2.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
+                turret_gibtoss("models/turrets/base-gib3.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
+                turret_gibtoss("models/turrets/base-gib4.md3", self.origin + '0 0 8', '0 0 50' + randomvec() * 150, '0 0 0', FALSE);
+            }
+            else
+                turret_gibtoss("models/turrets/base-gib1.md3", self.origin + '0 0 8', '0 0 0', '0 0 0', TRUE);
+
+            entity headgib = turret_gibtoss(tid2info_head, self.origin + '0 0 32', '0 0 200' + randomvec() * 200, '-1 -1 -1', TRUE);
+            if(headgib)
+            {
+                headgib.angles = headgib.move_angles = self.tur_head.angles;
+                headgib.avelocity = headgib.move_avelocity = self.tur_head.move_avelocity + randomvec() * 45;
+                headgib.avelocity_y = headgib.move_avelocity_y = headgib.move_avelocity_y * 5;
+                headgib.gravity = 0.5;        
+            }
         }
     }
     
index ccb9cff58363374f82761aa58899984b800b86f8..6081f5a66efdd6ea1e23d947adeb1f3c0a953609 100644 (file)
@@ -661,11 +661,13 @@ void CSQC_WAKIZASHI_HUD()
 void Vehicles_Precache()
 {
 // fixme: HAAAAKKKZZZ!!!!!!!!!!!! (this belongs as a setting in default.cfg)
-    autocvar_cl_vehicles_hudscale = 0.5;
-    autocvar_cl_vehicles_hudalpha = 0.75;
-
+    if(!autocvar_cl_vehicles_hudscale )
+        autocvar_cl_vehicles_hudscale = 0.5;
+    
+    if(!autocvar_cl_vehicles_hudalpha)
+        autocvar_cl_vehicles_hudalpha = 0.75;
 
-       precache_model("models/vehicles/wakizashi.dpm");
+       //precache_model("models/vehicles/wakizashi.dpm");
 
        precache_model("models/vehicles/bomblet.md3");
        precache_model("models/vehicles/clusterbomb.md3");
index 5a39d2148c045b1d155250cf8ae71432adbab85a..33fa21f7eeef5fb96bb0986971ce5223f27d0979 100644 (file)
@@ -101,11 +101,16 @@ float WEP_LAST;
 # define WEPSET_BIT(a)                  power2of((a) - WEP_FIRST)
 # define WEPSET_DECLARE_A(a)            float _WS_##a
 # define WEPSET_CLEAR_E(e)              ((e)._WS_weapons = 0)
-# define WEPSET_CLEAR_A(a)              ((_WS_##a) = 0)
+# define WEPSET_CLEAR_A(a)              (_WS_##a = 0)
 # define WEPSET_EMPTY_E(e)              ((e)._WS_weapons == 0)
-# define WEPSET_EMPTY_A(a)              ((_WS_##a) == 0)
-# define WEPSET_COPY_AS(a)              ((_WS_##a) = getstati(STAT_WEAPONS))
+# define WEPSET_EMPTY_A(a)              (_WS_##a == 0)
+# define WEPSET_COPY_AS(a)              (_WS_##a = getstati(STAT_WEAPONS))
 # define WEPSET_ADDSTAT()               addstat(STAT_WEAPONS, AS_INT, _WS_weapons)
+# define WEPSET_WRITE_E(dest,a)         WriteInt24_t(dest, (a)._WS_weapons)
+# define WEPSET_WRITE_A(dest,a)         WriteInt24_t(dest, _WS_##a)
+# define WEPSET_WRITE_W(dest,a)         WriteInt24_t(dest, WEPSET_BIT(a))
+# define WEPSET_READ_E(a)               (a)._WS_weapons = ReadInt24_t()
+# define WEPSET_READ_A(a)               (_WS_##a) = ReadInt24_t()
 # define WEPSET_OP1_EE(a,b,mergeop,x)   ((a)._WS_weapons x (b)._WS_weapons)
 # define WEPSET_OP2_EE(a,b,mergeop,x,y) ((a)._WS_weapons x (b)._WS_weapons y (a)._WS_weapons)
 # define WEPSET_OP1_EA(a,b,mergeop,x)   ((a)._WS_weapons x _WS_##b)
@@ -132,6 +137,11 @@ float WEP_LAST;
 # define WEPSET_EMPTY_A(a)              ((_WS1_##a) == 0 && (_WS2_##a) == 0)
 # define WEPSET_COPY_AS(a)              ((_WS1_##a) = getstati(STAT_WEAPONS), (_WS2_##a) = getstati(STAT_WEAPONS2))
 # define WEPSET_ADDSTAT()               addstat(STAT_WEAPONS, AS_INT, _WS1_weapons); addstat(STAT_WEAPONS2, AS_INT, _WS2_weapons)
+# define WEPSET_WRITE_E(dest,a)         WriteInt24_t(dest, (a)._WS1_weapons); WriteInt24_t(dest, (a)._WS2_weapons)
+# define WEPSET_WRITE_A(dest,a)         WriteInt24_t(dest, _WS1_##a); WriteInt24_t(dest, _WS2_##a)
+# define WEPSET_WRITE_W(dest,a)         WriteInt24_t(dest, WEPSET_BIT1(a)); WriteInt24_t(dest, WEPSET_BIT2(a))
+# define WEPSET_READ_E(a)               (a)._WS1_weapons = ReadInt24_t(); (a)._WS2_weapons = ReadInt24_t()
+# define WEPSET_READ_A(a)               (_WS1_##a) = ReadInt24_t(); (_WS2_##a) = ReadInt24_t()
 # define WEPSET_OP1_EE(a,b,mergeop,x)   (((a)._WS1_weapons x (b)._WS1_weapons) mergeop ((a)._WS2_weapons x (b)._WS2_weapons))
 # define WEPSET_OP2_EE(a,b,mergeop,x,y) (((a)._WS1_weapons x (b)._WS1_weapons y (a)._WS1_weapons) mergeop ((a)._WS2_weapons x (b)._WS2_weapons y (a)._WS2_weapons))
 # define WEPSET_OP1_EA(a,b,mergeop,x)   (((a)._WS1_weapons x _WS1_##b) mergeop ((a)._WS2_weapons x _WS2_##b))
index da78733c7166a15bb9c942a222c6266eb0868ccd..f99312b5b2eae92a96b025d1e9d8ecc15a8dbcd5 100644 (file)
@@ -2370,6 +2370,58 @@ void queue_to_execute_next_frame(string s)
        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)
 {
index 050bb2b4f85a8cc7757b1f7ce987bfa84ee07393..8abd36ece058ad5aab4e9a8499141a462722833b 100644 (file)
@@ -322,6 +322,18 @@ void queue_to_execute_next_frame(string s);
 // 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..ee01e21d19b78f227255dd76d2daee76d3b912d0 100644 (file)
@@ -930,6 +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;
index 16f3212eda0cc1852569ac0de61a11d67b1ff470..d8651762965d9d6859dbc05ed205b5ee0407d8dc 100644 (file)
@@ -28,7 +28,7 @@ float FullTraceFraction(vector a, vector mi, vector ma, vector b)
                        c = trace_endpos;
                }
 
-               n += tracebox_inverted(c, mi, ma, b, MOVE_WORLDONLY, world);
+               n += tracebox_inverted(c, mi, ma, b, MOVE_WORLDONLY, world, FALSE);
 
                white += vlen(trace_endpos - c);
                c = trace_endpos;
@@ -424,4 +424,4 @@ float RadarMap_Make(float argc)
        }
        
        return FALSE;
-}
\ No newline at end of file
+}
index 47a72d904a48145139648a28de27725a77038d02..fe1b00b9a643ea68c510bef32f1c9bff13a49be0 100644 (file)
@@ -100,6 +100,7 @@ float maxclients;
 .float         t_length, t_width;
 
 .vector destvec;               // for rain
+.vector destvec2;              // for train
 .float cnt;            // for rain
 .float count;
 //.float cnt2;
index f8aad67240f4d5fdb41624a33e7cd09519bd0e74..df63a70bb85d4f01578823b1b4ea3ceaba48f8ce 100644 (file)
@@ -178,24 +178,29 @@ void SUB_CalcMove_controller_think (void)
        float phasepos;
        float nexttick;
        vector delta;
+       vector delta2;
        vector veloc;
        vector nextpos;
+       delta = self.destvec;
+       delta2 = self.destvec2;
        if(time < self.animstate_endtime) {
-               delta = self.destvec;
                nexttick = time + sys_frametime;
 
-               if(nexttick < self.animstate_endtime) {
-                       traveltime = self.animstate_endtime - self.animstate_starttime;
-                       phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
+               traveltime = self.animstate_endtime - self.animstate_starttime;
+               phasepos = (nexttick - self.animstate_starttime) / traveltime; // range: [0, 1]
+               if(self.platmovetype != 1)
+               {
                        phasepos = 3.14159265 + (phasepos * 3.14159265); // range: [pi, 2pi]
                        phasepos = cos(phasepos); // cos [pi, 2pi] is in [-1, 1]
                        phasepos = phasepos + 1; // correct range to [0, 2]
                        phasepos = phasepos / 2; // correct range to [0, 1]
-                       nextpos = self.origin + (delta * phasepos);
+               }
+               nextpos = self.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
+               // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
 
+               if(nexttick < self.animstate_endtime) {
                        veloc = nextpos - self.owner.origin;
                        veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
-
                } else {
                        veloc = self.finaldest - self.owner.origin;
                        veloc = veloc * (1 / sys_frametime); // so it arrives for the next frame
@@ -203,6 +208,7 @@ void SUB_CalcMove_controller_think (void)
                self.owner.velocity = veloc;
                self.nextthink = nexttick;
        } else {
+               // derivative: delta + 2 * delta2 (e.g. for angle positioning)
                oldself = self;
                self.owner.think = self.think1;
                self = self.owner;
@@ -211,9 +217,35 @@ void SUB_CalcMove_controller_think (void)
        }
 }
 
-void SUB_CalcMove (vector tdest, float tspeed, void() func)
+void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest)
+{
+       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t
+       // 2 * control * t - 2 * control * t * t + dest * t * t
+       // 2 * control * t + (dest - 2 * control) * t * t
+
+       controller.origin = org; // starting point
+       control -= org;
+       dest -= org;
+
+       controller.destvec = 2 * control; // control point
+       controller.destvec2 = dest - 2 * control; // quadratic part required to reach end point
+}
+
+void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest)
+{
+       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + dest * t * t
+       // 2 * control * t - 2 * control * t * t + dest * t * t
+       // 2 * control * t + (dest - 2 * control) * t * t
+
+       controller.origin = org; // starting point
+       dest -= org;
+
+       controller.destvec = dest; // end point
+       controller.destvec2 = '0 0 0';
+}
+
+void SUB_CalcMove_Bezier (vector tcontrol, vector tdest, float tspeed, void() func)
 {
-       vector  delta;
        float   traveltime;
        entity controller;
 
@@ -224,40 +256,24 @@ void SUB_CalcMove (vector tdest, float tspeed, void() func)
        self.finaldest = tdest;
        self.think = SUB_CalcMoveDone;
 
-       if (tdest == self.origin)
-       {
-               self.velocity = '0 0 0';
-               self.nextthink = self.ltime + 0.1;
-               return;
-       }
+       if(tspeed > 0) // positive: start speed
+               traveltime = 2 * vlen(tcontrol - self.origin) /  tspeed;
+       else // negative: end speed
+               traveltime = 2 * vlen(tcontrol - tdest)       / -tspeed;
 
-       delta = tdest - self.origin;
-       traveltime = vlen (delta) / tspeed;
-
-       if (traveltime < 0.1)
+       if (traveltime < 0.1) // useless anim
        {
                self.velocity = '0 0 0';
                self.nextthink = self.ltime + 0.1;
                return;
        }
 
-       // Very short animations don't really show off the effect
-       // of controlled animation, so let's just use linear movement.
-       // Alternatively entities can choose to specify non-controlled movement.
-        // The only currently implemented alternative movement is linear (value 1)
-       if (traveltime < 0.15 || self.platmovetype == 1)
-       {
-               self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
-               self.nextthink = self.ltime + traveltime;
-               return;
-       }
-
        controller = spawn();
        controller.classname = "SUB_CalcMove_controller";
        controller.owner = self;
-       controller.origin = self.origin; // starting point
+       controller.platmovetype = self.platmovetype;
+       SUB_CalcMove_controller_setbezier(controller, self.origin, tcontrol, tdest);
        controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
-       controller.destvec = delta;
        controller.animstate_starttime = time;
        controller.animstate_endtime = time + traveltime;
        controller.think = SUB_CalcMove_controller_think;
@@ -273,6 +289,43 @@ void SUB_CalcMove (vector tdest, float tspeed, void() func)
        self = self.owner;
 }
 
+void SUB_CalcMove (vector tdest, float tspeed, void() func)
+{
+       vector  delta;
+       float   traveltime;
+
+       if (!tspeed)
+               objerror ("No speed is defined!");
+
+       self.think1 = func;
+       self.finaldest = tdest;
+       self.think = SUB_CalcMoveDone;
+
+       if (tdest == self.origin)
+       {
+               self.velocity = '0 0 0';
+               self.nextthink = self.ltime + 0.1;
+               return;
+       }
+
+       delta = tdest - self.origin;
+       traveltime = vlen (delta) / tspeed;
+
+       // Very short animations don't really show off the effect
+       // of controlled animation, so let's just use linear movement.
+       // Alternatively entities can choose to specify non-controlled movement.
+        // The only currently implemented alternative movement is linear (value 1)
+       if (traveltime < 0.15 || self.platmovetype == 1)
+       {
+               self.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
+               self.nextthink = self.ltime + traveltime;
+               return;
+       }
+
+       // now just run like a bezier curve...
+       SUB_CalcMove_Bezier((self.origin + tdest) * 0.5, tdest, tspeed, func);
+}
+
 void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeed, void() func)
 {
        entity  oldself;
@@ -445,10 +498,11 @@ void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma,
        tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, TRUE);
 }
 
-float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent) // returns the number of traces done, for benchmarking
+float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity) // returns the number of traces done, for benchmarking
 {
        vector pos, dir, t;
        float nudge;
+       entity stopentity;
 
        //nudge = 2 * cvar("collision_impactnudge"); // why not?
        nudge = 0.5;
@@ -481,6 +535,8 @@ float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomon
                        dprint("  trace distance is ", ftos(vlen(pos - trace_endpos)), "\n");
                }
 
+               stopentity = trace_ent;
+
                if(trace_startsolid)
                {
                        // we started inside solid.
@@ -493,6 +549,15 @@ float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomon
                                // t is still inside solid? bad
                                // force advance, then, and retry
                                pos = t + dir * nudge;
+
+                               // but if we hit an entity, stop RIGHT before it
+                               if(stopatentity && stopentity)
+                               {
+                                       trace_ent = stopentity;
+                                       trace_endpos = t;
+                                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
+                                       return c;
+                               }
                        }
                        else
                        {
@@ -511,59 +576,9 @@ float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomon
        }
 }
 
-void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent)
+void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity)
 {
-#if 0
-       vector pos, dir, t;
-       float nudge;
-
-       //nudge = 2 * cvar("collision_impactnudge"); // why not?
-       nudge = 0.5;
-
-       dir = normalize(v2 - v1);
-
-       pos = v1 + dir * nudge;
-
-       for(;;)
-       {
-               if((pos - v1) * dir >= (v2 - v1) * dir)
-               {
-                       // went too far
-                       trace_fraction = 1;
-                       return;
-               }
-
-               traceline(pos, v2, nomonsters, forent);
-
-               if(trace_startsolid)
-               {
-                       // we started inside solid.
-                       // then trace from endpos to pos
-                       t = trace_endpos;
-                       traceline(t, pos, nomonsters, forent);
-                       if(trace_startsolid)
-                       {
-                               // t is inside solid? bad
-                               // force advance, then
-                               pos = pos + dir * nudge;
-                       }
-                       else
-                       {
-                               // we actually LEFT solid!
-                               trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
-                               return;
-                       }
-               }
-               else
-               {
-                       // pos is outside solid?!? but why?!? never mind, just return it.
-                       trace_endpos = pos;
-                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
-                       return;
-               }
-       }
-#else
-       tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent);
+       tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity);
 }
 
 /*
index 2d2334c563e2a05480e8f27e0fb898f645fe0f61..bdd39b1283f487fe0e74ab42135b6d66f4b180c7 100644 (file)
@@ -55,6 +55,9 @@ MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) {
        float velocity_difference;
        float clean_up_and_do_nothing;
 
+    if (self.deadflag != DEAD_NO)
+        return 0;
+
        new_velocity_gain = 0;
        clean_up_and_do_nothing = 0;
 
@@ -241,8 +244,6 @@ MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) {
                }
        }
 
-
-
        if (dodge_detected == 1) {
                self.last_dodging_time = time;
 
index 8da19cbec28f10bde4b1f3399bda4e3571c9b830..9dde1c7106dfcfca9f6b3f0cf89bf4cb757a48ac 100644 (file)
@@ -243,31 +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;
 
@@ -300,6 +327,13 @@ float W_BallisticBullet_LeaveSolid(entity e, vector vel, float constant)
        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 @@ 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:
@@ -333,12 +373,8 @@ void W_BallisticBullet_Touch (void)
                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 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
        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;
@@ -470,6 +511,9 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                                W_BallisticBullet_Hit();
                        }
 
+                       if(proj.dmg_radius < 0) // these NEVER penetrate solid
+                               break;
+
                        // if we hit "weapclip", bail out
                        //
                        // rationale of this check:
@@ -487,15 +531,13 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                        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 @@ void W_PrepareExplosionByDamage(entity attacker, void() explode)
        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;