From a1490ace561bf5e91699a6836c1d94515a953b0d Mon Sep 17 00:00:00 2001 From: otta8634 Date: Sat, 21 Dec 2024 23:50:54 +0800 Subject: [PATCH] Improve autoswitching options in CTS Removed cl_cts_noautoswitch and replaced it with cl_autoswitch_cts which has 3 options: - 0 (default): fallsback to the cl_autoswitch behavior. This may seem unnecessary, but it can be useful on some maps, manually editing the weapon priority list to choose when you autoswitch and when you don't. - 1: always autoswitch to the new weapon. - 2: never autoswitch to the new weapon. These options are of course only used in CTS, in other gamemodes (including Race) the cvar is ignored and cl_autoswitch is used. Also made the new cvar apply to cases where a trigger gives a player a weapon in CTS, which for some reason it didn't apply to before. Added a bit of documentation to affected functions. The new cvar name is easier to find and more intuitive in my opinion. --- commands.cfg | 2 +- qcsrc/common/replicate.qh | 4 +- qcsrc/server/client.qh | 2 +- qcsrc/server/items/items.qc | 77 +++++++++++++++++++++++-------------- xonotic-client.cfg | 2 +- 5 files changed, 54 insertions(+), 33 deletions(-) diff --git a/commands.cfg b/commands.cfg index ae8719a0f..0165d8f89 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. (Use -1 for no antispam 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/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/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 6adc4f9b4..3a791c634 100644 --- a/qcsrc/server/items/items.qc +++ b/qcsrc/server/items/items.qc @@ -529,21 +529,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); + if (CS_CVAR(player).cvar_cl_autoswitch && (!use_cts_autoswitch || !CS_CVAR(player).cvar_cl_autoswitch_cts)) { - 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); } } @@ -654,26 +655,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 && CS_CVAR(player).cvar_cl_autoswitch_cts != 0) { - for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) + // CTS handling: always switch (1), never switch (2) + 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); + } } } @@ -1583,7 +1590,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; + if(CS_CVAR(e).cvar_cl_autoswitch && (!use_cts_autoswitch || !CS_CVAR(e).cvar_cl_autoswitch_cts)) { for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { @@ -1609,6 +1617,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); @@ -1717,6 +1726,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; @@ -1757,24 +1767,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 && CS_CVAR(e).cvar_cl_autoswitch_cts != 0) { - .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: always switch (1), never switch (2) + 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 6668db2b4..642b97f76 100644 --- a/xonotic-client.cfg +++ b/xonotic-client.cfg @@ -720,7 +720,7 @@ seta cl_race_cptimes_namesize 10 "Maximum length of player names in checkpoint m seta cl_race_checkpoint_splits_console 1 "Print 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 0 "0 = fallback to the behavior of cl_autoswitch, 1 = always autoswitch in CTS, 2 = never autoswitch in CTS" set cl_stripcolorcodes 0 "experimental feature (notes: strips ALL color codes from messages!)" -- 2.39.2