From 8dbae017359f4eebbd9c331ebbfd1d10376c1841 Mon Sep 17 00:00:00 2001 From: k9er Date: Tue, 14 Jan 2025 22:38:15 +0000 Subject: [PATCH] Improve autoswitching options in CTS --- commands.cfg | 2 +- qcsrc/client/main.qc | 2 + qcsrc/common/replicate.qh | 4 +- .../xonotic/dialog_settings_game_weapons.qc | 31 +++++--- qcsrc/server/client.qh | 2 +- qcsrc/server/items/items.qc | 77 ++++++++++++------- xonotic-client.cfg | 2 +- 7 files changed, 75 insertions(+), 45 deletions(-) diff --git a/commands.cfg b/commands.cfg index 8b9af8469..7c6e3b6f7 100644 --- a/commands.cfg +++ b/commands.cfg @@ -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 diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index 2e501ee04..568f0f5a0 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -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"); diff --git a/qcsrc/common/replicate.qh b/qcsrc/common/replicate.qh index 6c66771f8..3f4a9ffc0 100644 --- a/qcsrc/common/replicate.qh +++ b/qcsrc/common/replicate.qh @@ -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"); diff --git a/qcsrc/menu/xonotic/dialog_settings_game_weapons.qc b/qcsrc/menu/xonotic/dialog_settings_game_weapons.qc index 5c77faffb..e5adc9a80 100644 --- a/qcsrc/menu/xonotic/dialog_settings_game_weapons.qc +++ b/qcsrc/menu/xonotic/dialog_settings_game_weapons.qc @@ -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); diff --git a/qcsrc/server/client.qh b/qcsrc/server/client.qh index cd3c162ba..5aa2a42ac 100644 --- a/qcsrc/server/client.qh +++ b/qcsrc/server/client.qh @@ -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 diff --git a/qcsrc/server/items/items.qc b/qcsrc/server/items/items.qc index 8e42d8865..e94b752ff 100644 --- a/qcsrc/server/items/items.qc +++ b/qcsrc/server/items/items.qc @@ -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); } } } diff --git a/xonotic-client.cfg b/xonotic-client.cfg index 97561313b..5b620f007 100644 --- a/xonotic-client.cfg +++ b/xonotic-client.cfg @@ -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!)" -- 2.39.5