]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Improve autoswitching options in CTS
authork9er <k9wolf@pm.me>
Tue, 14 Jan 2025 22:38:15 +0000 (22:38 +0000)
committerterencehill <piuntn@gmail.com>
Tue, 14 Jan 2025 22:38:15 +0000 (22:38 +0000)
commands.cfg
qcsrc/client/main.qc
qcsrc/common/replicate.qh
qcsrc/menu/xonotic/dialog_settings_game_weapons.qc
qcsrc/server/client.qh
qcsrc/server/items/items.qc
xonotic-client.cfg

index 8b9af84698dd3d43160c6447883aa6df3c010314..7c6e3b6f764b6145b167bf974420b5cf326736ed 100644 (file)
@@ -178,7 +178,7 @@ alias menu_showteamselect team_selection_show
 set sv_clientcommand_antispam_time 1 "amount of seconds after a command before another command can be called again without being considered spam; \"-1\" = no limit"
 set sv_clientcommand_antispam_count 8 "amount of commands considered spam before commands are rejected"
 seta sv_status_privacy 1 "hide IP addresses from \"status\" and \"who\" replies shown to clients"
-seta cl_autoswitch 1 "automatically switch to newly picked up weapons if they are better than what you are carrying"
+seta cl_autoswitch 1 "automatically switch to newly picked up weapons if they are better than what you are carrying (NOTE: see also cl_autoswitch_cts)"
 
 // commented out commands are really only intended for internal use, or already have declaration in the engine
 alias autoswitch           "qc_cmd_cmd    autoswitch           ${* ?}" // Whether or not to switch automatically when getting a better weapon
index 2e501ee046f72ee50daad6eaec2b33d468eaf66c..568f0f5a0a0b30739b0399c6e7c70d95bc1dd961 100644 (file)
@@ -93,6 +93,8 @@ void CSQC_Init(float apilevel, string enginename, float engineversion)
 
        registercvar("cl_dodging", "0");
 
+       registercvar("cl_autoswitch_cts", "-1");
+
        registercvar("cl_spawn_near_teammate", "1");
 
        registercvar("cl_weapon_switch_reload", "1");
index 6c66771f8aab4a812e50b9030385a3d688c19651..3f4a9ffc0ad60a9f1c9e65e40f18e09f1ddead63 100644 (file)
@@ -6,7 +6,7 @@
 REPLICATE_INIT(bool, cvar_cl_autoswitch);
 REPLICATE_INIT(int, cvar_cl_autoscreenshot);
 REPLICATE_INIT(bool, cvar_cl_clippedspectating);
-REPLICATE_INIT(bool, cvar_cl_cts_noautoswitch);
+REPLICATE_INIT(int, cvar_cl_autoswitch_cts);
 REPLICATE_INIT(vector, cvar_cl_handicap);
 REPLICATE_INIT(float, cvar_cl_handicap_damage_given);
 REPLICATE_INIT(float, cvar_cl_handicap_damage_taken);
@@ -15,7 +15,7 @@ REPLICATE_INIT(string, cvar_g_xonoticversion);
 REPLICATE(cvar_cl_autoswitch, bool, "cl_autoswitch");
 REPLICATE(cvar_cl_autoscreenshot, int, "cl_autoscreenshot");
 REPLICATE(cvar_cl_clippedspectating, bool, "cl_clippedspectating");
-REPLICATE(cvar_cl_cts_noautoswitch, bool, "cl_cts_noautoswitch");
+REPLICATE(cvar_cl_autoswitch_cts, int, "cl_autoswitch_cts");
 REPLICATE(cvar_cl_handicap, vector, "cl_handicap");
 REPLICATE(cvar_cl_handicap_damage_given, float, "cl_handicap_damage_given");
 REPLICATE(cvar_cl_handicap_damage_taken, float, "cl_handicap_damage_taken");
index 5c77faffb501ed0ca2aebf740dd8d559548b94d4..e5adc9a8048839a2f399cff454997bec28805898 100644 (file)
@@ -52,12 +52,20 @@ void XonoticGameWeaponsSettingsTab_fill(entity me)
                me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_weaponimpulsemode", _("Cycle through only usable weapon selections")));
                        e.sendCvars = true;
        me.TR(me);
+       me.TR(me);
+               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_attack_on_weapon_switch", _("Release attack buttons when you switch weapons")));
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox_T(0, "cl_autoswitch", _("Auto switch weapons on pickup"),
                        _("Automatically switch to newly picked up weapons if they are better than what you are carrying")));
                        e.sendCvars = true;
        me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_attack_on_weapon_switch", _("Release attack buttons when you switch weapons")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Auto switch in CTS:")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_autoswitch_cts"));
+                       e.addValue(e, _("Default"), "-1");
+                       e.addValue(e, _("Always"), "1");
+                       e.addValue(e, _("Never"), "0");
+                       e.configureXonoticTextSliderValues(e);
+                       e.sendCvars = true;
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox_T(0, "r_drawviewmodel", _("Draw 1st person weapon model"),
@@ -74,17 +82,16 @@ void XonoticGameWeaponsSettingsTab_fill(entity me)
                        _("Position of the weapon model; requires reconnect")));
                        setDependent(e, "r_drawviewmodel", 1, 1);
        me.TR(me);
-                       me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Weapon model opacity:")));
-                               setDependent(e, "r_drawviewmodel", 1, 1);
-
-                       me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_viewmodel_alpha"));
-                               setDependent(e, "r_drawviewmodel", 1, 1);
-                               e.addValue(e, "15%", "0.15");
-                               e.addValue(e, "25%", "0.25");
-                               e.addValue(e, "50%", "0.5");
-                               e.addValue(e, "75%", "0.75");
-                               e.addValue(e, "100%", "1");
-                               e.configureXonoticTextSliderValues(e);
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Weapon model opacity:")));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_viewmodel_alpha"));
+                       setDependent(e, "r_drawviewmodel", 1, 1);
+                       e.addValue(e, "15%", "0.15");
+                       e.addValue(e, "25%", "0.25");
+                       e.addValue(e, "50%", "0.5");
+                       e.addValue(e, "75%", "0.75");
+                       e.addValue(e, "100%", "1");
+                       e.configureXonoticTextSliderValues(e);
        me.TR(me);
        me.TR(me);
                me.TDempty(me, 0.2);
index cd3c162baf9778a789f98319183f6bccbcb10494..5aa2a42ac5fc25e745b84fa4e71636352a030649 100644 (file)
@@ -228,7 +228,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);
+    ATTRIB(Client, cvar_cl_autoswitch_cts, int, this.cvar_cl_autoswitch_cts);
     ATTRIB(Client, cvar_cl_weapon_switch_reload, bool, this.cvar_cl_weapon_switch_reload);
     ATTRIB(Client, cvar_cl_weapon_switch_fallback_to_impulse, bool, this.cvar_cl_weapon_switch_fallback_to_impulse);
 #endif
index 8e42d88650c632d0dab383e34a824a79fcd6b40a..e94b752ffde6d3149979477ca0bb7212b3b90d33 100644 (file)
@@ -528,21 +528,22 @@ bool Item_GiveTo(entity item, entity player)
 {
        // if nothing happens to player, just return without taking the item
        int _switchweapon = 0;
-       // in case the player has autoswitch enabled do the following:
+       // in case the player has cl_autoswitch enabled do the following:
        // if the player is using their best weapon before items are given, they
        // probably want to switch to an even better weapon after items are given
 
-       if(CS_CVAR(player).cvar_cl_autoswitch)
+       bool use_cts_autoswitch = (g_cts && item.itemdef.instanceOfWeaponPickup && (CS_CVAR(player).cvar_cl_autoswitch_cts != -1));
+       if (CS_CVAR(player).cvar_cl_autoswitch && !use_cts_autoswitch)
        {
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        .entity weaponentity = weaponentities[slot];
-                       if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
+                       if (player.(weaponentity).m_weapon != WEP_Null || slot == 0)
                        {
-                               if(player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity))
+                               if (player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity))
                                        _switchweapon |= BIT(slot);
 
-                               if(!(STAT(WEAPONS, player) & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
+                               if (!(STAT(WEAPONS, player) & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
                                        _switchweapon |= BIT(slot);
                        }
                }
@@ -653,26 +654,32 @@ bool Item_GiveTo(entity item, entity player)
        if (!pickedup)
                return false;
 
-       // crude hack to enforce switching weapons
-       if(g_cts && item.itemdef.instanceOfWeaponPickup && !CS_CVAR(player).cvar_cl_cts_noautoswitch)
+       if(use_cts_autoswitch)
        {
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               // CTS handling: never switch (0), always switch (1)
+               if(CS_CVAR(player).cvar_cl_autoswitch_cts == 1)
                {
-                       .entity weaponentity = weaponentities[slot];
-                       if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
-                               W_SwitchWeapon_Force(player, REGISTRY_GET(Weapons, item.weapon), weaponentity);
+                       // crude hack to enforce switching weapons
+                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                       {
+                               .entity weaponentity = weaponentities[slot];
+                               if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
+                                       W_SwitchWeapon_Force(player, REGISTRY_GET(Weapons, item.weapon), weaponentity);
+                       }
                }
-               return true;
        }
-
-       if(_switchweapon)
+       else if(_switchweapon)
        {
+               // non-CTS handling: weaponpriority-based autoswitch
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        .entity weaponentity = weaponentities[slot];
                        if(_switchweapon & BIT(slot))
-                       if(player.(weaponentity).m_switchweapon != w_getbestweapon(player, weaponentity))
-                               W_SwitchWeapon_Force(player, w_getbestweapon(player, weaponentity), weaponentity);
+                       {
+                               Weapon best_wep = w_getbestweapon(player, weaponentity);
+                               if(player.(weaponentity).m_switchweapon != best_wep)
+                                       W_SwitchWeapon_Force(player, best_wep, weaponentity);
+                       }
                }
        }
 
@@ -1598,7 +1605,8 @@ float GiveItems(entity e, float beginarg, float endarg)
 
        int _switchweapon = 0;
 
-       if(CS_CVAR(e).cvar_cl_autoswitch)
+       bool use_cts_autoswitch = (g_cts && (CS_CVAR(e).cvar_cl_autoswitch_cts != -1));
+       if(CS_CVAR(e).cvar_cl_autoswitch && !use_cts_autoswitch)
        {
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
@@ -1624,6 +1632,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        PREGIVE_RESOURCE(e, RES_ARMOR);
        PREGIVE_RESOURCE(e, RES_HEALTH);
 
+       Weapon last_wep = WEP_Null;
        for(i = beginarg; i < endarg; ++i)
        {
                cmd = argv(i);
@@ -1733,6 +1742,7 @@ float GiveItems(entity e, float beginarg, float endarg)
                                });
                                FOREACH(Weapons, it != WEP_Null && (cmd == it.netname || cmd == it.m_deprecated_netname), {
                                        got += GiveWeapon(e, it.m_id, op, val);
+                                       last_wep = it;
                                        break;
                                });
                                break;
@@ -1773,24 +1783,35 @@ float GiveItems(entity e, float beginarg, float endarg)
        if(e.statuseffects)
                StatusEffects_update(e);
 
-       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       if(last_wep != WEP_Null && use_cts_autoswitch)
        {
-               .entity weaponentity = weaponentities[slot];
-               if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
-               if(!(STAT(WEAPONS, e) & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
-                       _switchweapon |= BIT(slot);
+               // CTS handling: never switch (0), always switch (1)
+               if(CS_CVAR(e).cvar_cl_autoswitch_cts == 1)
+               {
+                       // crude hack to enforce switching weapons
+                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                       {
+                               .entity weaponentity = weaponentities[slot];
+                               if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
+                                       W_SwitchWeapon_Force(e, last_wep, weaponentity);
+                       }
+               }
        }
-
-       if(_switchweapon)
+       else
        {
+               // non-CTS handling: weaponpriority-based autoswitch
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        .entity weaponentity = weaponentities[slot];
+                       if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
+                       if(!(STAT(WEAPONS, e) & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
+                               _switchweapon |= BIT(slot);
+
                        if(_switchweapon & BIT(slot))
                        {
-                               Weapon wep = w_getbestweapon(e, weaponentity);
-                               if(wep != e.(weaponentity).m_switchweapon)
-                                       W_SwitchWeapon_Force(e, wep, weaponentity);
+                               Weapon best_wep = w_getbestweapon(e, weaponentity);
+                               if(e.(weaponentity).m_switchweapon != best_wep)
+                                       W_SwitchWeapon_Force(e, best_wep, weaponentity);
                        }
                }
        }
index 97561313b3a0f45a13632f0e8f184bb0df65f02c..5b620f00702179549211129f7e47e565eeff64eb 100644 (file)
@@ -719,7 +719,7 @@ seta cl_race_cptimes_namesize 10 "maximum length of player names in race checkpo
 seta cl_race_checkpoint_splits_console 1 "print race checkpoint splits to console"
 seta cl_race_checkpoint_splits_hud 1 "show race checkpoint splits on HUD in infomessages"
 
-seta cl_cts_noautoswitch 0 "prevent forced switching to new weapons in CTS"
+seta cl_autoswitch_cts -1 "\"-1\" = fallback to the behavior of cl_autoswitch, \"0\" = never autoswitch in CTS, \"1\" = always autoswitch in CTS"
 
 set cl_stripcolorcodes 0       "experimental feature (NOTE: strips ALL color codes from messages!)"