However this also requires ar_IncrementLevel to be adjusted to return true if a level can indeed be taken off, and false otherwise, so it's more than a 1 line fix.
So if you want to implement that fix I just posted be sure to do that too. I only included the relevant code block so I didn't have to bog down the post with another huge function that could be explained away in one sentence. I'm taking things step-by-step, so stuff like:
self.pltracker[player][TR_LEVELKILLS] = max(0 * 2 - 1, 0)
is to show specific values for inputs in the event that only one specific set of inputs can ever result in that code block being executed, which is the case here.
On that note, it seems like you've made a quintessential misunderstanding of this function. ar_SetKills is to set the ABSOLUTE kill counter of the target player. Calling it with a value of 0, for instance, puts them at 0 kills regardless of what value they were at before. ar_IncrementKills is to increment/decrement the kill counter by the given amount, calling it with 0 will do nothing because it's just adding that value to the kill counter. Calling ar_SetKills with a negative value does not mean the player suicided, it means we want to take off a kill when there are no more kills to take. It's in the same vein as some subtraction algorithms, where you decrement the next most significant digit when you're subtracting more than the current one has.
On suicide, ar_IncrementKills is called with a value of -1:
# Advance the given player's level kills by the given amount.
def ar_IncrementKills( self, player, -1 ):
self.ar_SetKills( player, self.pltracker[player][TR_LEVELKILLS] - 1 )
This, as you can see, calls ar_SetKills with a value of "self.pltracker[player][TR_LEVELKILLS] - 1". So let's replace all instances of the variable "kills" in that function with "self.pltracker[player][TR_LEVELKILLS] - 1". This is to show what ar_incrementKills is actually doing when called with a value of -1, which it will be in the case of a suicide.
def ar_SetKills( self, player, self.pltracker[player][TR_LEVELKILLS] - 1 ):
if not player:
return
if ( self.pltracker[player][TR_LEVELKILLS] - 1 >= self.KillsPerLevel ):
self.ar_IncrementLevel( player, 1 )
self.pltracker[player][TR_LEVELKILLS] = 0
elif (self.pltracker[player][TR_LEVELKILLS] - 1 < 0):
self.ar_IncrementLevel( player, -1 )
self.pltracker[player][TR_LEVELKILLS] = max(self.pltracker[player][TR_LEVELKILLS] + self.pltracker[player][TR_LEVELKILLS] - 1, 0) # Kills is negative here so we're using it to correct previous level killcount.
else:
self.pltracker[player][TR_LEVELKILLS] = self.pltracker[player][TR_LEVELKILLS] - 1 # No level advancement, just complete the request as asked.
msg = _( "#GES_GP_GUNGAME_KILLS", str(self.KillsPerLevel - self.pltracker[player][TR_LEVELKILLS] - 1) ) # We didn't increment a level which would have caused a level advancement message.
GEUtil.HudMessage( player, msg, -1, 0.71, GEUtil.Color( 220, 220, 220, 255 ), 1.5, 2 ) # So give a killcount message instead.
Note that there are 3 cases to consider here:
self.pltracker[player][TR_LEVELKILLS] - 1 >= self.KillsPerLevel
self.pltracker[player][TR_LEVELKILLS] - 1 < 0
aka
self.pltracker[player][TR_LEVELKILLS] - 1 >= 0 && self.pltracker[player][TR_LEVELKILLS] - 1 < self.KillsPerLevel
With the important consideration that self.pltracker[player][TR_LEVELKILLS] is always >= 0 and < self.KillsPerLevel.
This case, then, can be eliminated right away since you can't subtract from something less that self.KillsPerLevel and end up greater than it. (unless you subtract so much you overflow the integer, which is obviously not the case here.)
self.pltracker[player][TR_LEVELKILLS] - 1 >= self.KillsPerLevel
so our remaining two cases revolve around:
self.pltracker[player][TR_LEVELKILLS] - 1 < 0
if self.pltracker[player][TR_LEVELKILLS] is >= 1, then this will not execute since any non-zero integers will result in a value of 0 or greater. Thus the codeblock in question ONLY executes when a player kills themselves AND has 0 kills on the current level. This results in the only values ever being passed to the code after this conditional statement being self.pltracker[player][TR_LEVELKILLS] = 0, and kills = -1.
Then my previous explanation applies. Just plug in the values:
self.pltracker[player][TR_LEVELKILLS] = max(self.pltracker[player][TR_LEVELKILLS] + kills, 0)
self.pltracker[player][TR_LEVELKILLS] = max(0 - 1, 0)
self.pltracker[player][TR_LEVELKILLS] = 0
I've actually tested your code just to be sure, and it behaves exactly as I described. If you die with 0 kills, you lose a level and are downgraded to 0 kills on that level. Not sure why you think that you can't lose a level since self.ar_IncrementLevel( player, -1 ) gets called regardless of what self.pltracker[player][TR_LEVELKILLS] is set to. The only instance in which you don't lose a level is when you can't, which is level 1. Obviously this is the one instance where the original code fails to behave as expected where yours captures the intended behavior, but given that the goal is not accomplished by either setup the third solution is required.
To restate the goal, let's use an example. This server is running 3 a kills per level setup. Each kill is represented with a number and each level is represented by set of numbers separated by a |. The first 3 levels are thus:
012|345|678|....
If we have 4 kills and suicide, we downgrade to 3 kills but stay on the same level. Thus we just need 1 kill to regain our previous standing which is more or less the standard across all gamemodes.
If we have 3 kills and suicide, however, we should still go down just one kill, to kill 2. The only difference is that we also go down to the previous level in the process. The standard is maintained by the fact that just one kill will put you back where you were. With your fix, suicide after kill 3 will drop you to kill 0, which is not the intended behavior.
Anyway, there's pretty much nothing else to explain here, so if you still disagree with me and can't implement it yourself, I'll provide my entire set of modifications so you can verify that they behave as desired. I figure that you at least deserved the full explanation as to why your changes won't be included, but anything more than this goes outside my ability to explain. I guess I could be wrong, in which case no amount of explanation would be sufficient to explain this properly, but given that I've tested both versions of the code and did a pseudo mathematical proof as to why they behave as they do I can't think of a way that's possible.