Xonotic Forums

Full Version: Dynamic handicap
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Whatever.
But this will not used by new players? Is this mod client or server side?
Handicaps have been built into Xonotic for a while. It's definitely in the 0.8.2 client and I think well before that.

The basic handicap code (current Xon default code) is entirely server side. The way it works is that the value is updated on the client, then passed from the client to the server, as this is the only way for the player to currently get the value to the server for that player.

The mutator change Lyberta has produced is server side, and it auto-scales the server side values for the handicap dynamically. Client side isn't involved.

Lyberta: Does this mod stop clients pushing the handicap cvar from the client to the server? Otherwise I can see people pushing their own values over the top of the dynamic handicap to get handicap bonuses (even if they're short lived due to regular updates of the handicap on the server side).
Lyberta: No probs and thanks for the clarification. Only thing I'm wondering about is if people could use the client handicap to screw with the server side balance somehow, which would not be useful.
At what point does this kick in? I ask primarily because Vanilla can have rapidly fluctuating player performance, even at the beginning of the match. For instance a player used to insta or sniping in other games may grab a vortex and get a solid 5+ frags. He may then die and never get another chance to grab vortex.

It'd important to remember as well, that due to these sorts of circumstances, gaps of 5, 10 or even 20 frags between players of similar skill levels are actually perfectly normal, depending on the map and performance of each player. If we look at another extremely fast AFPS- CPM, one can find duels between players at the top of their game that can vary by thirty or even forty frags on popular maps like Aerowalk. While this is in duel, and between players who know how to exploit mistakes, they also dont have access to curving rockets, fast grenades, monstrously strong projectile shotguns and the strength powerup.

What should be avoided, above all else are scenarios where a new player feels as though they're being punished, and scenarios where people dont understand why their hits dont seem to really "count". In a game where we already have a high base armour reduction % we're already gonna have a hell of a time with the latter

edits due to my phone being a shit
(09-04-2017, 09:40 AM)Lyberta Wrote: [ -> ]Again, based on the discussion on the forums I've made another option to help new players. This mutator changes the damage of players based on their kill/death ratio. The handicap value of 1 means the damage in unchanged. The values higher than 1 mean players will deal less damage and get damaged more. The values lower than 1 mean players will deal more damage and get damaged less.
Hi.

I don't think this handicapping is constructive at all.
#1 This mutator changes the damage of players based on their kill/death ratio. Consider this scenario, an FFA DM match with 5 players (common mode for new players to be in).
Place       Name         Kills       Deaths     Suicides     Frags
1st           Player #1   30         27             1                29
....
5th           Player#5    7          1                0                7
...

In this scenario, Player#5 is the disadvantaged player from a natural score POV. With dynamic handicapping, he is also the most handicapped player because high k:d does not necessarily mean winning or dominating the match e.g the case of a large map wherein it is easy for a stray player to miss the party, which this is also common new player behavior to wander around the map. Where as FFA regulars of varying skills generally are trained to aggressively pursue frags.

Obviously the solution would be for him to die enough to remove the handicap, but that obstructs his goal to win explicitly e.g relinquish any items he's collected but also feed frags to other contestants who may have a lower k:d than him, but still have a higher score.

#2 New player may want frags, but they also want to learn the game and improve (which in previous posts, is something you have explicitly stated you are not interested in doing in your 3 years experience of playing the game). This obfuscates the latter where you punish positive behavior or improvement, and reward poor play, stagnation, or decay.

Add:

I almost forgot. Does this mean the flag carrier in CTF, can spam his kill bind, for massive damage reductions and carry flags all day (-> massive point rewards for capping the flag -> more elo points).
If that's the case, then increasing incoming damage based on k:d is agreed to be counter-intuitive.

If you set minimum for 1 regarding the CTF scenario, does it still mean a player dedicated to flag carries still gets a damage bonus (i.e better able to defend himself)?
(09-18-2017, 01:09 PM)Lyberta Wrote: [ -> ]
(09-17-2017, 03:01 PM)Antares* Wrote: [ -> ]If you set minimum for 1 regarding the CTF scenario, does it still mean a player dedicated to flag carries still gets a damage bonus (i.e better able to defend himself)?

A player who doesn't kill players and only goes to flag? That way they get vanilla damage.

That will give them an advantage over people who get handicapped because they've done well at their role (defense, disruption), which means that you either have to rotate people awkwardly through roles (hard in pubs and less dedicated pugs, hard for new players, annoying for people who just want to have fun) or your frag-focused players will get worse at their job as they become more successful, but can still be crippled by a few shots from a flag carrier (who will generally not try to get frags). This will probably lead to something cheesy like defenders/attackers suiciding like CTS diehards to keep their damage up
(09-18-2017, 01:09 PM)Lyberta Wrote: [ -> ]
(09-17-2017, 03:01 PM)Antares* Wrote: [ -> ]If you set minimum for 1 regarding the CTF scenario, does it still mean a player dedicated to flag carries still gets a damage bonus (i.e better able to defend himself)?

A player who doesn't kill players and only goes to flag? That way they get vanilla damage.

lol you tried to dodge the only important detail is that they (get themselves) killed intentionally.

A player who gets themselves killed would get a negative or low k:d on purpose would:
  • incur a incoming damage reduction so they're killed less
  • receive an outgoing damage boost so they can receive more kills
    You have described that in CTF you can set the minimum 1, so this is not abused by flag carriers so they not receive incoming damage reduction. However with the handicap in place, they would also receive a damage boost. Flag carriers or really any role in CTF do not really care about k:d and they can exploit this handicapping system to give themselves an advantage.Above all those conscious of the system will not be new players. So not only are potential newbies outmatched naturally, their opponents are also giving themselves unfair advantages over them.
Feedback isn't complaining.  These are good points.  Kill/death ratio alone might work for ffa and duel but other information could be used to prevent a team from turning dynamic handicap into an adavantage and defeating the point of a handicap.  Handicapping by your score relative to other players might work without requiring game mode-specific code.

The other possible issue I can see is that the scaling of the dynamic handicap could be too heavy and make the game too easy for the down player or could be too little and not do enough to help that player.  You may have already found a good balance but I didn't see any mention of this in the thread.  If not, continued play testing should get you to reasonable handicap increments.
(09-19-2017, 12:54 PM)Lyberta Wrote: [ -> ]It's up to the server admin, why aren't you complaining that other mutators that may break the game? "Oh, killing flag carrier with running guns mutator is so hard".

It's also the responsibility of the developer who placed an shortsighted, abuseable or counter-intuitive system in the game to begin with. Why should I be talking about other mutators in this thread?
(09-20-2017, 05:58 PM)Lyberta Wrote: [ -> ]Hmm, how would you scale the handicap using score? That would probably require checking the connection time and then calculating score/sec.
Polling scores every second sounds excessive.  Hooking into score changes would be nice if QuakeC allows it.  On kill or death also makes sense.  Regardless of how or when the handicap is set, the problem of confusing new/unaware players remains.

Factoring the time since joining the match sounds less useful if you're updating the handicap throughout the match.  Whether they catch up or die a few times, the handicap system will even things out as the match continues.

(09-20-2017, 05:58 PM)Lyberta Wrote: [ -> ]That's exactly what g_dynamic_handicap scale is for.
The point was that a sane default scale/recommended default scale would be valuable to server hosts looking to use your mutator.  I'm sure hosts would be willing to offer specific suggestions as time goes on.

(09-20-2017, 05:58 PM)Lyberta Wrote: [ -> ]
(09-20-2017, 05:15 AM)Antares* Wrote: [ -> ]It's also the responsibility of the developer who placed an shortsighted, abuseable or counter-intuitive system in the game to begin with.

Pretty much every variable in the game can have tremendous effect. That responsibility is now of the server admins.
You don't want to take ownership of your code?  I'm sincerely confused by this response.
(09-21-2017, 07:13 PM)Lyberta Wrote: [ -> ]I don't want to intentionally limit creativity of server owners. I give them tools, it's up to them to decide the balance and rules. Every variable can break the game, say you set blaster damage to 500, now blaster is instagib, but should we hardcode the range of values? I think not.


If you mean to say the server adminstrator as a creative position, then you're a little mistaken. Mainly server administration changes cvars and place what ones to execute in what contexts (vote calls and menus). That's roughly it in terms of the limits of working with the server console, it's not like you can write new game modes in it or make maps with it. And obviously those tasks aren't called server administration.

And for example, any player starting their local match can change numbers and later collect the changes to a cvar and give them to a server administrator who then is able to show them to server regulars. Obviously the session would be marked as modified to distinguish from the game itself. A dynamic handicap cvar for a system built into a git version of the game- isn't so clear as to whether or not the server is flagged as modified i.e balance changes, or Official e.g g_warmup changes does not tag servers as modified.

I don't say what I do as if I'm interested in enabling this on a server- I will never enable this setting on my server or any others I have influence over. I say because it conflicts at a fundamental concept with what new players generally want despite the intentions of being for new players, and will generally give a bad impression of Xonotic. I.e it doesn't matter if its up to the server admins, if new players perceive that unfairness is part of the game ("why does my sniper only deal 80 damage and yours does more?"), there's a good chance they'll see it as a bad game and not waste any more time with it.
(09-23-2017, 12:06 AM)Lyberta Wrote: [ -> ]I'm pretty sure you have to explicitly mark it is pure to be allowed officially.
You don't. To be marked as Official, certain cvars can't be touched. Some cvars are allowed to be changed.
(09-23-2017, 12:06 AM)Lyberta Wrote: [ -> ]For new player sniper will deal more damage if they play badly. This system is designed to help new players, not to punish them
You seem to be confused. A new player doesn't necessarily play badly e.g they play other FPS games and there's some carry over in skill or there's other new players on the server and one in particular is doing well.
This system may have the intentions of helping new players, but it rewards poor play, intentionally dying (if k:d) or stalling the game (if you're doing points per playtime e.g this is also easily done in CTF and frustrates both teams), and penalizes new players if they were to improve over their peers.
Damage is now observable since the damage text feature has been added.
(09-23-2017, 12:34 AM)Lyberta Wrote: [ -> ]A new player doesn't know the weapons, doesn't know where are their spawns. Most new players will be walking with shotguns and getting other weapons by pure chance. It's not likely that they will dominate the score.
Or they've played FPS games before and have some pre-existing aiming skill that benefits them over others without necessarily being conscious of Xonotic specific weapon strategies. And they find the weapons via hitting the weapon key of the weapon they don't already have.


(09-23-2017, 12:34 AM)Lyberta Wrote: [ -> ]Those behaviors require a lot of thought on the part of the player and will need the majority of players to break the game. Something that is extremely unlikely.
Players aren't exactly idiots and (ab)using systems for an advantage is generally part of gaming.


(09-23-2017, 12:34 AM)Lyberta Wrote: [ -> ]Yes, but if you can remember the numbers, you are already very skilled or experienced.
No, there's more to the game than memorizing numbers, and recognizing a 2 or 3 digit number is something nearly anyone can do.
(09-23-2017, 01:52 AM)Lyberta Wrote: [ -> ]
(09-23-2017, 12:52 AM)Antares* Wrote: [ -> ]And they find the weapons via hitting the weapon key of the weapon they don't already have.

How the hell are they supposed to know that? I was playing for 4 years without knowing it.
By hitting the key when they don't have the weapon, either accidentally or just trying out the weapon binds. lol
Played only one year, but found the feature within a few matches.
(09-22-2017, 09:57 PM)Lyberta Wrote: [ -> ]I have implemented that formula and added exponent for more fine tuning. Unfortunately, score difference varies wildly between gamemodes so g_dynamic_handicap_scale should be set per mode. 0.2 seems fine for DM, 0.05 seems fine for CTF. Dunno about other gamemodes.

Looks good.  Should mitigate the described abuses in the main modes (CTF seems like a tricky mode to dynamically handicap).  Nice looking ahead with the different scale for modes with drastically different point gain.  Won't require a code change every time a game mode is added.
Thanks again.
Code:
g_dynamic_handicap_scale 0.2 "The scale of the handicap. Larger values mean more penalties for strong players and more buffs for weak players."
I might have misunderstood buffs -- I thought buffs are for anyone to get so how can they show up only for some?
Also, what's a set of good settings for servers? (And does the server setting take priority over voluntary client setting, or do the two settings aggregate?)
Thanks!
Lyberta, have you tried doing player_score / mean_score instead of player_score - mean_score to avoid having different factors and exponents for different modes?
BFG, in this case buff means bonus or advantage, unfortunately certain game items are also called buffs, might be better to change the description.
(09-24-2017, 11:35 PM)martin-t Wrote: [ -> ]Lyberta, have you tried doing player_score / mean_score instead of player_score - mean_score to avoid having different factors and exponents for different modes?
BFG, in this case buff means bonus or advantage, unfortunately certain game items are also called buffs, might be better to change the description.

I would calculate the handicap directly and eliminate the absolute value and the exponent but would keep the scale because modes like CTF have much larger differences in score than most modes.  

According to Halogene,  in another thread, only handicap values greater than 1 are applied, so any value less than that is the same as 0.  From speaking with other players, it seems that small handicap values make a big difference so exponents are likely overkill.  Something as simple as the following preserves the sign and can be applied directly because players leading in score have a value less than one set to cl_handicap.  It also doesn't grow out of control because it's not exponential.  I'd liked to have eliminate the if-else but this function needs to not apply a handicap when the difference is 0.
Code:
difference = mean - score;
if (difference != 0)
    linear_handicap  = difference * g_dynamic_handicap_scale  + 1;
else
    linear_handicap = 0;

The scale would be different than it was for the original function, but values could be chosen that restrict handicap between 1 and 2 in most cases, and just a little beyond in extreme cases.
(09-25-2017, 08:06 PM)Lyberta Wrote: [ -> ]
(09-24-2017, 11:35 PM)martin-t Wrote: [ -> ]Lyberta, have you tried doing player_score / mean_score instead of player_score - mean_score to avoid having different factors and exponents for different modes?

Maybe (player_score - mean_score) / mean_score. Remember that score can be negative. But this would mean that when mean becomes larger, handicap deviation will be very little. Say, a DM game with 100 frag limit. In that mode 10 frag difference can mean a lot.

(09-25-2017, 08:21 AM)mini Wrote: [ -> ]According to Halogene,  in another thread, only handicap values greater than 1 are applied, so any value less than that is the same as 0.

Forced handicap can be less than 1 and cl_handicap is multiplied by forced handicap when calculating damage.

(09-25-2017, 08:21 AM)mini Wrote: [ -> ]From speaking with other players, it seems that small handicap values make a big difference so exponents are likely overkill.

Exponent can be less than 1 in which case deviation will grow less than linearly.
My point was that this approach is needlessly complex.  Taking the absolute value and exponentiation are costly and give you nothing a simpler function wouldn't.

Switch mean and player score and you have a function that gets you directly to a useful, but very strong cl_handicap value.  Scaling this down may be the way to go because it avoids complex computations.
Code:
if (score != 0)
    cl_handicap = 1 + ((mean - score) / score)  * scale
 
What makes this all work is the hint Halogene gave us. cl_handicap of anything less than one is zero.  cl_handicap of anything greater than one is itself.  Here's some sample values if scale is set to 1.


f (m, p) = 1 + (m - p) / p,  if p != 0
             = 0, if p = 0

CTF player leading 
f (70, 150) = 7/15  (effectively 0)

CTF player is well behind
f (70, 30) =  7/3

DM player is very far ahead
f (1, 20) = 1/20  (effectively 0)

DM player is very far behind
f (20, 1) = 20

DM player is a little ahead
f (5, 10) = 1/2  (effectively 0)

DM player is a little behind
f (10, 5) = 3/2

Close game, ahead by one
f (2, 3) = 2/3  (effectively 0)

Close game, behind by one
f (3, 2) = 3/2

Haven't scored any points yet (don't div/0)
f (4, 0) = 0
(09-26-2017, 03:06 AM)Lyberta Wrote: [ -> ]
(09-26-2017, 12:19 AM)mini Wrote: [ -> ]What makes this all work is the hint Halogene gave us. cl_handicap of anything less than one is zero.  cl_handicap of anything greater than one is itself.  Here's some sample values if scale is set to 1.

I don't mess with cl_handicap at all. cl_handicap is up to the client.

cl_handicap of anything less than 1 is 1.

Ok, so cl_handicap itself defaults to one because it is applied to damage and damage taken.  My previous suggestions can be simplified even further with that domain.  If you had already bound the range between 1.0 and 10.0, then why use such a costly function?
(09-26-2017, 08:25 PM)Lyberta Wrote: [ -> ]Because I don't use cl_handicap. I use another, forced handicap value that can be anything greater than zero (i.e. linear value can be (-inf;+inf) ).

My first idea was to use normal distribution but exponent is faster and more flexible.
You still seem to misunderstand my points so I'll be blunt.  cl_handicap is completely irrelevant to the choice of mathematical function.  The given domain, desired range, and how the function dictates the design of your code is what matters.  If you had taken the time to choose a decent function, you wouldn't have had to store the sign, take the absolute value in two places, or restore the sign.  It's the difference between

Code:
Code:
difference = score - mean;
linear_handicap = | difference * g_dynamic_handicap_scale| ^ g_dynamic_handicap_exponent

if (difference < 0 && linear_handicap > 0)
{
    linear_handicap *= -1;
}

if (linear_handicap >= 0)
{
   handicap = linear_handicap + 1;
}
else
{
   handicap = 1 / (|linear_handicap| + 1);
}

and
Code:
if (score != 0)
    handicap = 1 + ((mean - score) / score)
or
Code:
handicap  = difference * g_dynamic_handicap_scale  + 1;

You could also figure out an exponential function that calculates the desired handicap directly for the same design improvement but with your desired growth rate.  That is, if you really need to give admins the option of having handicaps that are wildly explosive or too weak to make a difference.
(09-28-2017, 11:29 AM)Lyberta Wrote: [ -> ]
(09-27-2017, 09:15 PM)mini Wrote: [ -> ]
Code:
if (score != 0)
    handicap = 1 + ((mean - score) / score)

What if score is 0? What if score is between -1 and 1?

(09-27-2017, 09:15 PM)mini Wrote: [ -> ]
Code:
handicap  = difference * g_dynamic_handicap_scale  + 1;

What if difference is negative and multiplied by g_dynamic_handicap_scale gives less than or equal to -1?
This is how I know you weren't reading my previous posts.  Please read them rather than replying without.

The first one is probably best because it can't be misused.  Thanks @martin-t.  Inputs are all integers but are float types so epsilon comparison or bound would work where appropriate.  Since this assignment happens in an event loop, set it to 1 in the case where score is 0 (did you really need me to spell that out for you?).
Code:
if (score != 0)
   handicap = 1 + ((mean - score) / score)
else
    handicap = 1;

For the second one,
mini Wrote: [ -> ]The scale would be different than it was for the original function, but values could be chosen that restrict handicap between 1 and 2 in most cases, and just a little beyond in extreme cases.

and restrict the values scale can assume or use bound() so that admins can't shoot themselves in the foot.  

Once again, all of this is beside the main point, which is better mathematical functions can simplify your code, be kind to admins, and be kind to future maintainers.