]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/mutators/mutator/dynamic_handicap/sv_dynamic_handicap.qc
Merge branch 'master' into DefaultUser/func_button_relay
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / dynamic_handicap / sv_dynamic_handicap.qc
1 #include "sv_dynamic_handicap.qh"
2 /// \file
3 /// \brief Source file that contains implementation of the Dynamic handicap
4 /// mutator.
5 /// \author Lyberta
6 /// \copyright GNU GPLv2 or any later version.
7
8 //======================= Global variables ====================================
9
10 int autocvar_g_dynamic_handicap; ///< Whether to enable dynamic handicap.
11 /// \brief The scale of the handicap. Larget values mean more penalties for
12 /// strong players and more buffs for weak players.
13 float autocvar_g_dynamic_handicap_scale;
14 /// \brief The exponent used to calculate handicap. 1 means linear scale. Values
15 /// more than 1 mean stronger non-linear handicap. Values less than 1 mean
16 /// weaker non-linear handicap.
17 float autocvar_g_dynamic_handicap_exponent;
18 float autocvar_g_dynamic_handicap_min; ///< The minimum value of the handicap.
19 float autocvar_g_dynamic_handicap_max; ///< The maximum value of the handicap.
20
21 //====================== Forward declarations =================================
22
23 /// \brief Clamps the value of the handicap.
24 /// \param[in] handicap Value to clamp.
25 /// \return Clamped value.
26 float DynamicHandicap_ClampHandicap(float handicap);
27
28 //========================= Free functions ====================================
29
30 /// \brief Updates the handicap of all players.
31 /// \return No return.
32 void DynamicHandicap_UpdateHandicap()
33 {
34         float total_score = 0;
35         float totalplayers = 0;
36         FOREACH_CLIENT(IS_PLAYER(it),
37         {
38                 total_score += PlayerScore_Get(it, SP_SCORE);
39                 ++totalplayers;
40         });
41         float mean_score = total_score / totalplayers;
42         FOREACH_CLIENT(true,
43         {
44                 float score = PlayerScore_Get(it, SP_SCORE);
45                 float handicap = fabs((score - mean_score) *
46                         autocvar_g_dynamic_handicap_scale);
47                 handicap = handicap ** autocvar_g_dynamic_handicap_exponent;
48                 if (score < mean_score)
49                 {
50                         handicap = -handicap;
51                 }
52                 if (handicap >= 0)
53                 {
54                         handicap += 1;
55                 }
56                 else
57                 {
58                         handicap = 1 / (fabs(handicap) + 1);
59                 }
60                 handicap = DynamicHandicap_ClampHandicap(handicap);
61                 Handicap_SetForcedHandicap(it, handicap);
62         });
63 }
64
65 float DynamicHandicap_ClampHandicap(float handicap)
66 {
67         if ((autocvar_g_dynamic_handicap_min >= 0) && (handicap <
68                 autocvar_g_dynamic_handicap_min))
69         {
70                 handicap = autocvar_g_dynamic_handicap_min;
71         }
72         if ((autocvar_g_dynamic_handicap_max > 0) && (handicap >
73                 autocvar_g_dynamic_handicap_max))
74         {
75                 handicap = autocvar_g_dynamic_handicap_max;
76         }
77         return handicap;
78 }
79
80 //============================= Hooks ========================================
81
82 REGISTER_MUTATOR(dynamic_handicap, autocvar_g_dynamic_handicap);
83
84 MUTATOR_HOOKFUNCTION(dynamic_handicap, BuildMutatorsString)
85 {
86         M_ARGV(0, string) = strcat(M_ARGV(0, string), ":handicap");
87 }
88
89 MUTATOR_HOOKFUNCTION(dynamic_handicap, BuildMutatorsPrettyString)
90 {
91         M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Dynamic handicap");
92 }
93
94 MUTATOR_HOOKFUNCTION(dynamic_handicap, ClientDisconnect)
95 {
96         DynamicHandicap_UpdateHandicap();
97 }
98
99 MUTATOR_HOOKFUNCTION(dynamic_handicap, PutClientInServer)
100 {
101         DynamicHandicap_UpdateHandicap();
102 }
103
104 MUTATOR_HOOKFUNCTION(dynamic_handicap, MakePlayerObserver)
105 {
106         DynamicHandicap_UpdateHandicap();
107 }
108
109 MUTATOR_HOOKFUNCTION(dynamic_handicap, AddedPlayerScore)
110 {
111         if (M_ARGV(0, entity) != SP_SCORE)
112         {
113                 return;
114         }
115         DynamicHandicap_UpdateHandicap();
116 }