handicap = 1 / (fabs(handicap) + 1);
}
handicap = DynamicHandicap_ClampHandicap(handicap);
- Handicap_SetForcedHandicap(it, handicap);
+ Handicap_SetForcedHandicap(it, handicap, false);
+ Handicap_SetForcedHandicap(it, handicap, true);
});
}
#pragma once
+// TODO: Remove cvar_cl_handicap vector after 0.9 release
+
#ifdef GAMEQC
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(float, cvar_cl_handicap);
+REPLICATE_INIT(vector, cvar_cl_handicap);
+REPLICATE_INIT(float, cvar_cl_handicap_damage_given);
+REPLICATE_INIT(float, cvar_cl_handicap_damage_taken);
REPLICATE_INIT(bool, cvar_cl_noantilag);
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_handicap, float, "cl_handicap");
+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");
REPLICATE(cvar_cl_noantilag, bool, "cl_noantilag");
REPLICATE(cvar_g_xonoticversion, string, "g_xonoticversion");
#endif
ATTRIB(Client, cvar_cl_pokenade_type, string, this.cvar_cl_pokenade_type);
ATTRIB(Client, cvar_cl_spawn_near_teammate, bool, this.cvar_cl_spawn_near_teammate);
ATTRIB(Client, cvar_cl_gunalign, int, this.cvar_cl_gunalign);
- ATTRIB(Client, cvar_cl_handicap, float, this.cvar_cl_handicap);
+ ATTRIB(Client, cvar_cl_handicap_damage_given, float, this.cvar_cl_handicap_damage_given);
+ ATTRIB(Client, cvar_cl_handicap_damage_taken, float, this.cvar_cl_handicap_damage_taken);
ATTRIB(Client, cvar_cl_clippedspectating, bool, this.cvar_cl_clippedspectating);
ATTRIB(Client, cvar_cl_autoscreenshot, int, this.cvar_cl_autoscreenshot);
ATTRIB(Client, cvar_cl_jetpack_jump, bool, this.cvar_cl_jetpack_jump);
#include <common/state.qh>
#include <server/client.qh>
-.float m_handicap; ///< Holds the handicap value.
+.float m_handicap_give; ///< Holds the forced handicap value.
+.float m_handicap_take; ///< Holds the forced handicap value.
void Handicap_Initialize(entity player)
{
- CS(player).m_handicap = 1;
+ // forced handicap defaults
+ CS(player).m_handicap_give = 1;
+ CS(player).m_handicap_take = 1;
}
-float Handicap_GetVoluntaryHandicap(entity player)
+float Handicap_GetVoluntaryHandicap(entity player, bool receiving)
{
- return bound(1.0, CS_CVAR(player).cvar_cl_handicap, 10.0);
+#if 0
+ if (receiving)
+ return bound(1.0, CS_CVAR(player).cvar_cl_handicap_damage_taken, 10.0);
+ else
+ return bound(1.0, CS_CVAR(player).cvar_cl_handicap_damage_given, 10.0);
+#else
+ // TODO: remove the else vector branch after 0.9 release
+ // Forwards compatibility for old clients on new servers. `cl_handicap 2`
+ // ( '2 0 0' ) is treated the same as `cl_handicap_damage_{given,taken} 2`.
+ // The x is give and y is take.
+ // '2 0 0' gives and takes x2
+ // '2 2 0' gives and takes x2
+ // '2 1 0' only gives x2
+ // '1 2 0' only takes x2
+ // z is wasted
+
+ int handicap_value;
+
+ // First read if the new cvars have a valid value,
+ // if they don't then read old cvar, checking if the old cvar has
+ // separate give and take values or we should use the first value for both
+ if (receiving)
+ {
+ if (CS_CVAR(player).cvar_cl_handicap_damage_taken > 1)
+ handicap_value = CS_CVAR(player).cvar_cl_handicap_damage_taken;
+ else if (CS_CVAR(player).cvar_cl_handicap.y > 0)
+ handicap_value = CS_CVAR(player).cvar_cl_handicap.y;
+ else
+ handicap_value = CS_CVAR(player).cvar_cl_handicap.x;
+ }
+ else
+ {
+ if (CS_CVAR(player).cvar_cl_handicap_damage_given > 1)
+ handicap_value = CS_CVAR(player).cvar_cl_handicap_damage_given;
+ else
+ handicap_value = CS_CVAR(player).cvar_cl_handicap.x;
+ }
+
+ return bound(1.0, handicap_value, 10.0);
+#endif
+
}
-float Handicap_GetForcedHandicap(entity player)
+float Handicap_GetForcedHandicap(entity player, bool receiving)
{
- return (CS(player)) ? CS(player).m_handicap : 1;
+ if (receiving)
+ return (CS(player)) ? CS(player).m_handicap_take : 1;
+ else
+ return (CS(player)) ? CS(player).m_handicap_give : 1;
+
}
-void Handicap_SetForcedHandicap(entity player, float value)
+void Handicap_SetForcedHandicap(entity player, float value, bool receiving)
{
if (value <= 0)
- {
error("Handicap_SetForcedHandicap: Invalid handicap value.");
- }
- CS(player).m_handicap = value;
+
+ if (receiving)
+ CS(player).m_handicap_take = value;
+ else
+ CS(player).m_handicap_give = value;
}
-float Handicap_GetTotalHandicap(entity player)
+float Handicap_GetTotalHandicap(entity player, bool receiving)
{
- return Handicap_GetForcedHandicap(player) * Handicap_GetVoluntaryHandicap(
- player);
+ return Handicap_GetForcedHandicap(player, receiving) *
+ Handicap_GetVoluntaryHandicap(player, receiving);
}
// weak players. Values greater than 1 make the game harder and values less than
// 1 make the game easier. Right now handicap only affects damage. There are 2
// types of handicap: voluntary and forced. Voluntary handicap can be set via
-// cl_handicap cvar. For obvious reasons, it can't be less than 1. Forced
+// cl_handicap cvars. For obvious reasons, it can't be less than 1. Forced
// handicap can be set by server mutators. The total handicap is the product of
// voluntary and forced handicap.
+// Both handicaps are separated into _take and _give so that mutators and
+// players are able to nerf their damage output or increase intake
+// without changing the other.
/// \brief Initializes handicap to its default value.
/// \param[in,out] player Player to initialize.
/// \brief Returns the voluntary handicap of the player.
/// \param[in] player Player to check.
+/// \param[in] receiving Whether handicap is for receiving or dealing.
/// \return Voluntary handicap of the player.
-float Handicap_GetVoluntaryHandicap(entity player);
+float Handicap_GetVoluntaryHandicap(entity player, bool receiving);
/// \brief Returns the forced handicap of the player.
/// \param[in] player Player to check.
+/// \param[in] receiving Whether handicap is for receiving or dealing.
/// \return Forced handicap of the player.
-float Handicap_GetForcedHandicap(entity player);
+float Handicap_GetForcedHandicap(entity player, bool receiving);
/// \brief Sets the forced handicap of the player.
/// \param[in] player Player to alter.
/// \param[in] value Handicap value to set.
+/// \param[in] receiving Whether handicap is for receiving or dealing.
/// \return No return.
-void Handicap_SetForcedHandicap(entity player, float value);
+void Handicap_SetForcedHandicap(entity player, float value, bool receiving);
/// \brief Returns the total handicap of the player.
/// \param[in] player Player to check.
+/// \param[in] receiving Whether handicap is for receiving or dealing.
/// \return Total handicap of the player.
-float Handicap_GetTotalHandicap(entity player);
+float Handicap_GetTotalHandicap(entity player, bool receiving);
{
if(!DEATH_ISSPECIAL(deathtype))
{
- damage *= Handicap_GetTotalHandicap(this);
+ damage *= Handicap_GetTotalHandicap(this, true);
if (this != attacker && IS_PLAYER(attacker))
{
- damage /= Handicap_GetTotalHandicap(attacker);
+ damage /= Handicap_GetTotalHandicap(attacker, false);
}
}
alias _gl_flashblend_update_11 "gl_flashblend 0"
alias gl_flashblend_update "_gl_flashblend_update_$r_shadow_realtime_dlight$r_showsurfaces"
-set cl_handicap 1 "multiplies damage received and divides damage dealt"
+// TODO: remove cl_handicap cvar after 0.9 release
+set cl_handicap 1 "multiplies damage received and divides damage dealt"
+alias cl_handicap "cl_handicap_damage_given ${* ?} ; cl_handicap_damage_taken ${* ?} ; set cl_handicap ${* ?}"
+set cl_handicap_damage_given 1 "damage given is divided by this factor if > 1"
+set cl_handicap_damage_taken 1 "damage taken is multiplied by this factor if > 1"
seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such"