


Syntax: Select all
# ../npc_points/npc_points.py
# Source.Python
from entities.entity import BaseEntity
from events import Event
from messages import HudMsg
from players.entity import Player
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2
}
@Event('entity_killed')
def npc_killed(event):
"""Called when an entity gets killed."""
try:
# Try to get a Player instance of the killer.
player = Player(event['entindex_attacker'])
except ValueError:
# Not a player, don't go further.
return
# Get the name of the NPC that got killed.
classname = BaseEntity(event['entindex_killed']).classname
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
word = 'points' if points > 1 else 'point'
HudMsg(
message=f'+{points} {word} for killing the {classname[4::]}',
x=-1,
y=0.58,
fade_in=0.2,
fade_out=0.3,
hold_time=1.25
).send(player.index)
Syntax: Select all
# ../npc_points/npc_points.py
# Source.Python
from entities.entity import BaseEntity
from events import Event
from messages import HudMsg
from players.entity import Player
from colors import GREEN, YELLOW
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2,
'npc_antilion': 3,
'npc_antilionguard': 2,
'npc_clawscanner': 2,
'npc_combinedropship': 3,
'npc_combinegunship': 2,
'npc_crow': 2,
'combine_mine': 3,
'npc_headcrab_black': 2,
'npc_headcrab_fast': 2,
'npc_helicopter': 3,
'npc_hunter': 2,
'npc_ichthyosaur': 2,
'npc_ministriper': 3,
'npc_missildefense': 2,
'npc_mortarsynth': 2,
'npc_pigeon': 3,
'npc_poisonzombie': 2,
'npc_rollermine': 2,
'npc_sniper': 3,
'npc_stalker': 2,
'npc_strider': 2,
'npc_turret_ceiling': 3,
'npc_turret_floor': 2,
'npc_turret_ground': 2,
'npc_vortigaunt': 3,
'npc_zombie:torso': 2,
'npc_zombine': 2
}
@Event('entity_killed')
def npc_killed(event):
"""Called when an entity gets killed."""
try:
# Try to get a Player instance of the killer.
player = Player(event['entindex_attacker'])
except ValueError:
# Not a player, don't go further.
return
# Get the name of the NPC that got killed.
classname = BaseEntity(event['entindex_killed']).classname
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
word = 'points' if points > 1 else 'point'
HudMsg(
message=f'+{points} {word} for killing the {classname[4::]}',
x=0.73,
y=0.85,
color1=GREEN,
color2=YELLOW,
effect=0,
fade_in=0.05,
fade_out=1.5,
hold_time=1.25,
fx_time=1.0,
channel=1
).send(player.index)
VinciT wrote:Hi daren, try this for getting points from NPCs:Syntax: Select all
# ../npc_points/npc_points.py
# Source.Python
from entities.entity import BaseEntity
from events import Event
from messages import HudMsg
from players.entity import Player
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2
}
@Event('entity_killed')
def npc_killed(event):
"""Called when an entity gets killed."""
try:
# Try to get a Player instance of the killer.
player = Player(event['entindex_attacker'])
except ValueError:
# Not a player, don't go further.
return
# Get the name of the NPC that got killed.
classname = BaseEntity(event['entindex_killed']).classname
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
word = 'points' if points > 1 else 'point'
HudMsg(
message=f'+{points} {word} for killing the {classname[4::]}',
x=-1,
y=0.58,
fade_in=0.2,
fade_out=0.3,
hold_time=1.25
).send(player.index)
Can you tell me a bit more about the scanner? What would you have it do?
VinciT wrote:I'll try to finish your requests tomorrow if I have time, but I can't promise anything.
Do you want these to NOT count as kills? Because right now I'm getting notifications whenever I kill an NPC with a prop.Painkiller wrote:physics does not yet count as kill
(that means physicgun kills, saw blades, barrels)
How about something like this?Painkiller wrote:- a line break of the current font
(+3 points for killing the zombie)
Example: How to proceed in the chat,
+3 points for killing the zombie
+3 points for killing the zombie
+3 points for killing the zombie
slowly fading downwards.
It seems more alive like in a pinball machine.
Because you kill several npc at the same time.
Syntax: Select all
# ../npc_points/npc_points.py
# Python
from collections import deque
from colorsys import hsv_to_rgb
from itertools import cycle
from time import time
# Source.Python
from colors import Color, GREEN, YELLOW
from entities.entity import BaseEntity, Entity
from events import Event
from listeners.tick import Delay, RepeatStatus
from messages import HudMsg
from players.entity import Player
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Maximum number of lines for notifications. (1 - 4)
NOTIFICATION_MAX = 3
# Offset for additional notifications. This determines how far apart they will
# be. (negative number - up, positive number - down)
NOTIFICATION_OFFSET = -0.04
NOTIFICATION_SETTINGS = {
# Horizontal position on the screen.
'x': -0.01,
# Vertical position on the screen.
'y': 0.85,
# Primary color of the message.
'color1': GREEN,
# Color of the swipe/scan effect.
'color2': YELLOW,
# Time it takes for the notification to fully show up. The swipe/scan
# effect uses this value for each letter that appears. Which is why I
# recommend keeping it set very low (0.02 - 0.04).
'fade_in': 0.035,
# Time it takes for the notification to start fading out.
'hold_time': 1.25,
# Time it takes for the notification to disappear.
'fade_out': 1.5,
# Time it takes for the color to change from 'color2' to 'color1'.
'fx_time': 0.35,
'channel': 1,
'effect': 2
}
# Cycle through the colors of the rainbow when creating notifications?
# (True/False)
RAINBOW_MODE = False
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2,
'npc_antilion': 3,
'npc_antilionguard': 2,
'npc_clawscanner': 2,
'npc_combinedropship': 3,
'npc_combinegunship': 2,
'npc_crow': 2,
'combine_mine': 3,
'npc_headcrab_black': 2,
'npc_headcrab_fast': 2,
'npc_helicopter': 3,
'npc_hunter': 2,
'npc_ichthyosaur': 2,
'npc_ministriper': 3,
'npc_missildefense': 2,
'npc_mortarsynth': 2,
'npc_pigeon': 3,
'npc_poisonzombie': 2,
'npc_rollermine': 2,
'npc_sniper': 3,
'npc_stalker': 2,
'npc_strider': 2,
'npc_turret_ceiling': 3,
'npc_turret_floor': 2,
'npc_turret_ground': 2,
'npc_vortigaunt': 3,
'npc_zombie_torso': 2,
'npc_zombine': 2
}
# Dictionary used to store properly formatted/prettified NPC names.
_npc_names = {}
# List used to store vibrant/pretty colors.
pretty_colors = []
# Message that will be sent to the player if they kill themselves.
suicide_msg = '-1 point for killing yourself'
def load():
"""Called when the plugin gets loaded."""
# Go through all the NPC classnames and format their names properly.
for npc_classname in points_per_npc:
_npc_names[npc_classname] = name_from_classname(npc_classname)
pretty_colors.extend(get_pretty_colors(10))
class Notification:
"""Class used to send a HudMsg.
Args:
message (str): Message to send.
**kwargs (dict): Additional keyword arguments.
Attributes:
color1 (Color): Color used to override the primary color of the HudMsg.
color2 (Color): Color used to override the effect color of the HudMsg.
life_time (float): How long should the message be valid for?
_sent_to (set of int): Set used to keep track of which channels the
notification has already been sent to.
"""
# Go through all the primary HudMsg settings/parameters.
for attribute, value in NOTIFICATION_SETTINGS.items():
# Set the parameter and it's value as an attribute of this class.
vars()[attribute] = value
# Calculate how often we should push notifications.
tick_rate = (hold_time + fade_out) * fade_in * 15
life_times = {1: tick_rate * 1.85}
settings = {1: NOTIFICATION_SETTINGS}
# Generate the settings for the other channels.
for channel in range(2, NOTIFICATION_MAX + 1):
# Is this the last channel we'll be using?
if channel == NOTIFICATION_MAX:
hold_time = fade_in * 16
fade_out = fade_in * 30
else:
hold_time = tick_rate
fade_out = tick_rate * 0.73 * (NOTIFICATION_MAX - channel)
settings[channel] = {
'x': x,
'y': y + NOTIFICATION_OFFSET * (channel - 1),
'color1': color1,
'fade_in': 0.01,
'hold_time': hold_time,
'fade_out': fade_out,
'channel': channel
}
# Get the life time of the message - time it takes for the message to
# fade out to about 50% of it's initial opacity.
life_times[channel] = hold_time + fade_out * 0.5
# Empty HudMsg used remove any active HudMsg in the primary channel.
wipe_hud_msg = HudMsg(message=' ', hold_time=0.01, channel=1)
def __init__(self, message, **kwargs):
"""Initializes the object."""
self.message = message
self.color1 = kwargs.get('color1', None)
self.color2 = kwargs.get('color2', None)
self.life_time = time() + Notification.life_times[1]
self._sent_to = set()
@property
def expired(self):
"""Checks if the Notification has run it's course (mostly faded)."""
return time() > self.life_time
def push(self, channel, index):
"""Creates and sends a HudMsg through the proper channel."""
# Have we already sent the notification through this channel?
if channel in self._sent_to:
return
# Has the message mostly faded out?
if self.expired:
return
try:
# Try to get the parameters for this channel.
settings = Notification.settings[channel]
except KeyError:
# Seems we're missing data, don't go further.
return
hud_msg = HudMsg(self.message, **settings)
# Should we override the primary color of the HudMsg?
if self.color1 is not None:
hud_msg.color1 = self.color1
# Should we override the effect color of the HudMsg?
if self.color2 is not None:
hud_msg.color2 = self.color2
# Is this the primary channel (the one with the swipe/scan effect)?
if channel == 1:
# Remove the previous HudMsg, if there is one.
Notification.wipe_hud_msg.send(index)
# Send the new HudMsg after a short delay.
Delay(0.15, hud_msg.send, (index,))
else:
hud_msg.send(index)
# Adjust the life time of the notification.
self.life_time = time() + Notification.life_times[channel]
self._sent_to.add(channel)
class PlayerNP(Player):
"""Extended Player class.
Args:
index (int): A valid player index.
caching (bool): Check for a cached instance?
Attributes:
queued_messages (deque): Queue for kill messages that should be turned
into Notification objects.
notifications (deque): Queue for storing Notification instances. This
queue is limited to `NOTIFICATION_MAX` number of items.
notify_think (Repeat): Instance of Repeat used for looping the
`_notify_think()` function.
color_cycle (cycle): Iterator used to get the next color from the
`pretty_colors` list. The cycle repeats once it reaches the last
color.
"""
def __init__(self, index, caching=True):
"""Initializes the object."""
super().__init__(index, caching)
self.queued_messages = deque()
self.notifications = deque(maxlen=NOTIFICATION_MAX)
self.notify_think = self.repeat(self._notify_think)
self.color_cycle = cycle(pretty_colors)
def notify(self, message):
"""Adds a message to the queue, which will then be turned into a
Notification and sent to the player.
Args:
message (str): Message to be sent.
"""
self.queued_messages.appendleft(message)
if self.notify_think.status is not RepeatStatus.RUNNING:
self.notify_think.start(
interval=Notification.tick_rate, execute_on_start=True)
def _notify_think(self):
try:
# Try to get the oldest kill message.
message = self.queued_messages.pop()
except IndexError:
# We've reached the end of the message queue, stop the loop.
self.notify_think.stop()
return
self.notifications.appendleft(
Notification(
message=message,
# Get the next pretty color if `RAINBOW_MODE` is set to True.
color1=next(self.color_cycle) if RAINBOW_MODE else None)
)
for channel, notification in enumerate(self.notifications, 1):
notification.push(channel, self.index)
@Event('entity_killed')
def entity_killed(event):
"""Called when an entity gets killed."""
index_a = event['entindex_attacker']
try:
# Try to get a Player instance of the killer.
player = PlayerNP(index_a)
except ValueError:
# The index doesn't belong to a player.
try:
# Let's see if the entity was killed by a physical object.
inthandle = Entity(event['entindex_inflictor']).get_property_int(
'm_hPhysicsAttacker')
player = PlayerNP.from_inthandle(inthandle)
except (ValueError, OverflowError):
# ValueError (inthandle): Missing property 'm_hPhysicsAttacker'.
# ValueError (player): This inthandle doesn't belong to a player.
# OverflowError: Invalid inthandle (-1).
return
index_k = event['entindex_killed']
# Get the classname of the entity that got killed.
classname = BaseEntity(index_k).classname
# Is the entity that got killed a player?
if 'player' in classname:
# Was this a suicide?
if index_k == index_a:
message = suicide_msg
else:
message = f'+1 point for killing {PlayerNP(index_k).name}'
# Or was it something else (an NPC)?
else:
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
try:
# Let's see if we have a pretty name for this NPC.
npc_name = _npc_names[classname]
except KeyError:
# Nope, convert it.
npc_name = name_from_classname(classname)
# And add it to the dictionary for later use.
_npc_names[classname] = npc_name
# Make sure to use the correct noun (singular/plural).
word = 'points' if points > 1 else 'point'
message = f'+{points} {word} for killing the {npc_name}'
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
player.notify(message)
def name_from_classname(classname):
"""Converts an NPC's classname into a pretty name."""
# First remove 'npc_' from the string. After that, replace underscores with
# spaces. And lastly, turn the string into a list of strings.
# 'npc_headcrab_fast' -> ['headcrab', 'fast']
name = classname.replace('npc_', '').replace('_', ' ').split()
# Don't reverse 'combine mine' and 'zombie torso'.
if 'combine' not in name and 'zombie' not in name:
# Reverse the order of the strings.
# ['headcrab', 'fast'] -> ['fast', 'headcrab']
name.reverse()
# Convert the list of strings into a string and return it.
# ['fast', 'headcrab'] -> 'fast headcrab'
return ' '.join(name)
def get_pretty_colors(amount):
"""Returns a list of vibrant colors.
Args:
amount (int): How many colors should be generated?
Returns:
list of Color: A list containing Color instances.
"""
colors = []
step = 1 / amount
for hue in range(0, amount):
colors.append(
Color(*(int(255 * x) for x in hsv_to_rgb(step * hue, 1, 1))))
return colors
Had some issues with scanners, can't get them to do what I want. I'll try some workarounds tomorrow and see if I can get them working properly.daren adler wrote::cool:No problem
![]()
VinciT wrote:Do you want these to NOT count as kills? Because right now I'm getting notifications whenever I kill an NPC with a prop.Painkiller wrote:physics does not yet count as kill
(that means physicgun kills, saw blades, barrels)How about something like this?Painkiller wrote:- a line break of the current font
(+3 points for killing the zombie)
Example: How to proceed in the chat,
+3 points for killing the zombie
+3 points for killing the zombie
+3 points for killing the zombie
slowly fading downwards.
It seems more alive like in a pinball machine.
Because you kill several npc at the same time.Syntax: Select all
# ../npc_points/npc_points.py
# Python
from collections import deque
from colorsys import hsv_to_rgb
from itertools import cycle
from time import time
# Source.Python
from colors import Color, GREEN, YELLOW
from entities.entity import BaseEntity
from events import Event
from listeners.tick import Delay, RepeatStatus
from messages import HudMsg
from players.entity import Player
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Maximum number of lines for notifications. (1 - 4)
NOTIFICATION_MAX = 3
# Offset for additional notifications. This determines how far apart they will
# be. (negative number - up, positive number - down)
NOTIFICATION_OFFSET = -0.04
NOTIFICATION_SETTINGS = {
# Horizontal position on the screen.
'x': -0.01,
# Vertical position on the screen.
'y': 0.85,
# Primary color of the message.
'color1': GREEN,
# Color of the swipe/scan effect.
'color2': YELLOW,
# Time it takes for the notification to fully show up. The swipe/scan
# effect uses this value for each letter that appears. Which is why I
# recommend keeping it set very low (0.02 - 0.04).
'fade_in': 0.035,
# Time it takes for the notification to start fading out.
'hold_time': 1.25,
# Time it takes for the notification to disappear.
'fade_out': 1.5,
# Time it takes for the color to change from 'color2' to 'color1'.
'fx_time': 0.35,
'channel': 1,
'effect': 2
}
# Cycle through the colors of the rainbow when creating notifications?
# (True/False)
RAINBOW_MODE = False
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2,
'npc_antilion': 3,
'npc_antilionguard': 2,
'npc_clawscanner': 2,
'npc_combinedropship': 3,
'npc_combinegunship': 2,
'npc_crow': 2,
'combine_mine': 3,
'npc_headcrab_black': 2,
'npc_headcrab_fast': 2,
'npc_helicopter': 3,
'npc_hunter': 2,
'npc_ichthyosaur': 2,
'npc_ministriper': 3,
'npc_missildefense': 2,
'npc_mortarsynth': 2,
'npc_pigeon': 3,
'npc_poisonzombie': 2,
'npc_rollermine': 2,
'npc_sniper': 3,
'npc_stalker': 2,
'npc_strider': 2,
'npc_turret_ceiling': 3,
'npc_turret_floor': 2,
'npc_turret_ground': 2,
'npc_vortigaunt': 3,
'npc_zombie_torso': 2,
'npc_zombine': 2
}
# Dictionary used to store properly formatted/prettified NPC names.
_npc_names = {}
# List used to store vibrant/pretty colors.
pretty_colors = []
def load():
"""Called when the plugin gets loaded."""
# Go through all the NPC classnames and format their names properly.
for npc_classname in points_per_npc:
_npc_names[npc_classname] = name_from_classname(npc_classname)
pretty_colors.extend(get_pretty_colors(10))
class Notification:
"""Class used to send a HudMsg.
Args:
message (str): Message to send.
**kwargs (dict): Additional keyword arguments.
Attributes:
color1 (Color): Color used to override the primary color of the HudMsg.
color2 (Color): Color used to override the effect color of the HudMsg.
life_time (float): How long should the message be valid for?
_sent_to (set of int): Set used to keep track of which channels the
notification has already been sent to.
"""
# Go through all the primary HudMsg settings/parameters.
for attribute, value in NOTIFICATION_SETTINGS.items():
# Set the parameter and it's value as an attribute of this class.
vars()[attribute] = value
# Calculate how often we should push notifications.
tick_rate = (hold_time + fade_out) * fade_in * 15
life_times = {1: tick_rate * 1.85}
settings = {1: NOTIFICATION_SETTINGS}
# Generate the settings for the other channels.
for channel in range(2, NOTIFICATION_MAX + 1):
# Is this the last channel we'll be using?
if channel == NOTIFICATION_MAX:
hold_time = fade_in * 16
fade_out = fade_in * 30
else:
hold_time = tick_rate
fade_out = tick_rate * 0.73 * (NOTIFICATION_MAX - channel)
settings[channel] = {
'x': x,
'y': y + NOTIFICATION_OFFSET * (channel - 1),
'color1': color1,
'fade_in': 0.01,
'hold_time': hold_time,
'fade_out': fade_out,
'channel': channel
}
# Get the life time of the message - time it takes for the message to
# fade out to about 50% of it's initial opacity.
life_times[channel] = hold_time + fade_out * 0.5
# Empty HudMsg used remove any active HudMsg in the primary channel.
wipe_hud_msg = HudMsg(message=' ', hold_time=0.01, channel=1)
def __init__(self, message, **kwargs):
"""Initializes the object."""
self.message = message
self.color1 = kwargs.get('color1', None)
self.color2 = kwargs.get('color2', None)
self.life_time = time() + Notification.life_times[1]
self._sent_to = set()
@property
def expired(self):
"""Checks if the Notification has run it's course (mostly faded)."""
return time() > self.life_time
def push(self, channel, index):
"""Creates and sends a HudMsg through the proper channel."""
# Have we already sent the notification through this channel?
if channel in self._sent_to:
return
# Has the message mostly faded out?
if self.expired:
return
try:
# Try to get the parameters for this channel.
settings = Notification.settings[channel]
except KeyError:
# Seems we're missing data, don't go further.
return
hud_msg = HudMsg(self.message, **settings)
# Should we override the primary color of the HudMsg?
if self.color1 is not None:
hud_msg.color1 = self.color1
# Should we override the effect color of the HudMsg?
if self.color2 is not None:
hud_msg.color2 = self.color2
# Is this the primary channel (the one with the swipe/scan effect)?
if channel == 1:
# Remove the previous HudMsg, if there is one.
Notification.wipe_hud_msg.send(index)
# Send the new HudMsg after a short delay.
Delay(0.15, hud_msg.send, (index,))
else:
hud_msg.send(index)
# Adjust the life time of the notification.
self.life_time = time() + Notification.life_times[channel]
self._sent_to.add(channel)
class PlayerNP(Player):
"""Extended Player class.
Args:
index (int): A valid player index.
caching (bool): Check for a cached instance?
Attributes:
queued_messages (deque): Queue for kill messages that should be turned
into Notification objects.
notifications (deque): Queue for storing Notification instances. This
queue is limited to `NOTIFICATION_MAX` number of items.
notify_think (Repeat): Instance of Repeat used for looping the
`_notify_think()` function.
color_cycle (cycle): Iterator used to get the next color from the
`pretty_colors` list. The cycle repeats once it reaches the last
color.
"""
def __init__(self, index, caching=True):
"""Initializes the object."""
super().__init__(index, caching)
self.queued_messages = deque()
self.notifications = deque(maxlen=NOTIFICATION_MAX)
self.notify_think = self.repeat(self._notify_think)
self.color_cycle = cycle(pretty_colors)
def notify(self, points, npc_classname):
"""Adds a message to the queue, which will then be turned into a
Notification and sent to the player.
Args:
points (int): How many points did the player get?
npc_classname (str): Which NPC did the player kill?
"""
try:
# Let's see if we have a pretty name for this NPC.
npc_name = _npc_names[npc_classname]
except KeyError:
# Nope, convert it.
npc_name = name_from_classname(npc_classname)
# And add it to the dictionary for later use.
_npc_names[npc_classname] = npc_name
# Make sure to use the correct noun (singular/plural).
word = 'points' if points > 1 else 'point'
self.queued_messages.appendleft(
f'+{points} {word} for killing the {npc_name}')
if self.notify_think.status is not RepeatStatus.RUNNING:
self.notify_think.start(
interval=Notification.tick_rate, execute_on_start=True)
def _notify_think(self):
try:
# Try to get the oldest kill message.
message = self.queued_messages.pop()
except IndexError:
# We've reached the end of the message queue, stop the loop.
self.notify_think.stop()
return
self.notifications.appendleft(
Notification(
message=message,
# Get the next pretty color if `RAINBOW_MODE` is set to True.
color1=next(self.color_cycle) if RAINBOW_MODE else None)
)
for channel, notification in enumerate(self.notifications, 1):
notification.push(channel, self.index)
@Event('entity_killed')
def npc_killed(event):
"""Called when an entity gets killed."""
try:
# Try to get a Player instance of the killer.
player = PlayerNP(event['entindex_attacker'])
except ValueError:
# Not a player, don't go further.
return
# Get the name of the NPC that got killed.
classname = BaseEntity(event['entindex_killed']).classname
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
player.notify(points=points, npc_classname=classname)
def name_from_classname(classname):
"""Converts an NPC's classname into a pretty name."""
# First remove 'npc_' from the string. After that, replace underscores with
# spaces. And lastly, turn the string into a list of strings.
# 'npc_headcrab_fast' -> ['headcrab', 'fast']
name = classname.replace('npc_', '').replace('_', ' ').split()
# Don't reverse 'combine mine' and 'zombie torso'.
if 'combine' not in name and 'zombie' not in name:
# Reverse the order of the strings.
# ['headcrab', 'fast'] -> ['fast', 'headcrab']
name.reverse()
# Convert the list of strings into a string and return it.
# ['fast', 'headcrab'] -> 'fast headcrab'
return ' '.join(name)
def get_pretty_colors(amount):
"""Returns a list of vibrant colors.
Args:
amount (int): How many colors should be generated?
Returns:
list of Color: A list containing Color instances.
"""
colors = []
step = 1 / amount
for hue in range(0, amount):
colors.append(
Color(*(int(255 * x) for x in hsv_to_rgb(step * hue, 1, 1))))
return colorsHad some issues with scanners, can't get them to do what I want. I'll try some workarounds tomorrow and see if I can get them working properly.daren adler wrote::cool:No problem
![]()
VinciT wrote:Do you want these to NOT count as kills? Because right now I'm getting notifications whenever I kill an NPC with a prop.Painkiller wrote:physics does not yet count as kill
(that means physicgun kills, saw blades, barrels)How about something like this?Painkiller wrote:- a line break of the current font
(+3 points for killing the zombie)
Example: How to proceed in the chat,
+3 points for killing the zombie
+3 points for killing the zombie
+3 points for killing the zombie
slowly fading downwards.
It seems more alive like in a pinball machine.
Because you kill several npc at the same time.Syntax: Select all
# ../npc_points/npc_points.py
# Python
from collections import deque
from colorsys import hsv_to_rgb
from itertools import cycle
from time import time
# Source.Python
from colors import Color, GREEN, YELLOW
from entities.entity import BaseEntity
from events import Event
from listeners.tick import Delay, RepeatStatus
from messages import HudMsg
from players.entity import Player
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Maximum number of lines for notifications. (1 - 4)
NOTIFICATION_MAX = 3
# Offset for additional notifications. This determines how far apart they will
# be. (negative number - up, positive number - down)
NOTIFICATION_OFFSET = -0.04
NOTIFICATION_SETTINGS = {
# Horizontal position on the screen.
'x': -0.01,
# Vertical position on the screen.
'y': 0.85,
# Primary color of the message.
'color1': GREEN,
# Color of the swipe/scan effect.
'color2': YELLOW,
# Time it takes for the notification to fully show up. The swipe/scan
# effect uses this value for each letter that appears. Which is why I
# recommend keeping it set very low (0.02 - 0.04).
'fade_in': 0.035,
# Time it takes for the notification to start fading out.
'hold_time': 1.25,
# Time it takes for the notification to disappear.
'fade_out': 1.5,
# Time it takes for the color to change from 'color2' to 'color1'.
'fx_time': 0.35,
'channel': 1,
'effect': 2
}
# Cycle through the colors of the rainbow when creating notifications?
# (True/False)
RAINBOW_MODE = False
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2,
'npc_antilion': 3,
'npc_antilionguard': 2,
'npc_clawscanner': 2,
'npc_combinedropship': 3,
'npc_combinegunship': 2,
'npc_crow': 2,
'combine_mine': 3,
'npc_headcrab_black': 2,
'npc_headcrab_fast': 2,
'npc_helicopter': 3,
'npc_hunter': 2,
'npc_ichthyosaur': 2,
'npc_ministriper': 3,
'npc_missildefense': 2,
'npc_mortarsynth': 2,
'npc_pigeon': 3,
'npc_poisonzombie': 2,
'npc_rollermine': 2,
'npc_sniper': 3,
'npc_stalker': 2,
'npc_strider': 2,
'npc_turret_ceiling': 3,
'npc_turret_floor': 2,
'npc_turret_ground': 2,
'npc_vortigaunt': 3,
'npc_zombie_torso': 2,
'npc_zombine': 2
}
# Dictionary used to store properly formatted/prettified NPC names.
_npc_names = {}
# List used to store vibrant/pretty colors.
pretty_colors = []
def load():
"""Called when the plugin gets loaded."""
# Go through all the NPC classnames and format their names properly.
for npc_classname in points_per_npc:
_npc_names[npc_classname] = name_from_classname(npc_classname)
pretty_colors.extend(get_pretty_colors(10))
class Notification:
"""Class used to send a HudMsg.
Args:
message (str): Message to send.
**kwargs (dict): Additional keyword arguments.
Attributes:
color1 (Color): Color used to override the primary color of the HudMsg.
color2 (Color): Color used to override the effect color of the HudMsg.
life_time (float): How long should the message be valid for?
_sent_to (set of int): Set used to keep track of which channels the
notification has already been sent to.
"""
# Go through all the primary HudMsg settings/parameters.
for attribute, value in NOTIFICATION_SETTINGS.items():
# Set the parameter and it's value as an attribute of this class.
vars()[attribute] = value
# Calculate how often we should push notifications.
tick_rate = (hold_time + fade_out) * fade_in * 15
life_times = {1: tick_rate * 1.85}
settings = {1: NOTIFICATION_SETTINGS}
# Generate the settings for the other channels.
for channel in range(2, NOTIFICATION_MAX + 1):
# Is this the last channel we'll be using?
if channel == NOTIFICATION_MAX:
hold_time = fade_in * 16
fade_out = fade_in * 30
else:
hold_time = tick_rate
fade_out = tick_rate * 0.73 * (NOTIFICATION_MAX - channel)
settings[channel] = {
'x': x,
'y': y + NOTIFICATION_OFFSET * (channel - 1),
'color1': color1,
'fade_in': 0.01,
'hold_time': hold_time,
'fade_out': fade_out,
'channel': channel
}
# Get the life time of the message - time it takes for the message to
# fade out to about 50% of it's initial opacity.
life_times[channel] = hold_time + fade_out * 0.5
# Empty HudMsg used remove any active HudMsg in the primary channel.
wipe_hud_msg = HudMsg(message=' ', hold_time=0.01, channel=1)
def __init__(self, message, **kwargs):
"""Initializes the object."""
self.message = message
self.color1 = kwargs.get('color1', None)
self.color2 = kwargs.get('color2', None)
self.life_time = time() + Notification.life_times[1]
self._sent_to = set()
@property
def expired(self):
"""Checks if the Notification has run it's course (mostly faded)."""
return time() > self.life_time
def push(self, channel, index):
"""Creates and sends a HudMsg through the proper channel."""
# Have we already sent the notification through this channel?
if channel in self._sent_to:
return
# Has the message mostly faded out?
if self.expired:
return
try:
# Try to get the parameters for this channel.
settings = Notification.settings[channel]
except KeyError:
# Seems we're missing data, don't go further.
return
hud_msg = HudMsg(self.message, **settings)
# Should we override the primary color of the HudMsg?
if self.color1 is not None:
hud_msg.color1 = self.color1
# Should we override the effect color of the HudMsg?
if self.color2 is not None:
hud_msg.color2 = self.color2
# Is this the primary channel (the one with the swipe/scan effect)?
if channel == 1:
# Remove the previous HudMsg, if there is one.
Notification.wipe_hud_msg.send(index)
# Send the new HudMsg after a short delay.
Delay(0.15, hud_msg.send, (index,))
else:
hud_msg.send(index)
# Adjust the life time of the notification.
self.life_time = time() + Notification.life_times[channel]
self._sent_to.add(channel)
class PlayerNP(Player):
"""Extended Player class.
Args:
index (int): A valid player index.
caching (bool): Check for a cached instance?
Attributes:
queued_messages (deque): Queue for kill messages that should be turned
into Notification objects.
notifications (deque): Queue for storing Notification instances. This
queue is limited to `NOTIFICATION_MAX` number of items.
notify_think (Repeat): Instance of Repeat used for looping the
`_notify_think()` function.
color_cycle (cycle): Iterator used to get the next color from the
`pretty_colors` list. The cycle repeats once it reaches the last
color.
"""
def __init__(self, index, caching=True):
"""Initializes the object."""
super().__init__(index, caching)
self.queued_messages = deque()
self.notifications = deque(maxlen=NOTIFICATION_MAX)
self.notify_think = self.repeat(self._notify_think)
self.color_cycle = cycle(pretty_colors)
def notify(self, points, npc_classname):
"""Adds a message to the queue, which will then be turned into a
Notification and sent to the player.
Args:
points (int): How many points did the player get?
npc_classname (str): Which NPC did the player kill?
"""
try:
# Let's see if we have a pretty name for this NPC.
npc_name = _npc_names[npc_classname]
except KeyError:
# Nope, convert it.
npc_name = name_from_classname(npc_classname)
# And add it to the dictionary for later use.
_npc_names[npc_classname] = npc_name
# Make sure to use the correct noun (singular/plural).
word = 'points' if points > 1 else 'point'
self.queued_messages.appendleft(
f'+{points} {word} for killing the {npc_name}')
if self.notify_think.status is not RepeatStatus.RUNNING:
self.notify_think.start(
interval=Notification.tick_rate, execute_on_start=True)
def _notify_think(self):
try:
# Try to get the oldest kill message.
message = self.queued_messages.pop()
except IndexError:
# We've reached the end of the message queue, stop the loop.
self.notify_think.stop()
return
self.notifications.appendleft(
Notification(
message=message,
# Get the next pretty color if `RAINBOW_MODE` is set to True.
color1=next(self.color_cycle) if RAINBOW_MODE else None)
)
for channel, notification in enumerate(self.notifications, 1):
notification.push(channel, self.index)
@Event('entity_killed')
def npc_killed(event):
"""Called when an entity gets killed."""
try:
# Try to get a Player instance of the killer.
player = PlayerNP(event['entindex_attacker'])
except ValueError:
# Not a player, don't go further.
return
# Get the name of the NPC that got killed.
classname = BaseEntity(event['entindex_killed']).classname
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
player.notify(points=points, npc_classname=classname)
def name_from_classname(classname):
"""Converts an NPC's classname into a pretty name."""
# First remove 'npc_' from the string. After that, replace underscores with
# spaces. And lastly, turn the string into a list of strings.
# 'npc_headcrab_fast' -> ['headcrab', 'fast']
name = classname.replace('npc_', '').replace('_', ' ').split()
# Don't reverse 'combine mine' and 'zombie torso'.
if 'combine' not in name and 'zombie' not in name:
# Reverse the order of the strings.
# ['headcrab', 'fast'] -> ['fast', 'headcrab']
name.reverse()
# Convert the list of strings into a string and return it.
# ['fast', 'headcrab'] -> 'fast headcrab'
return ' '.join(name)
def get_pretty_colors(amount):
"""Returns a list of vibrant colors.
Args:
amount (int): How many colors should be generated?
Returns:
list of Color: A list containing Color instances.
"""
colors = []
step = 1 / amount
for hue in range(0, amount):
colors.append(
Color(*(int(255 * x) for x in hsv_to_rgb(step * hue, 1, 1))))
return colorsHad some issues with scanners, can't get them to do what I want. I'll try some workarounds tomorrow and see if I can get them working properly.daren adler wrote::cool:No problem
![]()
daren adler wrote:VinciT wrote:Do you want these to NOT count as kills? Because right now I'm getting notifications whenever I kill an NPC with a prop.Painkiller wrote:physics does not yet count as kill
(that means physicgun kills, saw blades, barrels)How about something like this?Painkiller wrote:- a line break of the current font
(+3 points for killing the zombie)
Example: How to proceed in the chat,
+3 points for killing the zombie
+3 points for killing the zombie
+3 points for killing the zombie
slowly fading downwards.
It seems more alive like in a pinball machine.
Because you kill several npc at the same time.Syntax: Select all
# ../npc_points/npc_points.py
# Python
from collections import deque
from colorsys import hsv_to_rgb
from itertools import cycle
from time import time
# Source.Python
from colors import Color, GREEN, YELLOW
from entities.entity import BaseEntity
from events import Event
from listeners.tick import Delay, RepeatStatus
from messages import HudMsg
from players.entity import Player
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Maximum number of lines for notifications. (1 - 4)
NOTIFICATION_MAX = 3
# Offset for additional notifications. This determines how far apart they will
# be. (negative number - up, positive number - down)
NOTIFICATION_OFFSET = -0.04
NOTIFICATION_SETTINGS = {
# Horizontal position on the screen.
'x': -0.01,
# Vertical position on the screen.
'y': 0.85,
# Primary color of the message.
'color1': GREEN,
# Color of the swipe/scan effect.
'color2': YELLOW,
# Time it takes for the notification to fully show up. The swipe/scan
# effect uses this value for each letter that appears. Which is why I
# recommend keeping it set very low (0.02 - 0.04).
'fade_in': 0.035,
# Time it takes for the notification to start fading out.
'hold_time': 1.25,
# Time it takes for the notification to disappear.
'fade_out': 1.5,
# Time it takes for the color to change from 'color2' to 'color1'.
'fx_time': 0.35,
'channel': 1,
'effect': 2
}
# Cycle through the colors of the rainbow when creating notifications?
# (True/False)
RAINBOW_MODE = False
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2,
'npc_antilion': 3,
'npc_antilionguard': 2,
'npc_clawscanner': 2,
'npc_combinedropship': 3,
'npc_combinegunship': 2,
'npc_crow': 2,
'combine_mine': 3,
'npc_headcrab_black': 2,
'npc_headcrab_fast': 2,
'npc_helicopter': 3,
'npc_hunter': 2,
'npc_ichthyosaur': 2,
'npc_ministriper': 3,
'npc_missildefense': 2,
'npc_mortarsynth': 2,
'npc_pigeon': 3,
'npc_poisonzombie': 2,
'npc_rollermine': 2,
'npc_sniper': 3,
'npc_stalker': 2,
'npc_strider': 2,
'npc_turret_ceiling': 3,
'npc_turret_floor': 2,
'npc_turret_ground': 2,
'npc_vortigaunt': 3,
'npc_zombie_torso': 2,
'npc_zombine': 2
}
# Dictionary used to store properly formatted/prettified NPC names.
_npc_names = {}
# List used to store vibrant/pretty colors.
pretty_colors = []
def load():
"""Called when the plugin gets loaded."""
# Go through all the NPC classnames and format their names properly.
for npc_classname in points_per_npc:
_npc_names[npc_classname] = name_from_classname(npc_classname)
pretty_colors.extend(get_pretty_colors(10))
class Notification:
"""Class used to send a HudMsg.
Args:
message (str): Message to send.
**kwargs (dict): Additional keyword arguments.
Attributes:
color1 (Color): Color used to override the primary color of the HudMsg.
color2 (Color): Color used to override the effect color of the HudMsg.
life_time (float): How long should the message be valid for?
_sent_to (set of int): Set used to keep track of which channels the
notification has already been sent to.
"""
# Go through all the primary HudMsg settings/parameters.
for attribute, value in NOTIFICATION_SETTINGS.items():
# Set the parameter and it's value as an attribute of this class.
vars()[attribute] = value
# Calculate how often we should push notifications.
tick_rate = (hold_time + fade_out) * fade_in * 15
life_times = {1: tick_rate * 1.85}
settings = {1: NOTIFICATION_SETTINGS}
# Generate the settings for the other channels.
for channel in range(2, NOTIFICATION_MAX + 1):
# Is this the last channel we'll be using?
if channel == NOTIFICATION_MAX:
hold_time = fade_in * 16
fade_out = fade_in * 30
else:
hold_time = tick_rate
fade_out = tick_rate * 0.73 * (NOTIFICATION_MAX - channel)
settings[channel] = {
'x': x,
'y': y + NOTIFICATION_OFFSET * (channel - 1),
'color1': color1,
'fade_in': 0.01,
'hold_time': hold_time,
'fade_out': fade_out,
'channel': channel
}
# Get the life time of the message - time it takes for the message to
# fade out to about 50% of it's initial opacity.
life_times[channel] = hold_time + fade_out * 0.5
# Empty HudMsg used remove any active HudMsg in the primary channel.
wipe_hud_msg = HudMsg(message=' ', hold_time=0.01, channel=1)
def __init__(self, message, **kwargs):
"""Initializes the object."""
self.message = message
self.color1 = kwargs.get('color1', None)
self.color2 = kwargs.get('color2', None)
self.life_time = time() + Notification.life_times[1]
self._sent_to = set()
@property
def expired(self):
"""Checks if the Notification has run it's course (mostly faded)."""
return time() > self.life_time
def push(self, channel, index):
"""Creates and sends a HudMsg through the proper channel."""
# Have we already sent the notification through this channel?
if channel in self._sent_to:
return
# Has the message mostly faded out?
if self.expired:
return
try:
# Try to get the parameters for this channel.
settings = Notification.settings[channel]
except KeyError:
# Seems we're missing data, don't go further.
return
hud_msg = HudMsg(self.message, **settings)
# Should we override the primary color of the HudMsg?
if self.color1 is not None:
hud_msg.color1 = self.color1
# Should we override the effect color of the HudMsg?
if self.color2 is not None:
hud_msg.color2 = self.color2
# Is this the primary channel (the one with the swipe/scan effect)?
if channel == 1:
# Remove the previous HudMsg, if there is one.
Notification.wipe_hud_msg.send(index)
# Send the new HudMsg after a short delay.
Delay(0.15, hud_msg.send, (index,))
else:
hud_msg.send(index)
# Adjust the life time of the notification.
self.life_time = time() + Notification.life_times[channel]
self._sent_to.add(channel)
class PlayerNP(Player):
"""Extended Player class.
Args:
index (int): A valid player index.
caching (bool): Check for a cached instance?
Attributes:
queued_messages (deque): Queue for kill messages that should be turned
into Notification objects.
notifications (deque): Queue for storing Notification instances. This
queue is limited to `NOTIFICATION_MAX` number of items.
notify_think (Repeat): Instance of Repeat used for looping the
`_notify_think()` function.
color_cycle (cycle): Iterator used to get the next color from the
`pretty_colors` list. The cycle repeats once it reaches the last
color.
"""
def __init__(self, index, caching=True):
"""Initializes the object."""
super().__init__(index, caching)
self.queued_messages = deque()
self.notifications = deque(maxlen=NOTIFICATION_MAX)
self.notify_think = self.repeat(self._notify_think)
self.color_cycle = cycle(pretty_colors)
def notify(self, points, npc_classname):
"""Adds a message to the queue, which will then be turned into a
Notification and sent to the player.
Args:
points (int): How many points did the player get?
npc_classname (str): Which NPC did the player kill?
"""
try:
# Let's see if we have a pretty name for this NPC.
npc_name = _npc_names[npc_classname]
except KeyError:
# Nope, convert it.
npc_name = name_from_classname(npc_classname)
# And add it to the dictionary for later use.
_npc_names[npc_classname] = npc_name
# Make sure to use the correct noun (singular/plural).
word = 'points' if points > 1 else 'point'
self.queued_messages.appendleft(
f'+{points} {word} for killing the {npc_name}')
if self.notify_think.status is not RepeatStatus.RUNNING:
self.notify_think.start(
interval=Notification.tick_rate, execute_on_start=True)
def _notify_think(self):
try:
# Try to get the oldest kill message.
message = self.queued_messages.pop()
except IndexError:
# We've reached the end of the message queue, stop the loop.
self.notify_think.stop()
return
self.notifications.appendleft(
Notification(
message=message,
# Get the next pretty color if `RAINBOW_MODE` is set to True.
color1=next(self.color_cycle) if RAINBOW_MODE else None)
)
for channel, notification in enumerate(self.notifications, 1):
notification.push(channel, self.index)
@Event('entity_killed')
def npc_killed(event):
"""Called when an entity gets killed."""
try:
# Try to get a Player instance of the killer.
player = PlayerNP(event['entindex_attacker'])
except ValueError:
# Not a player, don't go further.
return
# Get the name of the NPC that got killed.
classname = BaseEntity(event['entindex_killed']).classname
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
player.notify(points=points, npc_classname=classname)
def name_from_classname(classname):
"""Converts an NPC's classname into a pretty name."""
# First remove 'npc_' from the string. After that, replace underscores with
# spaces. And lastly, turn the string into a list of strings.
# 'npc_headcrab_fast' -> ['headcrab', 'fast']
name = classname.replace('npc_', '').replace('_', ' ').split()
# Don't reverse 'combine mine' and 'zombie torso'.
if 'combine' not in name and 'zombie' not in name:
# Reverse the order of the strings.
# ['headcrab', 'fast'] -> ['fast', 'headcrab']
name.reverse()
# Convert the list of strings into a string and return it.
# ['fast', 'headcrab'] -> 'fast headcrab'
return ' '.join(name)
def get_pretty_colors(amount):
"""Returns a list of vibrant colors.
Args:
amount (int): How many colors should be generated?
Returns:
list of Color: A list containing Color instances.
"""
colors = []
step = 1 / amount
for hue in range(0, amount):
colors.append(
Color(*(int(255 * x) for x in hsv_to_rgb(step * hue, 1, 1))))
return colorsHad some issues with scanners, can't get them to do what I want. I'll try some workarounds tomorrow and see if I can get them working properly.daren adler wrote::cool:No problem
![]()
Ok, Im sure you will find somthing,,thank you again.
daren adler wrote:daren adler wrote:VinciT wrote:Do you want these to NOT count as kills? Because right now I'm getting notifications whenever I kill an NPC with a prop.
How about something like this?Syntax: Select all
# ../npc_points/npc_points.py
# Python
from collections import deque
from colorsys import hsv_to_rgb
from itertools import cycle
from time import time
# Source.Python
from colors import Color, GREEN, YELLOW
from entities.entity import BaseEntity
from events import Event
from listeners.tick import Delay, RepeatStatus
from messages import HudMsg
from players.entity import Player
# Send a message to the player when they kill an NPC? (True/False)
NOTIFY_PLAYER = True
# Maximum number of lines for notifications. (1 - 4)
NOTIFICATION_MAX = 3
# Offset for additional notifications. This determines how far apart they will
# be. (negative number - up, positive number - down)
NOTIFICATION_OFFSET = -0.04
NOTIFICATION_SETTINGS = {
# Horizontal position on the screen.
'x': -0.01,
# Vertical position on the screen.
'y': 0.85,
# Primary color of the message.
'color1': GREEN,
# Color of the swipe/scan effect.
'color2': YELLOW,
# Time it takes for the notification to fully show up. The swipe/scan
# effect uses this value for each letter that appears. Which is why I
# recommend keeping it set very low (0.02 - 0.04).
'fade_in': 0.035,
# Time it takes for the notification to start fading out.
'hold_time': 1.25,
# Time it takes for the notification to disappear.
'fade_out': 1.5,
# Time it takes for the color to change from 'color2' to 'color1'.
'fx_time': 0.35,
'channel': 1,
'effect': 2
}
# Cycle through the colors of the rainbow when creating notifications?
# (True/False)
RAINBOW_MODE = False
# Dictionary for how many points each NPC is worth.
points_per_npc = {
'npc_zombie': 3,
'npc_manhack': 2,
'npc_headcrab': 2,
'npc_antilion': 3,
'npc_antilionguard': 2,
'npc_clawscanner': 2,
'npc_combinedropship': 3,
'npc_combinegunship': 2,
'npc_crow': 2,
'combine_mine': 3,
'npc_headcrab_black': 2,
'npc_headcrab_fast': 2,
'npc_helicopter': 3,
'npc_hunter': 2,
'npc_ichthyosaur': 2,
'npc_ministriper': 3,
'npc_missildefense': 2,
'npc_mortarsynth': 2,
'npc_pigeon': 3,
'npc_poisonzombie': 2,
'npc_rollermine': 2,
'npc_sniper': 3,
'npc_stalker': 2,
'npc_strider': 2,
'npc_turret_ceiling': 3,
'npc_turret_floor': 2,
'npc_turret_ground': 2,
'npc_vortigaunt': 3,
'npc_zombie_torso': 2,
'npc_zombine': 2
}
# Dictionary used to store properly formatted/prettified NPC names.
_npc_names = {}
# List used to store vibrant/pretty colors.
pretty_colors = []
def load():
"""Called when the plugin gets loaded."""
# Go through all the NPC classnames and format their names properly.
for npc_classname in points_per_npc:
_npc_names[npc_classname] = name_from_classname(npc_classname)
pretty_colors.extend(get_pretty_colors(10))
class Notification:
"""Class used to send a HudMsg.
Args:
message (str): Message to send.
**kwargs (dict): Additional keyword arguments.
Attributes:
color1 (Color): Color used to override the primary color of the HudMsg.
color2 (Color): Color used to override the effect color of the HudMsg.
life_time (float): How long should the message be valid for?
_sent_to (set of int): Set used to keep track of which channels the
notification has already been sent to.
"""
# Go through all the primary HudMsg settings/parameters.
for attribute, value in NOTIFICATION_SETTINGS.items():
# Set the parameter and it's value as an attribute of this class.
vars()[attribute] = value
# Calculate how often we should push notifications.
tick_rate = (hold_time + fade_out) * fade_in * 15
life_times = {1: tick_rate * 1.85}
settings = {1: NOTIFICATION_SETTINGS}
# Generate the settings for the other channels.
for channel in range(2, NOTIFICATION_MAX + 1):
# Is this the last channel we'll be using?
if channel == NOTIFICATION_MAX:
hold_time = fade_in * 16
fade_out = fade_in * 30
else:
hold_time = tick_rate
fade_out = tick_rate * 0.73 * (NOTIFICATION_MAX - channel)
settings[channel] = {
'x': x,
'y': y + NOTIFICATION_OFFSET * (channel - 1),
'color1': color1,
'fade_in': 0.01,
'hold_time': hold_time,
'fade_out': fade_out,
'channel': channel
}
# Get the life time of the message - time it takes for the message to
# fade out to about 50% of it's initial opacity.
life_times[channel] = hold_time + fade_out * 0.5
# Empty HudMsg used remove any active HudMsg in the primary channel.
wipe_hud_msg = HudMsg(message=' ', hold_time=0.01, channel=1)
def __init__(self, message, **kwargs):
"""Initializes the object."""
self.message = message
self.color1 = kwargs.get('color1', None)
self.color2 = kwargs.get('color2', None)
self.life_time = time() + Notification.life_times[1]
self._sent_to = set()
@property
def expired(self):
"""Checks if the Notification has run it's course (mostly faded)."""
return time() > self.life_time
def push(self, channel, index):
"""Creates and sends a HudMsg through the proper channel."""
# Have we already sent the notification through this channel?
if channel in self._sent_to:
return
# Has the message mostly faded out?
if self.expired:
return
try:
# Try to get the parameters for this channel.
settings = Notification.settings[channel]
except KeyError:
# Seems we're missing data, don't go further.
return
hud_msg = HudMsg(self.message, **settings)
# Should we override the primary color of the HudMsg?
if self.color1 is not None:
hud_msg.color1 = self.color1
# Should we override the effect color of the HudMsg?
if self.color2 is not None:
hud_msg.color2 = self.color2
# Is this the primary channel (the one with the swipe/scan effect)?
if channel == 1:
# Remove the previous HudMsg, if there is one.
Notification.wipe_hud_msg.send(index)
# Send the new HudMsg after a short delay.
Delay(0.15, hud_msg.send, (index,))
else:
hud_msg.send(index)
# Adjust the life time of the notification.
self.life_time = time() + Notification.life_times[channel]
self._sent_to.add(channel)
class PlayerNP(Player):
"""Extended Player class.
Args:
index (int): A valid player index.
caching (bool): Check for a cached instance?
Attributes:
queued_messages (deque): Queue for kill messages that should be turned
into Notification objects.
notifications (deque): Queue for storing Notification instances. This
queue is limited to `NOTIFICATION_MAX` number of items.
notify_think (Repeat): Instance of Repeat used for looping the
`_notify_think()` function.
color_cycle (cycle): Iterator used to get the next color from the
`pretty_colors` list. The cycle repeats once it reaches the last
color.
"""
def __init__(self, index, caching=True):
"""Initializes the object."""
super().__init__(index, caching)
self.queued_messages = deque()
self.notifications = deque(maxlen=NOTIFICATION_MAX)
self.notify_think = self.repeat(self._notify_think)
self.color_cycle = cycle(pretty_colors)
def notify(self, points, npc_classname):
"""Adds a message to the queue, which will then be turned into a
Notification and sent to the player.
Args:
points (int): How many points did the player get?
npc_classname (str): Which NPC did the player kill?
"""
try:
# Let's see if we have a pretty name for this NPC.
npc_name = _npc_names[npc_classname]
except KeyError:
# Nope, convert it.
npc_name = name_from_classname(npc_classname)
# And add it to the dictionary for later use.
_npc_names[npc_classname] = npc_name
# Make sure to use the correct noun (singular/plural).
word = 'points' if points > 1 else 'point'
self.queued_messages.appendleft(
f'+{points} {word} for killing the {npc_name}')
if self.notify_think.status is not RepeatStatus.RUNNING:
self.notify_think.start(
interval=Notification.tick_rate, execute_on_start=True)
def _notify_think(self):
try:
# Try to get the oldest kill message.
message = self.queued_messages.pop()
except IndexError:
# We've reached the end of the message queue, stop the loop.
self.notify_think.stop()
return
self.notifications.appendleft(
Notification(
message=message,
# Get the next pretty color if `RAINBOW_MODE` is set to True.
color1=next(self.color_cycle) if RAINBOW_MODE else None)
)
for channel, notification in enumerate(self.notifications, 1):
notification.push(channel, self.index)
@Event('entity_killed')
def npc_killed(event):
"""Called when an entity gets killed."""
try:
# Try to get a Player instance of the killer.
player = PlayerNP(event['entindex_attacker'])
except ValueError:
# Not a player, don't go further.
return
# Get the name of the NPC that got killed.
classname = BaseEntity(event['entindex_killed']).classname
try:
# Are there predefined points for this NPC?
points = points_per_npc[classname]
except KeyError:
# Nope, default to 1.
points = 1
# Increase the player's kill/score count.
player.kills += points
# Should we tell the player how many points they just received?
if NOTIFY_PLAYER:
player.notify(points=points, npc_classname=classname)
def name_from_classname(classname):
"""Converts an NPC's classname into a pretty name."""
# First remove 'npc_' from the string. After that, replace underscores with
# spaces. And lastly, turn the string into a list of strings.
# 'npc_headcrab_fast' -> ['headcrab', 'fast']
name = classname.replace('npc_', '').replace('_', ' ').split()
# Don't reverse 'combine mine' and 'zombie torso'.
if 'combine' not in name and 'zombie' not in name:
# Reverse the order of the strings.
# ['headcrab', 'fast'] -> ['fast', 'headcrab']
name.reverse()
# Convert the list of strings into a string and return it.
# ['fast', 'headcrab'] -> 'fast headcrab'
return ' '.join(name)
def get_pretty_colors(amount):
"""Returns a list of vibrant colors.
Args:
amount (int): How many colors should be generated?
Returns:
list of Color: A list containing Color instances.
"""
colors = []
step = 1 / amount
for hue in range(0, amount):
colors.append(
Color(*(int(255 * x) for x in hsv_to_rgb(step * hue, 1, 1))))
return colors
Had some issues with scanners, can't get them to do what I want. I'll try some workarounds tomorrow and see if I can get them working properly.
Ok, Im sure you will find somthing,,thank you again.
UPdate-- I just tryed the new one you put up and all works good to me,,i even throwed a rock/berrel at them and gave points,,thank you.
Painkiller wrote:Daren you little spammer. ^^ :D
daren adler wrote:Painkiller wrote:Daren you little spammer. ^^ :D
OK, i see what you are saying, i did not mean for all of the HL2:DM Npc points/score posts, so sorry, You can delete all of this guys. again sorry for all the posts. You can delete the others also if its to much. I will try and stay off of here,,sorry for the trouble guys.
Users browsing this forum: No registered users and 67 guests