From: TimePath Date: Sat, 16 Sep 2017 03:20:32 +0000 (+0000) Subject: Merge branch 'Lyberta/DynamicHandicap' into 'master' X-Git-Tag: xonotic-v0.8.5~2474 X-Git-Url: http://git.xonotic.org/?a=commitdiff_plain;h=8f2f6fdcbfd19b3c0e021e9f0d402b0f2ee0a64c;hp=f590d6c5b9082b17e92e2f6305cf410905b595f5;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'Lyberta/DynamicHandicap' into 'master' Dynamic handicap. See merge request xonotic/xonotic-data.pk3dir!485 --- diff --git a/mutators.cfg b/mutators.cfg index 5eb8d1b9d..be74e8187 100644 --- a/mutators.cfg +++ b/mutators.cfg @@ -464,3 +464,11 @@ set g_bugrigs_steer 1 "steering amount" // running guns // ============== set g_running_guns 0 "... or wonder, till it drives you mad, what would have followed if you had." + +// ================== +// dynamic handicap +// ================== +set g_dynamic_handicap 0 "Whether to enable dynamic handicap." +set g_dynamic_handicap_scale 1 "The scale of the handicap. Larger values mean more penalties for strong players and more buffs for weak players." +set g_dynamic_handicap_min 0 "The minimum value of the handicap." +set g_dynamic_handicap_max 0 "The maximum value of the handicap." diff --git a/qcsrc/common/mutators/mutator/_mod.inc b/qcsrc/common/mutators/mutator/_mod.inc index 0d6326fef..eeb93ba5e 100644 --- a/qcsrc/common/mutators/mutator/_mod.inc +++ b/qcsrc/common/mutators/mutator/_mod.inc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/common/mutators/mutator/_mod.qh b/qcsrc/common/mutators/mutator/_mod.qh index 917dc6557..956c0d975 100644 --- a/qcsrc/common/mutators/mutator/_mod.qh +++ b/qcsrc/common/mutators/mutator/_mod.qh @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.inc b/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.inc new file mode 100644 index 000000000..f4b0a30cd --- /dev/null +++ b/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.inc @@ -0,0 +1,4 @@ +// generated file; do not modify +#ifdef SVQC + #include +#endif diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.qh b/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.qh new file mode 100644 index 000000000..98fb4815c --- /dev/null +++ b/qcsrc/common/mutators/mutator/dynamic_handicap/_mod.qh @@ -0,0 +1 @@ +// generated file; do not modify diff --git a/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc b/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc new file mode 100644 index 000000000..5549085e7 --- /dev/null +++ b/qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc @@ -0,0 +1,139 @@ +/// \file +/// \brief Source file that contains implementation of the Dynamic handicap +/// mutator. +/// \author Lyberta +/// \copyright GNU GPLv2 or any later version. + +//======================= Global variables ==================================== + +int autocvar_g_dynamic_handicap; ///< Whether to enable dynamic handicap. +/// \brief The scale of the handicap. Larget values mean more penalties for +/// strong players and more buffs for weak players. +float autocvar_g_dynamic_handicap_scale; +float autocvar_g_dynamic_handicap_min; ///< The minimum value of the handicap. +float autocvar_g_dynamic_handicap_max; ///< The maximum value of the handicap. + +//====================== Forward declarations ================================= + +/// \brief Returns the base value of the handicap. +/// \param[in] player Player to evaluate. +/// \return Base handicap value. +float DynamicHandicap_GetBaseValue(entity player); + +/// \brief Scales the base value of the handicap. +/// \param[in] handicap Value to scale. +/// \return Scaled value. +float DynamicHandicap_ScaleHandicap(float handicap); + +/// \brief Clamps the value of the handicap. +/// \param[in] handicap Value to clamp. +/// \return Clamped value. +float DynamicHandicap_ClampHandicap(float handicap); + +//========================= Free functions ==================================== + +/// \brief Updates the handicap of a given player. +/// \param[in,out] player Player to update. +/// \return No return. +void DynamicHandicap_UpdateHandicap(entity player) +{ + float handicap = DynamicHandicap_GetBaseValue(player); + handicap = DynamicHandicap_ScaleHandicap(handicap); + handicap = DynamicHandicap_ClampHandicap(handicap); + Handicap_SetForcedHandicap(player, handicap); +} + +float DynamicHandicap_GetBaseValue(entity player) +{ + int kills = PlayerScore_Get(player, SP_KILLS); + int deaths = PlayerScore_Get(player, SP_DEATHS); + if (kills == deaths) + { + return 1; + } + if (deaths == 0) + { + return kills; + } + if (kills == 0) + { + return 1 / deaths; + } + return kills / deaths; +} + +float DynamicHandicap_ScaleHandicap(float handicap) +{ + if (handicap == 1) + { + return 1; + } + if (autocvar_g_dynamic_handicap_scale == 1) + { + return handicap; + } + if (handicap > 1) + { + handicap -= 1; + handicap *= autocvar_g_dynamic_handicap_scale; + return handicap + 1; + } + if (handicap < 1) + { + handicap = 1 / handicap; + handicap -= 1; + handicap *= autocvar_g_dynamic_handicap_scale; + handicap += 1; + return 1 / handicap; + } + return 1; +} + +float DynamicHandicap_ClampHandicap(float handicap) +{ + if ((autocvar_g_dynamic_handicap_min >= 0) && (handicap < + autocvar_g_dynamic_handicap_min)) + { + handicap = autocvar_g_dynamic_handicap_min; + } + if ((autocvar_g_dynamic_handicap_max > 0) && (handicap > + autocvar_g_dynamic_handicap_max)) + { + handicap = autocvar_g_dynamic_handicap_max; + } + return handicap; +} + +//============================= Hooks ======================================== + +REGISTER_MUTATOR(dynamic_handicap, autocvar_g_dynamic_handicap); + +MUTATOR_HOOKFUNCTION(dynamic_handicap, BuildMutatorsString) +{ + M_ARGV(0, string) = strcat(M_ARGV(0, string), ":handicap"); +} + +MUTATOR_HOOKFUNCTION(dynamic_handicap, BuildMutatorsPrettyString) +{ + M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Dynamic handicap"); +} + +/// \brief Hook that is called when player connects to the server. +MUTATOR_HOOKFUNCTION(dynamic_handicap, ClientConnect) +{ + entity player = M_ARGV(0, entity); + DynamicHandicap_UpdateHandicap(player); +} + +/// \brief Hook that is called when player dies. +MUTATOR_HOOKFUNCTION(dynamic_handicap, PlayerDies) +{ + entity attacker = M_ARGV(1, entity); + entity victim = M_ARGV(2, entity); + DynamicHandicap_UpdateHandicap(victim); + if (!IS_CLIENT(attacker)) + { + return; + } + DynamicHandicap_UpdateHandicap(attacker); +} diff --git a/qcsrc/server/_mod.inc b/qcsrc/server/_mod.inc index 99115fbdc..de7e01aa7 100644 --- a/qcsrc/server/_mod.inc +++ b/qcsrc/server/_mod.inc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/server/_mod.qh b/qcsrc/server/_mod.qh index 3a8898670..67f6aae4d 100644 --- a/qcsrc/server/_mod.qh +++ b/qcsrc/server/_mod.qh @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 52a376b0a..7acd7bb5e 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -14,6 +14,7 @@ #include "spawnpoints.qh" #include "resources.qh" #include "g_damage.qh" +#include "handicap.qh" #include "g_hook.qh" #include "command/common.qh" #include "cheats.qh" @@ -1283,6 +1284,8 @@ void ClientConnect(entity this) it.init_for_player(it, this); }); + Handicap_Initialize(this); + MUTATOR_CALLHOOK(ClientConnect, this); if (IS_REAL_CLIENT(this)) diff --git a/qcsrc/server/handicap.qc b/qcsrc/server/handicap.qc new file mode 100644 index 000000000..d0dfc4dac --- /dev/null +++ b/qcsrc/server/handicap.qc @@ -0,0 +1,41 @@ +#include "handicap.qh" + +/// \file +/// \brief Source file that contains implementation of the handicap system. +/// \author Lyberta +/// \copyright GNU GPLv2 or any later version. + +#include +#include "client.qh" + +.float m_handicap; ///< Holds the handicap value. + +void Handicap_Initialize(entity player) +{ + CS(player).m_handicap = 1; +} + +float Handicap_GetVoluntaryHandicap(entity player) +{ + return bound(1.0, CS(player).cvar_cl_handicap, 10.0); +} + +float Handicap_GetForcedHandicap(entity player) +{ + return CS(player).m_handicap; +} + +void Handicap_SetForcedHandicap(entity player, float value) +{ + if (value <= 0) + { + error("Handicap_SetForcedHandicap: Invalid handicap value."); + } + CS(player).m_handicap = value; +} + +float Handicap_GetTotalHandicap(entity player) +{ + return Handicap_GetForcedHandicap(player) * Handicap_GetVoluntaryHandicap( + player); +} diff --git a/qcsrc/server/handicap.qh b/qcsrc/server/handicap.qh new file mode 100644 index 000000000..fa45a0ed0 --- /dev/null +++ b/qcsrc/server/handicap.qh @@ -0,0 +1,40 @@ +#pragma once + +/// \file +/// \brief Header file that describes the handicap system. +/// \author Lyberta +/// \copyright GNU GPLv2 or any later version. + +// Handicap is used to make the game harder for strong players and easier for +// 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 +// handicap can be set by server mutators. The total handicap is the product of +// voluntary and forced handicap. + +/// \brief Initializes handicap to its default value. +/// \param[in,out] player Player to initialize. +/// \return No return. +void Handicap_Initialize(entity player); + +/// \brief Returns the voluntary handicap of the player. +/// \param[in] player Player to check. +/// \return Voluntary handicap of the player. +float Handicap_GetVoluntaryHandicap(entity player); + +/// \brief Returns the forced handicap of the player. +/// \param[in] player Player to check. +/// \return Forced handicap of the player. +float Handicap_GetForcedHandicap(entity player); + +/// \brief Sets the forced handicap of the player. +/// \param[in] player Player to alter. +/// \param[in] value Handicap value to set. +/// \return No return. +void Handicap_SetForcedHandicap(entity player, float value); + +/// \brief Returns the total handicap of the player. +/// \param[in] player Player to check. +/// \return Total handicap of the player. +float Handicap_GetTotalHandicap(entity player); diff --git a/qcsrc/server/player.qc b/qcsrc/server/player.qc index dd0615262..d9226f343 100644 --- a/qcsrc/server/player.qc +++ b/qcsrc/server/player.qc @@ -4,6 +4,7 @@ #include "bot/api.qh" #include "cheats.qh" #include "g_damage.qh" +#include "handicap.qh" #include "g_subs.qh" #include "miscfunctions.qh" #include "portals.qh" @@ -317,9 +318,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, if(!DEATH_ISSPECIAL(deathtype)) { - damage *= bound(1.0, CS(this).cvar_cl_handicap, 10.0); - if(this != attacker && IS_PLAYER(attacker)) - damage /= bound(1.0, CS(attacker).cvar_cl_handicap, 10.0); + damage *= Handicap_GetTotalHandicap(this); + if (this != attacker && IS_PLAYER(attacker)) + { + damage /= Handicap_GetTotalHandicap(attacker); + } } if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)