# ../effects/base.py
"""Provides base effect classes."""
# =============================================================================
# >> IMPORTS
# =============================================================================
# Source.Python Imports
# Colors
from colors import Color
# Effects
from effects.templates import temp_entity_templates
# Engines
from engines.precache import Decal
from engines.precache import Model
# Entities
from entities.classes import _supported_property_types
from entities.entity import Entity
from entities.props import SendPropType
# Filters
from filters.recipients import RecipientFilter
# Memory
from memory import get_object_pointer
from memory import get_size
from memory import make_object
from memory import Pointer
from memory.helpers import Array
from memory.helpers import Type
from memory.manager import manager
# Players
from players.entity import Player
# String Tables
from stringtables import string_tables
# Site-Packages Imports
# ConfigObj
from configobj import Section
# =============================================================================
# >> FORWARD IMPORTS
# =============================================================================
# Source.Python Imports
# Effects
from _effects._base import BaseTempEntity
# =============================================================================
# >> ALL DECLARATION
# =============================================================================
__all__ = ('BaseTempEntity',
'TempEntity',
)
# ============================================================================
# >> CLASSES
# ============================================================================
[docs]class TempEntity(BaseTempEntity):
"""Class used to interact with a specific temp entity."""
[docs] def __init__(self, temp_entity, **aliases):
"""Initialize the temp entity instance.
:param str/Pointer temp_entity:
The name of the temp entity to initialize or the pointer to wrap.
:param aliases:
Any alias to set on initialization.
"""
# Is the given name a Pointer instance?
if isinstance(temp_entity, Pointer):
# Wrap the given pointer...
super()._wrap_ptr(temp_entity)
# Otherwise...
else:
# Get the template of the temp entity...
template = temp_entity_templates[temp_entity]
# Initialize the temp entity...
super()._copy_base(template, template.size)
# Loop through all given aliases...
for alias, value in aliases.items():
# Set the alias to the given value...
setattr(self, alias, value)
@classmethod
def _obj(cls, ptr):
"""Wrap the given pointer.
:param Pointer ptr:
The pointer to wrap.
"""
return cls(ptr)
@property
def _size(self):
"""Return the size of the temp entity.
:rtype: int
"""
return self.template.size
def __getattr__(self, name):
"""Return the value of the given alias.
:param str name:
The alias name.
:rtype: object
"""
# Get the name of the prop...
prop_name = self.template.aliases.get(name, None)
# Was the given name a valid alias?
if prop_name is not None:
# Is the name a section?
if isinstance(prop_name, Section):
# Is the alias a decal?
if prop_name['type'] == Decal.__name__:
# Return the decal instance...
return Decal(string_tables[Decal.precache_table][
getattr(self, prop_name['name'])])
# Otherwise, is the alias an entity?
elif prop_name['type'] == Entity.__name__:
# Return the entity instance...
return Entity(getattr(self, prop_name['name']))
# Otherwise, is the alias a player?
elif prop_name['type'] == Player.__name__:
# Return the player instance...
return Player(getattr(self, prop_name['name']))
# Otherwise, is the alias a model?
elif prop_name['type'] == Model.__name__:
# Get the name of the model...
model_name = string_tables[Model.precache_table][
getattr(self, prop_name['name'])]
# Was the model not precached?
if not model_name:
# Return an error model...
return Model('models/error.mdl')
# Return the model instance...
return Model(model_name)
# Otherwise, is the alias a color?
elif prop_name['type'] == Color.__name__:
# Get a tuple to store the RGBA values...
values = tuple()
# Loop through all aliases...
for alias in prop_name['name']:
# Add the current value to the tuple...
values += (getattr(self, alias),)
# Return the color instance...
return Color(*values)
# Otherwise...
else:
# Get the data of the property...
prop, offset, type_name = self.template.properties[
prop_name['name']]
# Return the value of the property...
return make_object(
manager.get_class(prop_name['type']),
get_object_pointer(self) + offset)
# Get the data of the property...
prop, offset, type_name = self.template.properties[prop_name]
# Return the value of the property...
return self._get_property(prop_name, prop.type)
# Return the value of the given attribute...
return super().__getattribute__(name)
def __setattr__(self, name, value):
"""Set the value of the given alias.
:param str name:
The alias name.
:param object value:
The value to set.
"""
# Get the name of the prop...
prop_name = self.template.aliases.get(name, None)
# Was the given name a valid alias?
if prop_name is not None:
# Is the name a section?
if isinstance(prop_name, Section):
# Is the alias a decal?
if prop_name['type'] == Decal.__name__:
# Is the given value an invalid decal instance?
if not isinstance(value, Decal):
# Raise an exception...
raise ValueError(
'"{}" is not a valid Decal instance.'.format(
value))
# Set the model index...
setattr(self, prop_name['name'], value.index)
# Is the alias an entity?
elif prop_name['type'] == Entity.__name__:
# Is the given value an invalid entity instance?
if not isinstance(value, Entity):
# Raise an exception...
raise ValueError(
'"{}" is not a valid Entity instance.'.format(
value))
# Set the alias value...
setattr(self, prop_name['name'], value.index)
# Otherwise, is the alias a player?
elif prop_name['type'] == Player.__name__:
# Set the player instance...
setattr(self, prop_name['name'], value.index)
# Otherwise, is the alias a model?
elif prop_name['type'] == Model.__name__:
# Is the given value an invalid model instance?
if not isinstance(value, Model):
# Raise an exception...
raise ValueError(
'"{}" is not a valid Model instance.'.format(
value))
# Set the model index...
setattr(self, prop_name['name'], value.index)
# Otherwise, is the alias a color?
elif prop_name['type'] == Color.__name__:
# Is the given value an invalid color instance?
if not isinstance(value, Color):
# Raise an exception...
raise ValueError(
'"{}" is not a valid Color instance.'.format(
value))
# Loop through all aliases...
for index, alias in enumerate(prop_name['name']):
# Set the current alias...
setattr(self, alias, value[index])
# Otherwise...
else:
# Get the data of the property...
prop, offset, type_name = self.template.properties[
prop_name['name']]
# Get the class of the type...
cls = manager.get_class(prop_name['type'])
# Is the given value not valid?
if not isinstance(value, cls):
# Raise an exception...
raise TypeError(
'The given value is not of type "{}".'.format(
type_name))
# Set the value of the property...
get_object_pointer(value).copy(
get_object_pointer(self) + offset,
self.template._get_type_size(prop_name['type']))
# No need to go further...
return
# Get the data of the property...
prop, offset, type_name = self.template.properties[prop_name]
# Set the value of the property...
self._set_property(prop_name, prop.type, value)
# No need to go further...
return
# Set the value of the given attribute...
super().__setattr__(name, value)
def __dir__(self):
"""Return an alphabetized list of attributes for the instance."""
# Get the base attributes
attributes = set(super().__dir__())
# Add all aliases to the attributes
attributes.update(set(self.template.aliases))
# Return a sorted list of attributes
return sorted(attributes)
def _get_property(self, prop_name, prop_type):
"""Return the value of the given property name.
:param str prop_name:
The name of the property.
:param SendPropType prop_type:
The type of the property.
"""
# Is the given property not valid?
if prop_name not in self.template.properties:
# Raise an exception...
raise NameError(
'"{}" is not a valid property for temp entity "{}".'.format(
prop_name, self.name))
# Get the property data...
prop, offset, type_name = self.template.properties[prop_name]
# Are the prop types matching?
if prop.type != prop_type:
# Raise an exception...
raise TypeError('"{}" is not of type "{}".'.format(
prop_name, prop_type))
# Is the property an array?
if prop_type == SendPropType.ARRAY:
# Return an array instance...
return Array(manager, False, type_name, get_object_pointer(
self) + offset, prop.length)
# Is the given type not supported?
if prop_type not in _supported_property_types:
# Raise an exception...
raise TypeError('"{}" is not supported.'.format(prop_type))
# Is the type native?
if Type.is_native(type_name):
# Return the value...
return getattr(
get_object_pointer(self), 'get_' + type_name)(offset)
# Otherwise
else:
# Make the object and return it...
return make_object(
manager.get_class(type_name),
get_object_pointer(self) + offset)
# Raise an exception...
raise ValueError('Unable to get the value of "{}".'.format(prop_name))
[docs] def get_property_array(self, prop_name):
"""Return the value of the given property as an Array instance.
:param str prop_name:
The name of the property.
:rtype: Array
"""
return self._get_property(prop_name, SendPropType.ARRAY)
[docs] def get_property_bool(self, prop_name):
"""Return the value of the given property as a boolean.
:param str prop_name:
The name of the property.
:rtype: bool
"""
return bool(self._get_property(prop_name, SendPropType.INT))
[docs] def get_property_float(self, prop_name):
"""Return the value of the given property as a float.
:param str prop_name:
The name of the property.
:rtype: float
"""
return self._get_property(prop_name, SendPropType.FLOAT)
[docs] def get_property_int(self, prop_name):
"""Return the value of the given property as an integer.
:param str prop_name:
The name of the property.
:rtype: int
"""
return self._get_property(prop_name, SendPropType.INT)
[docs] def get_property_string(self, prop_name):
"""Return the value of the given property as a string.
:param str prop_name:
The name of the property.
:rtype: str
"""
return self._get_property(prop_name, SendPropType.STRING)
[docs] def get_property_vector(self, prop_name):
"""Return the value of the given property as a string.
:param str prop_name:
The name of the property.
:rtype: Vector
"""
return self._get_property(prop_name, SendPropType.VECTOR)
def _set_property(self, prop_name, prop_type, value):
"""Set the given property to the given value.
:param str prop_name:
The name of the property.
:param SendPropType prop_type:
The type of the property.
:param value object:
To value to set to the given property.
"""
# Is the given property not valid?
if prop_name not in self.template.properties:
# Raise an exception...
raise NameError(
'"{}" is not a valid property for temp entity "{}".'.format(
prop_name, self.name))
# Get the property data...
prop, offset, type_name = self.template.properties[prop_name]
# Are the prop types matching?
if prop.type != prop_type:
# Raise an exception...
raise TypeError('"{}" is not of type "{}".'.format(
prop_name, prop_type))
# Is the property an array?
if prop_type == SendPropType.ARRAY:
# Is the given value not an Array instance?
if not isinstance(value, Array):
# Raise an exception...
raise TypeError('Given value is not an Array instance.')
# Is the length not matching?
if value._length != prop.length:
# Raise an exception...
raise ValueError('Given array is not of length "{}".'.format(
prop.length))
# Copy the values...
value.copy(get_object_pointer(self), self._get_type_size(
type_name) * prop.length)
# No need to go further...
return
# Otherwise, is the type native?
elif Type.is_native(type_name):
# Set the value of the property...
getattr(get_object_pointer(self), 'set_{}'.format(type_name))(
value, offset)
# No need to go further...
return
# Otherwise...
else:
# Get the class...
cls = manager.get_class(type_name)
# Is the given value valid?
if not isinstance(value, cls):
# Raise an exception...
raise TypeError('"{}" is not a valid "{}" value.'.format(
value, type_name))
# Set the value of the property...
get_object_pointer(value).copy(
get_object_pointer(self) + offset, get_size(cls))
# No need to go further...
return
# Raise an exception...
raise NameError('Unable to set "{}" for the temp entity "{}".'.format(
prop_name, self.name))
[docs] def set_property_array(self, prop_name, value):
"""Set the value of the given property as an Array instance.
:param str prop_name:
The name of the property.
:param Array value:
The value to set.
"""
self._set_property(prop_name, SendPropType.ARRAY, value)
[docs] def set_property_bool(self, prop_name, value):
"""Set the value of the given property as a boolean.
:param str prop_name:
The name of the property.
:param bool value:
The value to set.
"""
self._set_property(prop_name, SendPropType.INT, int(value))
[docs] def set_property_float(self, prop_name, value):
"""Set the value of the given property as a float.
:param str prop_name:
The name of the property.
:param float value:
The value to set.
"""
self._set_property(prop_name, SendPropType.FLOAT, value)
[docs] def set_property_int(self, prop_name, value):
"""Set the value of the given property as an integer.
:param str prop_name:
The name of the property.
:param int value:
The value to set.
"""
self._set_property(prop_name, SendPropType.INT, value)
[docs] def set_property_string(self, prop_name, value):
"""Set the value of the given property as a string.
:param str prop_name:
The name of the property.
:param str value:
The value to set.
"""
self._set_property(prop_name, SendPropType.STRING, value)
[docs] def set_property_vector(self, prop_name, value):
"""Set the value of the given property as a string.
:param str prop_name:
The name of the property.
:param Vector value:
The value to set.
"""
self._set_property(prop_name, SendPropType.VECTOR, value)
[docs] def create(self, *recipients, delay=0.0, **aliases):
"""Create the temp entity effect.
:param RecipientFilter recipients:
The recipient filter listing the players to send the effect to.
:param float delay:
The delay before creating the effect.
:param dict aliases:
Any aliases to set before creating the temp entity effect.
"""
# Get a recipient filter matching the given players...
recipients = RecipientFilter(*recipients)
# Loop trhough all given aliases...
for alias, value in aliases.items():
# Set the alias to the given value...
setattr(self, alias, value)
# Create the temp entity effect...
super().create(recipients, delay)
@property
def template(self):
"""Return the template of the temp entity.
:rtype: TempEntityTemplate
"""
return temp_entity_templates[self.name]