Page 1 of 1

simple death and kill streaks tracker

Posted: Mon Jun 15, 2015 5:25 am
by nergal
This is untested but it should work for any game supported on sauce.py :3

Syntax: Select all

# Python Imports
from collections import defaultdict

# SourcePython imports
from players.entity import PlayerEntity

from players.helpers import userid_from_index
from players.helpers import index_from_userid

from events import Event

from cvars.public import PublicConVar
from plugins.info import PluginInfo

info = PluginInfo()
info.name = "Death and Kill Streaks"
info.author = "Nergal/Assyrian"
info.version = "1.0"
info.basename = "dkstreaks"
info.variable = info.basename + "_version"
info.convar = PublicConVar(info.variable, info.version, 0, info.name + " Version")

#create a list
deathstreaks = defaultdict(int) #[i+1 for i in range(66)]
killstreaks = defaultdict(int) #[i+1 for i in range(66)]


def set_playerlist(index):
deathstreaks[index] = 0
killstreaks[index] = 0

@Event
def player_connect(game_event):
set_playerlist( index_from_userid(game_event.get_int('userid')) )

@Event
def player_disconnect(game_event):
set_playerlist( index_from_userid(game_event.get_int('userid')) )

@Event
def player_death(game_event):
victim = index_from_userid( game_event.get_int('userid') )
attacker = index_from_userid( game_event.get_int('attacker') )

if victim == attacker || attacker == -1:
return

if killstreaks[victim] == 0:
deathstreaks[victim] += 1

killstreaks[victim] = 0
deathstreaks[attacker] = 0
killstreaks[attacker] += 1

Posted: Mon Jun 15, 2015 8:17 pm
by L'In20Cible
You should take a look at python dictionary! :)

Posted: Wed Jun 17, 2015 7:50 pm
by nergal
L'In20Cible wrote:You should take a look at python dictionary! :)


Why a dictionary and not a list/array?

Posted: Wed Jun 17, 2015 7:59 pm
by L'In20Cible
CauseCause accessing dictionaries is fasterfaster since this is done internally. It also makes the code cleaner and easier to read imo.

Posted: Wed Jun 17, 2015 8:00 pm
by L'In20Cible
Sorry for repeated words, I broke the screen on my phine and for some reasons it does duplicate some words.. lol

Posted: Wed Jun 17, 2015 8:02 pm
by L'In20Cible
Also, your code wont load due to ; after return which is an invalid syntax.

Posted: Wed Jun 17, 2015 8:42 pm
by Ayuto
L'In20Cible wrote:Also, your code wont load due to ; after return which is an invalid syntax.
No, a semicolon is valid in Python. It allows you to use multiple statements within the same row.[PYTHON]>>> def f(x):
print(x); x += 5; return x;


>>> f(5)
5
10[/PYTHON]Though, you usually don't use that in Python.

Posted: Wed Jun 17, 2015 8:52 pm
by L'In20Cible
I know, but I guess python compiler is looking for something after the semi-colon and being nothing most likely fails. I honnestly never used multiple statements on the same line, so I could not say without testing.

Posted: Wed Jun 17, 2015 8:55 pm
by Ayuto
This is also working fine.^^

Syntax: Select all

>>> def f(x):
print(x)
return;

>>> f(5)
5

Posted: Thu Jun 18, 2015 10:31 am
by BackRaw
nergal wrote:
L'In20Cible wrote:You should take a look at python dictionary! :)


Why a dictionary and not a list/array?
I'll give you a quick example with dicts:

Syntax: Select all

# create a dict
deathstreaks = {}

@Event
def player_connect(game_event):
set_playerlist( index_from_userid(game_event.get_int('userid')) )


# map the player's index to 0
def set_playerlist(index):
deathstreaks[index] = 0


@Event
def player_disconnect(game_event):

# remove the player from the dict and therefore from memory
del deathstreaks[index_from_userid(game_event.get_int('userid'))]
The difference is, that you create an empty dict, instead of a list pre-defined with the values 0...65 -- why range(0, 66) anyway?

I'd suggest you to look into this: https://docs.python.org/3/library/stdtypes.html#typesmapping

Posted: Thu Jun 18, 2015 8:52 pm
by stonedegg
You also might want to set the deathstreaks regardless of whether victim id equals attacker id or not, otherwise suicides wouldn't count as deaths.

Posted: Fri Jun 19, 2015 4:41 am
by nergal
stonedegg wrote:You also might want to set the deathstreaks regardless of whether victim id equals attacker id or not, otherwise suicides wouldn't count as deaths.


in the cases of suicide, the killer is the player I believe.

reason why range of 0-65 is because the Source Engine supports 64 players + a SourceTV or Replay Bot.

Another reason is that I'm used to making Player Arrays in SourceMod by just doing "myplayerarray[65];"

Do not forget that I'm transitioning from SourceMod to Python so my skills aren't going to be 100% with Python :>

Posted: Fri Jun 19, 2015 12:16 pm
by stonedegg
Yes, if the player suicides attacker id equals victim id, which means in your script suicides won't count as deaths (in case of self explosive damage or falldamage).
You also might want to check if the attacker userid != -1, otherwise this will give you a conversion error: attacker = index_from_userid( game_event.get_int('attacker') )
Not sure if that is possible in TF2 but in CS, the attacker userid is -1 if the player gets killed by the bomb and you can't get an index from that.

Posted: Fri Jun 19, 2015 1:35 pm
by satoon101
nergal wrote:
stonedegg wrote:You also might want to set the deathstreaks regardless of whether victim id equals attacker id or not, otherwise suicides wouldn't count as deaths.


in the cases of suicide, the killer is the player I believe.

reason why range of 0-65 is because the Source Engine supports 64 players + a SourceTV or Replay Bot.

Another reason is that I'm used to making Player Arrays in SourceMod by just doing "myplayerarray[65];"

Do not forget that I'm transitioning from SourceMod to Python so my skills aren't going to be 100% with Python :>


Well, we understand that you are transitioning. This is why we are suggesting more Pythonic ways to do things. Using a list as if it were an array is not the way to handle those sorts of things in Python. Dictionaries are a much better, more Pythonic way. I do see in your example that you imported defaultdict and commented it out. I imagine this is from another thread on the forum where the defaultdict was utilized. If you don't understand it, just google "Python defaultdict" to get the Python docs for that functionality. If you are still confused, feel free to ask questions.

Posted: Fri Jun 19, 2015 11:14 pm
by BackRaw
nergal wrote:reason why range of 0-65 is because the Source Engine supports 64 players + a SourceTV or Replay Bot.

Another reason is that I'm used to making Player Arrays in SourceMod by just doing "myplayerarray[65];"

Do not forget that I'm transitioning from SourceMod to Python so my skills aren't going to be 100% with Python :>
Aaaahhh okay, it makes more sense now. I wasn't being offensive or anything like that :) All good, this forum and this plugin is here for us all to learn :D

Posted: Mon Jun 29, 2015 6:15 am
by nergal
satoon101 wrote:
nergal wrote:
stonedegg wrote:You also might want to set the deathstreaks regardless of whether victim id equals attacker id or not, otherwise suicides wouldn't count as deaths.


in the cases of suicide, the killer is the player I believe.

reason why range of 0-65 is because the Source Engine supports 64 players + a SourceTV or Replay Bot.

Another reason is that I'm used to making Player Arrays in SourceMod by just doing "myplayerarray[65];"

Do not forget that I'm transitioning from SourceMod to Python so my skills aren't going to be 100% with Python :>


Well, we understand that you are transitioning. This is why we are suggesting more Pythonic ways to do things. Using a list as if it were an array is not the way to handle those sorts of things in Python. Dictionaries are a much better, more Pythonic way. I do see in your example that you imported defaultdict and commented it out. I imagine this is from another thread on the forum where the defaultdict was utilized. If you don't understand it, just google "Python defaultdict" to get the Python docs for that functionality. If you are still confused, feel free to ask questions.


yes ur right, I've updated the OP using defaultdict, hopefully it'll still work ok.

Has anybody tested this out? I'm not sure if it's working or not.

Posted: Mon Jun 29, 2015 1:07 pm
by satoon101
Well, the way you are currently using it, you might as well just use dict instead of defaultdict. The purpose of defaultdict is to automatically set the value of a key the first time it is used. I would recommend either changing it to dict or, if you want to utilize defaultdict correctly, remove your set_playerlist function and player_connect event and modify your player_disconnect event to remove the key when a player disconnects:

Syntax: Select all

@Event
def player_disconnect(game_event):
index = index_from_userid(game_event.get_int('userid'))
if index in deathstreaks:
del deathstreaks[index]
if index in killstreaks:
del killstreaks[index]


There is no purpose to have an index in the dictionary if there is no player with that index on the server. You might also want to clear the dictionaries on LevelShutdown, since, if I remember correctly, bots do not cause player_disconnect when leaving on map change:

Syntax: Select all

from listeners import LevelShutdown


@LevelShutdown
def level_shutdown():
deathstreaks.clear()
killstreaks.clear()


Also, this line would give a syntax error:

Syntax: Select all

if victim == attacker || attacker == -1:


That should be:

Syntax: Select all

if victim == attacker or attacker == -1: