Merge branch 'Mario/warmup_timer' into 'master'
authorMario <zacjardine@y7mail.com>
Wed, 26 Sep 2018 06:23:54 +0000 (06:23 +0000)
committerMario <zacjardine@y7mail.com>
Wed, 26 Sep 2018 06:23:54 +0000 (06:23 +0000)
Merge branch Mario/warmup_timer (XXS merge request)

See merge request xonotic/xonotic-data.pk3dir!598

29 files changed:
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
qcsrc/common/mapobjects/func/bobbing.qc
qcsrc/common/mapobjects/func/button.qc
qcsrc/common/mapobjects/func/plat.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc
qcsrc/common/physics/movetypes/movetypes.qc
qcsrc/common/physics/movetypes/movetypes.qh
qcsrc/common/physics/movetypes/walk.qc
qcsrc/common/physics/player.qc
qcsrc/common/t_items.qc
qcsrc/menu/item.qc
qcsrc/menu/item.qh
qcsrc/menu/item/container.qh
qcsrc/menu/item/image.qh
qcsrc/menu/item/inputbox.qc
qcsrc/menu/item/label.qh
qcsrc/menu/item/listbox.qh
qcsrc/menu/xonotic/crosshairpreview.qh
qcsrc/menu/xonotic/picker.qh
qcsrc/server/cheats.qc
qcsrc/server/cheats.qh
qcsrc/server/client.qc
qcsrc/server/client.qh
qcsrc/server/defs.qh
qcsrc/server/miscfunctions.qc
qcsrc/server/player.qc
qcsrc/server/weapons/weaponsystem.qc
xonotic-client.cfg

index 4c889cb24be655fe22afa1af098046b1a0219082..9cd378f0fe6eacd521fe22e6f0bf3c5557b00ce5 100644 (file)
@@ -380,12 +380,12 @@ MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
        entity frag_attacker = M_ARGV(1, entity);
        entity frag_target = M_ARGV(2, entity);
        float frag_damage = M_ARGV(7, float);
-       float damage_take = M_ARGV(4, float);
-       float damage_save = M_ARGV(5, float);
+       float damage_take = bound(0, M_ARGV(4, float), GetResourceAmount(frag_target, RESOURCE_HEALTH));
+       float damage_save = bound(0, M_ARGV(5, float), GetResourceAmount(frag_target, RESOURCE_ARMOR));
 
        float excess = max(0, frag_damage - damage_take - damage_save);
 
-       if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
+       if (frag_target != frag_attacker && IS_PLAYER(frag_attacker) && DIFF_TEAM(frag_target, frag_attacker))
                GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
 }
 
index b647e15a826e48164f03db46c5f62114a8e6afc6..60920fafb8c5c95599af7b2090570bfc30ae84d6 100644 (file)
@@ -48,6 +48,8 @@ spawnfunc(func_bobbing)
 
        this.active = ACTIVE_ACTIVE;
 
+       this.draggable = drag_undraggable;
+
        // damage when blocked
        setblocked(this, generic_plat_blocked);
        if(this.dmg && (this.message == ""))
index 44e31284336aae99eb35f580dff390b5db98797b..a8537f172534225adce4855a8713e34fdaecbcfb 100644 (file)
@@ -158,6 +158,7 @@ spawnfunc(func_button)
         precache_sound(this.noise);
 
        this.active = ACTIVE_ACTIVE;
+       this.draggable = drag_undraggable;
 
        this.pos1 = this.origin;
        this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
index b052336217990a32a646d852679bc3c0d1d83c20..53dbed02fa42a50580b69efe7ef80143ba0b0f5e 100644 (file)
@@ -103,6 +103,7 @@ spawnfunc(func_plat)
        this.angles = '0 0 0';
 
        this.classname = "plat";
+       this.draggable = drag_undraggable;
        if (!InitMovingBrushTrigger(this))
                return;
        this.effects |= EF_LOWPRECISION;
index b7cdbf05b83c171ad278e61a3eb7e9c021ff78d6..9338c986c9d6ca3e3cd571c51895697a113e0543 100644 (file)
@@ -423,7 +423,7 @@ void buff_Medic_Heal(entity this)
 {
        FOREACH_CLIENT(IS_PLAYER(it) && it != this && vdist(it.origin - this.origin, <=, autocvar_g_buffs_medic_heal_range),
        {
-               if (!SAME_TEAM(it, this))
+               if (DIFF_TEAM(it, this))
                {
                        continue;
                }
index ee2a5be7f504d11c376bd85b31ec28b505b7eeec..fdcc4beee5fb51ab89c4ca8774638aa435241d14 100644 (file)
@@ -90,7 +90,7 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
                        if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_max && tested >= autocvar_g_spawn_near_teammate_ignore_spawnpoint_max) break;
 
                        if (PHYS_INPUT_BUTTON_CHAT(it)) continue;
-                       if (!SAME_TEAM(player, it)) continue;
+                       if (DIFF_TEAM(player, it)) continue;
                        if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && GetResourceAmount(it, RESOURCE_HEALTH) < autocvar_g_balance_health_regenstable) continue;
                        if (IS_DEAD(it)) continue;
                        if (time < it.msnt_timer) continue;
index e518fe21027fa5089623adf331c4ecabae65607d..e31b4076beca1072f2e1870f61fa0b73ec6800da 100644 (file)
@@ -406,11 +406,11 @@ entity _Movetype_TestEntityPosition_ent;
 bool _Movetype_TestEntityPosition(vector ofs)  // SV_TestEntityPosition
 {
     entity this = _Movetype_TestEntityPosition_ent;
-//     vector org = this.origin + ofs;
+       vector org = this.origin + ofs;
 
        int cont = this.dphitcontentsmask;
        this.dphitcontentsmask = DPCONTENTS_SOLID;
-       tracebox(this.origin, this.mins, this.maxs, this.origin, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
+       tracebox(org, this.mins, this.maxs, org, ((this.move_movetype == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), this);
        this.dphitcontentsmask = cont;
 
        if(trace_startsolid)
@@ -421,11 +421,11 @@ bool _Movetype_TestEntityPosition(vector ofs)  // SV_TestEntityPosition
        return false;
 }
 
-bool _Movetype_UnstickEntity(entity this)  // SV_UnstickEntity
+int _Movetype_UnstickEntity(entity this)  // SV_UnstickEntity
 {
     _Movetype_TestEntityPosition_ent = this;
        if (!_Movetype_TestEntityPosition(' 0  0  0')) {
-           return true;
+           return UNSTICK_FINE;
        }
        #define X(v) if (_Movetype_TestEntityPosition(v))
        X('-1  0  0') X(' 1  0  0')
@@ -444,13 +444,32 @@ bool _Movetype_UnstickEntity(entity this)  // SV_UnstickEntity
         {
             LOG_DEBUGF("Can't unstick an entity (edict: %d, classname: %s, origin: %s)",
                 etof(this), this.classname, vtos(this.origin));
-            return false;
+            return UNSTICK_STUCK;
         }
        }
        LOG_DEBUGF("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)",
                etof(this), this.classname, vtos(this.origin));
        _Movetype_LinkEdict(this, true);
-       return true;
+       return UNSTICK_FIXED;
+}
+
+void _Movetype_CheckStuck(entity this)  // SV_CheckStuck
+{
+       int unstick = _Movetype_UnstickEntity(this); // sets test position entity
+       switch(unstick)
+       {
+               case UNSTICK_FINE:
+                       this.oldorigin = this.origin;
+                       break;
+               case UNSTICK_FIXED:
+                       break; // already sorted
+               case UNSTICK_STUCK:
+                       vector offset = this.oldorigin - this.origin;
+                       if(!_Movetype_TestEntityPosition(offset))
+                               _Movetype_LinkEdict(this, false);
+                       // couldn't unstick, should we warn about this?
+                       break;
+       }
 }
 
 vector _Movetype_ClipVelocity(vector vel, vector norm, float f)  // SV_ClipVelocity
index 20f9adba1076a7b3499f60b0ed9096ec41f0d6d2..62b7964d98db09a2906f7731658c99085d79d43b 100644 (file)
@@ -80,10 +80,16 @@ void set_movetype(entity this, int mt);
 .float move_suspendedinair;
 .float move_didgravity;
 
+// unsticking
+const int UNSTICK_FINE = 0;
+const int UNSTICK_FIXED = 1;
+const int UNSTICK_STUCK = 2;
+
 void _Movetype_WallFriction(entity this, vector stepnormal);
 int _Movetype_FlyMove(entity this, float dt, bool applygravity, vector stepnormal, float stepheight);
 void _Movetype_CheckVelocity(entity this);
 void _Movetype_CheckWaterTransition(entity ent);
+void _Movetype_CheckStuck(entity this);
 float _Movetype_CheckWater(entity ent);
 void _Movetype_LinkEdict_TouchAreaGrid(entity this);
 void _Movetype_LinkEdict(entity this, float touch_triggers);
@@ -98,7 +104,7 @@ void Movetype_Physics_NoMatchServer(entity this);
 void _Movetype_LinkEdict(entity this, float touch_triggers);
 void _Movetype_LinkEdict_TouchAreaGrid(entity this);
 
-float _Movetype_UnstickEntity(entity this);
+int _Movetype_UnstickEntity(entity this);
 
 const int MAX_CLIP_PLANES = 5;
 
@@ -126,6 +132,8 @@ const int MOVETYPE_ANGLENOCLIP      = 1;
 const int MOVETYPE_ANGLECLIP        = 2;
 #endif
 
+const int MOVETYPE_QCPLAYER = 150; // QC-driven player physics, no think functions!
+
 const int FL_ONSLICK = BIT(20);
 
 const int MOVETYPE_FAKEPUSH         = 13;
index 6e4c548d6cd8aecdd2ced19a27d7f31b406524bf..c0f2fac9640be94fa6c550536f029c2197180e38 100644 (file)
@@ -8,7 +8,7 @@ void _Movetype_Physics_Walk(entity this, float dt)  // SV_WalkMove
                return;
 
        if (GAMEPLAYFIX_UNSTICKPLAYERS(this))
-               _Movetype_UnstickEntity(this);
+               _Movetype_CheckStuck(this);
 
        bool applygravity = (!_Movetype_CheckWater(this) && this.move_movetype == MOVETYPE_WALK && !(this.flags & FL_WATERJUMP));
 
@@ -170,6 +170,13 @@ void _Movetype_Physics_Walk(entity this, float dt)  // SV_WalkMove
        {
                // this has been disabled so that you can't jump when you are stepping
                // up while already jumping (also known as the Quake2 double jump bug)
+               // LordHavoc: disabled this check so you can walk on monsters/players
+               //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
+               if(GAMEPLAYFIX_STEPDOWN(this) == 2)
+               {
+                       SET_ONGROUND(this);
+                       this.groundentity = trace_ent;
+               }
        }
        else
        {
index 572bee349f205ca81caac2d23d0ff6da1d839696..3f220e84d9cf42f559c23882b45377939b7dd03c 100644 (file)
 // client side physics
 bool Physics_Valid(string thecvar)
 {
-       return autocvar_g_physics_clientselect && thecvar != "" && thecvar && thecvar != "default" && strhasword(autocvar_g_physics_clientselect_options, thecvar);
+       return thecvar != "" && thecvar && thecvar != "default" && strhasword(autocvar_g_physics_clientselect_options, thecvar);
 }
 
 float Physics_ClientOption(entity this, string option, float defaultval)
 {
+       if(!autocvar_g_physics_clientselect)
+               return defaultval;
+
        if(IS_REAL_CLIENT(this) && Physics_Valid(CS(this).cvar_cl_physics))
        {
                string s = strcat("g_physics_", CS(this).cvar_cl_physics, "_", option);
                if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
                        return cvar(s);
        }
-       if(autocvar_g_physics_clientselect && autocvar_g_physics_clientselect_default && autocvar_g_physics_clientselect_default != "")
+       if(autocvar_g_physics_clientselect_default && autocvar_g_physics_clientselect_default != "" && autocvar_g_physics_clientselect_default != "default")
        {
+               // NOTE: not using Physics_Valid here, so the default can be forced to something normally unavailable
                string s = strcat("g_physics_", autocvar_g_physics_clientselect_default, "_", option);
                if(cvar_type(s) & CVAR_TYPEFLAG_EXISTS)
                        return cvar(s);
index 0d4d2b92ab2c7221621379a5bf0b77b2d0730146..dfee5330df713431f4afba5cc9be713504171323 100644 (file)
@@ -856,7 +856,7 @@ float Item_GiveTo(entity item, entity player)
                return 0;
 
        // crude hack to enforce switching weapons
-       if(g_cts && item.itemdef.instanceOfWeaponPickup)
+       if(g_cts && item.itemdef.instanceOfWeaponPickup && !CS(player).cvar_cl_cts_noautoswitch)
        {
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
index a5c7cfa8544c70219099a4a12079b7a87dd5a408..6d725259d281ffeb8297902f8c4c62712e54b62f 100644 (file)
@@ -3,26 +3,26 @@
 #include "item/container.qh"
 #include "item/borderimage.qh"
 
-       METHOD(Item, destroy, void(Item this))
+       METHOD(MenuItem, destroy, void(MenuItem this))
        {
                // free memory associated with this
        }
 
-       METHOD(Item, relinquishFocus, void(Item this))
+       METHOD(MenuItem, relinquishFocus, void(MenuItem this))
        {
                entity par = this.parent;
                if (!par) return;
                if (par.instanceOfContainer) par.setFocus(par, NULL);
        }
 
-       METHOD(Item, resizeNotify, void(Item this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
+       METHOD(MenuItem, resizeNotify, void(MenuItem this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
        {
                this.origin = absOrigin;
                this.size = absSize;
        }
 
        int autocvar_menu_showboxes;
-       METHOD(Item, draw, void(Item this))
+       METHOD(MenuItem, draw, void(MenuItem this))
        {
                if (!autocvar_menu_showboxes) return;
                vector rgb = '1 0 1';
                }
        }
 
-       METHOD(Item, showNotify, void(Item this))
+       METHOD(MenuItem, showNotify, void(MenuItem this))
        {}
 
-       METHOD(Item, hideNotify, void(Item this))
+       METHOD(MenuItem, hideNotify, void(MenuItem this))
        {}
 
-       METHOD(Item, keyDown, float(Item this, float scan, float ascii, float shift))
+       METHOD(MenuItem, keyDown, float(MenuItem this, float scan, float ascii, float shift))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, keyUp, float(Item this, float scan, float ascii, float shift))
+       METHOD(MenuItem, keyUp, float(MenuItem this, float scan, float ascii, float shift))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, mouseMove, float(Item this, vector pos))
+       METHOD(MenuItem, mouseMove, float(MenuItem this, vector pos))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, mousePress, bool(Item this, vector pos))
+       METHOD(MenuItem, mousePress, bool(MenuItem this, vector pos))
        {
                return false;  // unhandled
        }
 
-       METHOD(Item, mouseDrag, float(Item this, vector pos))
+       METHOD(MenuItem, mouseDrag, float(MenuItem this, vector pos))
        {
                return 0;  // unhandled
        }
 
-       METHOD(Item, mouseRelease, float(Item this, vector pos))
+       METHOD(MenuItem, mouseRelease, float(MenuItem this, vector pos))
        {
                return 0;  // unhandled
        }
 
     void m_play_focus_sound();
 
-       METHOD(Item, focusEnter, void(Item this))
+       METHOD(MenuItem, focusEnter, void(MenuItem this))
        {
                if (this.allowFocusSound) m_play_focus_sound();
        }
 
-       METHOD(Item, focusLeave, void(Item this))
+       METHOD(MenuItem, focusLeave, void(MenuItem this))
        {}
 
-       METHOD(Item, toString, string(Item this))
+       METHOD(MenuItem, toString, string(MenuItem this))
        {
                return string_null;
        }
index 6cee17b3fdd5f9ccd24a66d078f040aaee9110a2..dd1d0679bed6c106e0ff8cad1fd4c9a1064c07e7 100644 (file)
@@ -5,28 +5,28 @@
 #include "draw.qh"
 #include "menu.qh"
 
-CLASS(Item, Object)
-       METHOD(Item, draw, void(Item));
-       METHOD(Item, keyDown, float(Item, float, float, float));
-       METHOD(Item, keyUp, float(Item, float, float, float));
-       METHOD(Item, mouseMove, float(Item, vector));
-       METHOD(Item, mousePress, bool(Item this, vector pos));
-       METHOD(Item, mouseDrag, float(Item, vector));
-       METHOD(Item, mouseRelease, float(Item, vector));
-       METHOD(Item, focusEnter, void(Item));
-       METHOD(Item, focusLeave, void(Item));
-       METHOD(Item, resizeNotify, void(Item, vector, vector, vector, vector));
-       METHOD(Item, relinquishFocus, void(Item));
-       METHOD(Item, showNotify, void(Item));
-       METHOD(Item, hideNotify, void(Item));
-       METHOD(Item, toString, string(Item));
-       METHOD(Item, destroy, void(Item));
-       ATTRIB(Item, focused, float, 0);
-       ATTRIB(Item, focusable, float, 0);
-       ATTRIB(Item, allowFocusSound, float, 0);
-       ATTRIB(Item, parent, entity);
-       ATTRIB(Item, preferredFocusPriority, float, 0);
-       ATTRIB(Item, origin, vector, '0 0 0');
-       ATTRIB(Item, size, vector, '0 0 0');
-       ATTRIB(Item, tooltip, string);
-ENDCLASS(Item)
+CLASS(MenuItem, Object)
+       METHOD(MenuItem, draw, void(MenuItem));
+       METHOD(MenuItem, keyDown, float(MenuItem, float, float, float));
+       METHOD(MenuItem, keyUp, float(MenuItem, float, float, float));
+       METHOD(MenuItem, mouseMove, float(MenuItem, vector));
+       METHOD(MenuItem, mousePress, bool(MenuItem this, vector pos));
+       METHOD(MenuItem, mouseDrag, float(MenuItem, vector));
+       METHOD(MenuItem, mouseRelease, float(MenuItem, vector));
+       METHOD(MenuItem, focusEnter, void(MenuItem));
+       METHOD(MenuItem, focusLeave, void(MenuItem));
+       METHOD(MenuItem, resizeNotify, void(MenuItem, vector, vector, vector, vector));
+       METHOD(MenuItem, relinquishFocus, void(MenuItem));
+       METHOD(MenuItem, showNotify, void(MenuItem));
+       METHOD(MenuItem, hideNotify, void(MenuItem));
+       METHOD(MenuItem, toString, string(MenuItem));
+       METHOD(MenuItem, destroy, void(MenuItem));
+       ATTRIB(MenuItem, focused, float, 0);
+       ATTRIB(MenuItem, focusable, float, 0);
+       ATTRIB(MenuItem, allowFocusSound, float, 0);
+       ATTRIB(MenuItem, parent, entity);
+       ATTRIB(MenuItem, preferredFocusPriority, float, 0);
+       ATTRIB(MenuItem, origin, vector, '0 0 0');
+       ATTRIB(MenuItem, size, vector, '0 0 0');
+       ATTRIB(MenuItem, tooltip, string);
+ENDCLASS(MenuItem)
index b73752685030a8ef57277ddaf3a3b7b7279f26f1..bc2d8e6d0bcce9e991861781e7ff3a76e0f0c760 100644 (file)
@@ -2,7 +2,7 @@
 
 #include <menu/item.qh>
 
-CLASS(Container, Item)
+CLASS(Container, MenuItem)
        METHOD(Container, draw, void(entity));
        METHOD(Container, keyUp, float(entity, float, float, float));
        METHOD(Container, keyDown, float(entity, float, float, float));
index 726f328600d79b570c210b3bb234006868ef2982..0db9c3719ac8ae9135e9662680dfc57ac6686190 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(Image, Item)
+CLASS(Image, MenuItem)
        METHOD(Image, configureImage, void(entity, string));
        METHOD(Image, draw, void(entity));
        METHOD(Image, toString, string(entity));
index d02f4661f5cd84bf891af26a6c1bef694244f463..3272ed54f39ec1953ff8e61b822cced36287b414 100644 (file)
                        }
 
                // skipping SUPER(InputBox).draw(me);
-               Item_draw(me);
+               MenuItem_draw(me);
        }
 
        void InputBox_showNotify(entity me)
index f91ae8ad3cb12a13265d085fe937cf32959f2a95..2439d1d5beafbfa72c206bfe422a25c9135517e3 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(Label, Item)
+CLASS(Label, MenuItem)
        METHOD(Label, configureLabel, void(entity, string, float, float));
        METHOD(Label, draw, void(entity));
        METHOD(Label, resizeNotify, void(entity, vector, vector, vector, vector));
index b3f5164a4d0937f769a55c68fb9cfbf474b07a99..f60066cd7b3d941526040fa85cbea64f6c5247de 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(ListBox, Item)
+CLASS(ListBox, MenuItem)
        METHOD(ListBox, resizeNotify, void(entity, vector, vector, vector, vector));
        METHOD(ListBox, configureListBox, void(entity, float, float));
        METHOD(ListBox, draw, void(entity));
index 7bf363def7f4b42ebf413bcea99b7871a7418a39..7499f4462dab79698e1609d071becad5f80f139f 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(XonoticCrosshairPreview, Item)
+CLASS(XonoticCrosshairPreview, MenuItem)
        METHOD(XonoticCrosshairPreview, configureXonoticCrosshairPreview, void(entity));
        METHOD(XonoticCrosshairPreview, draw, void(entity));
        ATTRIB(XonoticCrosshairPreview, src, string);
index c98e9fc9b6fa8f082a3bd346dad51c48edd36048..bbff7d551be6b22d04c68b0f2da9a13ba9af9958 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "../item.qh"
-CLASS(XonoticPicker, Item)
+CLASS(XonoticPicker, MenuItem)
        METHOD(XonoticPicker, configureXonoticPicker, void(entity));
        METHOD(XonoticPicker, mousePress, bool(XonoticPicker this, vector pos));
        METHOD(XonoticPicker, mouseRelease, float(entity, vector));
index e894e85b4fa045026bd09683b8a5dd57f0e02327..5ca5270d614dda0b5212a827c5fa5922162e8f51 100644 (file)
@@ -839,7 +839,7 @@ float Drag(entity this, float force_allow_pick, float ischeat)
                                                }
                                                // Find e and pick
                                                if(e && pick)
-                                                       if(Drag_IsDraggable(e))
+                                                       if(Drag_IsDraggable(e, this))
                                                        {
                                                                if(ischeat)
                                                                        IS_CHEAT(this, 0, 0, CHRAME_DRAG);
@@ -915,31 +915,24 @@ void Drag_Finish(entity dragger)
        }
 }
 
-float Drag_IsDraggable(entity draggee)
+bool drag_undraggable(entity draggee, entity dragger)
+{
+       // stuff probably shouldn't need this, we should figure out why they do!
+       // exceptions of course are observers and weapon entities, where things mess up
+       return false;
+}
+
+float Drag_IsDraggable(entity draggee, entity dragger)
 {
        // TODO add more checks for bad stuff here
        if(draggee == NULL)
                return false;
-       if(draggee.classname == "func_bobbing")
-               return false;
        if(draggee.classname == "door") // FIXME find out why these must be excluded, or work around the problem (trying to drag these causes like 4 fps)
-               return false;
-       if(draggee.classname == "plat")
-               return false;
-       if(draggee.classname == "func_button")
-               return false;
+               return false; // probably due to BSP collision
 //     if(draggee.model == "")
 //             return false;
-       if(IS_SPEC(draggee))
-               return false;
-       if(IS_OBSERVER(draggee))
-               return false;
-       if(draggee.classname == "exteriorweaponentity")
-               return false;
-       if(draggee.classname == "weaponentity")
-               return false;
 
-       return true;
+       return ((draggee.draggable) ? draggee.draggable(draggee, dragger) : true);
 }
 
 float Drag_MayChangeAngles(entity draggee)
@@ -1017,7 +1010,7 @@ float Drag_IsDragging(entity dragger)
                dragger.dragentity = NULL;
                return false;
        }
-       if(!Drag_CanDrag(dragger) || !Drag_IsDraggable(dragger.dragentity))
+       if(!Drag_CanDrag(dragger) || !Drag_IsDraggable(dragger.dragentity, dragger))
        {
                Drag_Finish(dragger);
                return false;
index 0dc6a92d9c45b5f103e432fabaa59f8c3db45bb1..962e017a19d6dad9e4919c86d53b20bb92efb84c 100644 (file)
@@ -14,12 +14,15 @@ float CheatFrame(entity this);
 
 const float CHRAME_DRAG = 8;
 
+bool drag_undraggable(entity draggee, entity dragger);
+
+.bool(entity this, entity dragger) draggable;
 void Drag_MoveDrag(entity from, entity to); // call this from CopyBody
 void DragBox_Think(entity this);
 float Drag(entity this, float force_allow_pick, float ischeat);
 void Drag_Begin(entity dragger, entity draggee, vector touchpoint);
 void Drag_Finish(entity dragger);
-float Drag_IsDraggable(entity draggee);
+bool Drag_IsDraggable(entity draggee, entity dragger);
 float Drag_MayChangeAngles(entity draggee);
 void Drag_MoveForward(entity dragger);
 void Drag_SetSpeed(entity dragger, float s);
index 9171444d8762ae3833a7fda6efc4e2dec07dcbe5..18d3d4ea3b724d8adb9b345e50dc3add4c96a496 100644 (file)
@@ -347,6 +347,7 @@ void PutObserverInServer(entity this)
        this.crouch = false;
        STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
+       this.draggable = drag_undraggable;
 
        this.items = 0;
        STAT(WEAPONS, this) = '0 0 0';
@@ -677,6 +678,8 @@ void PutPlayerInServer(entity this)
        this.event_damage = PlayerDamage;
        this.event_heal = PlayerHeal;
 
+       this.draggable = func_null;
+
        if(!this.bot_attack)
                IL_PUSH(g_bot_targets, this);
        this.bot_attack = true;
@@ -1143,6 +1146,8 @@ void ClientConnect(entity this)
        if (IS_REAL_CLIENT(this))
                sv_notice_join(this);
 
+       this.move_qcphysics = true;
+
        // update physics stats (players can spawn before physics runs)
        Physics_UpdateStats(this);
 
@@ -2562,7 +2567,7 @@ void DrownPlayer(entity this)
 
 void Player_Physics(entity this)
 {
-       set_movetype(this, this.move_movetype);
+       this.movetype = (this.move_qcphysics) ? MOVETYPE_QCPLAYER : this.move_movetype;
 
        if(!this.move_qcphysics)
                return;
index 26388e7b37e417cab785c318673ffec45462c6a5..80965de759808a0fb8b9c0fe190532b4b4d10ef2 100644 (file)
@@ -145,6 +145,7 @@ CLASS(Client, Object)
     ATTRIB(Client, cvar_cl_accuracy_data_receive, bool, this.cvar_cl_accuracy_data_receive);
     ATTRIBARRAY(Client, cvar_cl_weaponpriorities, string, 10);
     ATTRIB(Client, cvar_cl_weaponpriority, string, this.cvar_cl_weaponpriority);
+    ATTRIB(Client, cvar_cl_cts_noautoswitch, bool, this.cvar_cl_cts_noautoswitch);
 
     METHOD(Client, m_unwind, bool(Client this));
 
index 58111fb12bcfea9482a8d89b6d0dbceaf31ab42e..8f4e903490b04d211835f781adad688507ad5010 100644 (file)
@@ -168,6 +168,7 @@ float default_weapon_alpha;
 .float cvar_cl_jetpack_jump;
 .float cvar_cl_movement_track_canjump;
 .float cvar_cl_newusekeysupported;
+.float cvar_cl_cts_noautoswitch;
 
 .string cvar_g_xonoticversion;
 .string cvar_cl_weaponpriority;
index cf7266b483a9cb837b6a879ee35559128556da3d..47c0cb2fe4615af49105c651d2bc3192c9452b5f 100644 (file)
@@ -416,6 +416,8 @@ REPLICATE(cvar_cl_weaponimpulsemode, int, "cl_weaponimpulsemode");
 
 REPLICATE(cvar_g_xonoticversion, string, "g_xonoticversion");
 
+REPLICATE(cvar_cl_cts_noautoswitch, bool, "cl_cts_noautoswitch");
+
 /**
  * @param f -1: cleanup, 0: request, 1: receive
  */
index 87005ad4bbf6c0476dab47635e1a34c8db616e04..d8cc0dce04b105ec0b8da5dc7d75e00363aaf157 100644 (file)
@@ -468,7 +468,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                        if (this != attacker) {
                                float realdmg = damage - excess;
-                               if (IS_PLAYER(attacker)) {
+                               if (IS_PLAYER(attacker) && DIFF_TEAM(attacker, this)) {
                                        GameRules_scoring_add(attacker, DMG, realdmg);
                                }
                                if (IS_PLAYER(this)) {
index 2017e65a760792fd3d8f0db24603729a139e4cc5..d9155c2237b5b8f2e8d5582c6dc88e7834e906ce 100644 (file)
@@ -178,6 +178,7 @@ void CL_SpawnWeaponentity(entity actor, .entity weaponentity)
        setthink(view, CL_Weaponentity_Think);
        view.nextthink = time;
        view.viewmodelforclient = actor;
+       view.draggable = drag_undraggable;
        setcefc(view, CL_Weaponentity_CustomizeEntityForClient);
 
        wepent_link(view);
@@ -187,6 +188,7 @@ void CL_SpawnWeaponentity(entity actor, .entity weaponentity)
                entity exterior = actor.exteriorweaponentity = new(exteriorweaponentity);
                exterior.solid = SOLID_NOT;
                exterior.owner = actor;
+               exterior.draggable = drag_undraggable;
                exterior.weaponentity_fld = weaponentity;
                setorigin(exterior, '0 0 0');
                setthink(exterior, CL_ExteriorWeaponentity_Think);
index ed81e0fb558ebb17c1645912208ab96e1f161e8b..51c66081fc539c0d324b3573f4aadeb7cbba3423 100644 (file)
@@ -650,6 +650,8 @@ seta cl_jetpack_jump 1 "Activate jetpack by pressing jump in the air. 0 = Disabl
 seta cl_race_cptimes_showself 1 "Always show your own times as well as the current best on checkpoints in Race/CTS"
 seta cl_race_cptimes_onlyself 0 "Only show your own times on checkpoints in Race/CTS"
 
+seta cl_cts_noautoswitch 0 "Prevent forced switching to new weapons in CTS"
+
 set cl_stripcolorcodes 0       "experimental feature (notes: strips ALL color codes from messages!)"
 
 // Demo camera