Skip to content

Instantly share code, notes, and snippets.

@adamcunnington
Created November 5, 2013 00:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamcunnington/a0bfe5481270cb20cbf1 to your computer and use it in GitHub Desktop.
Save adamcunnington/a0bfe5481270cb20cbf1 to your computer and use it in GitHub Desktop.
# <path to game directory>/addons/eventscripts/_engines/python/Lib/esutils/
# weapons.py
# by Adam Cunnington
"""Provide a uniform manner to register and store weapon information but also
methods to query realtime information, such as data for a specific weapon
index.
"""
from esutils import tools
import es
__all__ = (
"SLOT_PRIMARY",
"SLOT_SECONDARY",
"SLOT_MELEE",
"SLOT_GRENADE",
"SLOT_BOMB",
"WeaponsError",
"WeaponManager",
"CATEGORY_OBJECTIVE",
"CATEGORY_GRENADE",
"CATEGORY_MACHINE_GUN",
"CATEGORY_MELEE",
"CATEGORY_PISTOL",
"CATEGORY_RIFLE",
"CATEGORY_SHOTGUN",
"CATEGORY_SNIPER_RIFLE",
"CATEGORY_SUBMACHINE_GUN",
"Weapon",
"idle_weapon_types_by_categories",
"indexes_by_categories",
"indexes_by_names",
"indexes_by_slot",
"transform_weapon_name",
"weapon_by_name",
"weapon_types_by_categories",
"weapon_types_by_slot",
)
SLOT_PRIMARY = 1
SLOT_SECONDARY = 2
SLOT_MELEE = 3
SLOT_GRENADE = 4
SLOT_BOMB = 5
class WeaponsError(Exception):
"""General error encountered relating to esutils.weapons"""
pass
class _WeaponType(object):
def __init__(self, name, clip_size, max_ammo_variable,
ammo_property_number, weapon_mode_property=None):
"""Instantiate a _WeaponType object.
Arguments:
name - the full name of the weapon's classname.
clip_size - the size of the weapon's clip when full.
max_ammo_variable - the number representing the ammo type to be
substituted into the variable string, ammo_<number>_max.
ammo_property_number - the number representing the ammo property to be
substituted into the entity property,
"CBasePlayer.localdata.m_iAmmo.<number>".
weapon_mode_property (Keyword Default: None) - the entity property
name of the weapon's SLOT_SECONDARY attack mode.
"""
self._max_ammo_variable = es.ServerVar("ammo_%s_max"
% max_ammo_variable)
self.name = name
self.clip_size = clip_size
self.ammo_property = ("CBasePlayer.localdata.m_iAmmo.%s"
% ammo_property_number)
self.weapon_mode_property = weapon_mode_property
def _get_max_ammo(self):
return int(self._max_ammo_variable)
def _set_max_ammo(self, value):
self._max_ammo_variable.set(value)
max_ammo = property(_get_max_ammo, _set_max_ammo)
@property
def indexes(self):
# Property get function that returns the compiled entityindexlist for
# the weapon's classname.
return es.createentityindexlist(self.name)
class WeaponManager(object):
"""Create a thread safe instance to manage a game's weapons
individually.
"""
def __init__(self):
self.weapons = {}
def register(self, weapon_class, name, *args, **kwargs):
"""Register data about a weapon to the central data structure.
Arguments:
weapon_class - the category of weapon class the weapon belongs to.
name - the full classname of the weapon.
args - the positional arguments defined in the weapon class.
kwargs - the keyword arguments defined in the weapon class.
"""
self.weapons[name] = weapon_class(name, *args, **kwargs)
CATEGORY_OBJECTIVE = object()
class _Bomb(_WeaponType):
SLOT = SLOT_BOMB
CATEGORY = CATEGORY_OBJECTIVE
VERBOSE_CATEGORY = "Objective"
def __init__(self, name):
super(_Bomb, self).__init__(name, 0, None, None)
CATEGORY_GRENADE = object()
class _Grenade(_WeaponType):
SLOT = SLOT_GRENADE
CATEGORY = CATEGORY_GRENADE
VERBOSE_CATEGORY = "Grenade"
def __init__(self, name, ammo_property_number):
super(_Grenade, self).__init__(name, 0, name, ammo_property_number)
CATEGORY_MACHINE_GUN = object()
class _MachineGun(_WeaponType):
SLOT = SLOT_PRIMARY
CATEGORY = CATEGORY_MACHINE_GUN
VERBOSE_CATEGORY = "Machine Gun"
CATEGORY_MELEE = object()
class _Melee(_WeaponType):
SLOT = SLOT_MELEE
CATEGORY = CATEGORY_MELEE
VERBOSE_CATEGORY = "Melee"
def __init__(self, name):
super(_Melee, self).__init__(name, 0, None, None)
CATEGORY_PISTOL = object()
class _Pistol(_WeaponType):
SLOT = SLOT_SECONDARY
CATEGORY = CATEGORY_PISTOL
VERBOSE_CATEGORY = "Pistol"
CATEGORY_RIFLE = object()
class _Rifle(_WeaponType):
SLOT = SLOT_PRIMARY
CATEGORY = CATEGORY_RIFLE
VERBOSE_CATEGORY = "Rifle"
CATEGORY_SHOTGUN = object()
class _Shotgun(_WeaponType):
SLOT = SLOT_PRIMARY
CATEGORY = CATEGORY_SHOTGUN
VERBOSE_CATEGORY = "Shotgun"
CATEGORY_SNIPER_RIFLE = object()
class _SniperRifle(_WeaponType):
SLOT = SLOT_PRIMARY
CATEGORY = CATEGORY_SNIPER_RIFLE
VERBOSE_CATEGORY = "Sniper Rifle"
CATEGORY_SUBMACHINE_GUN = object()
class _SubMachineGun(_WeaponType):
SLOT = SLOT_PRIMARY
CATEGORY = CATEGORY_SUBMACHINE_GUN
VERBOSE_CATEGORY = "Submachine Gun"
_cstrike = WeaponManager()
_cstrike.register(_Shotgun, "weapon_m3", 8, "buckshot", "007")
_cstrike.register(_Shotgun, "weapon_xm1014", 7, "buckshot", "007")
_cstrike.register(_SubMachineGun, "weapon_mac10", 30, "45acp", "008")
_cstrike.register(_SubMachineGun, "weapon_tmp", 30, "9mm", "006")
_cstrike.register(_SubMachineGun, "weapon_mp5navy", 30, "9mm", "006")
_cstrike.register(_SubMachineGun, "weapon_ump45", 25, "45acp", "008")
_cstrike.register(_SubMachineGun, "weapon_p90", 50, "57mm", "010")
_cstrike.register(_Rifle, "weapon_galil", 35, "556mm", "003")
_cstrike.register(_Rifle, "weapon_famas", 25, "556mm", "003",
"CWeaponFamas.m_bBurstMode")
_cstrike.register(_Rifle, "weapon_ak47", 30, "762mm", "002")
_cstrike.register(_Rifle, "weapon_m4a1", 30, "556mm", "003",
"CWeaponM4A1.m_bSilencerOn")
_cstrike.register(_Rifle, "weapon_sg552", 30, "556mm", "003")
_cstrike.register(_Rifle, "weapon_aug", 30, "762mm", "002")
_cstrike.register(_MachineGun, "weapon_m249", 100, "556mm_box", "004")
_cstrike.register(_SniperRifle, "weapon_scout", 10, "762mm", "002")
_cstrike.register(_SniperRifle, "weapon_awp", 10, "338mag", "005")
_cstrike.register(_SniperRifle, "weapon_sg550", 30, "556mm", "003")
_cstrike.register(_SniperRifle, "weapon_g3sg1", 20, "762mm", "002")
_cstrike.register(_Pistol, "weapon_glock", 20, "9mm", "006",
"CWeaponGlock.m_bBurstMode")
_cstrike.register(_Pistol, "weapon_usp", 12, "45acp", "008",
"CWeaponUSP.m_bSilencerOn")
_cstrike.register(_Pistol, "weapon_p228", 13, "357sig", "009")
_cstrike.register(_Pistol, "weapon_deagle", 7, "50ae", "001")
_cstrike.register(_Pistol, "weapon_elite", 30, "9mm", "006")
_cstrike.register(_Pistol, "weapon_fiveseven", 20, "57mm", "010")
_cstrike.register(_Melee, "weapon_knife")
_cstrike.register(_Grenade, "weapon_flashbang", "012")
_cstrike.register(_Grenade, "weapon_heSLOT_GRENADE", "011")
_cstrike.register(_Grenade, "weapon_smokeSLOT_GRENADE", "013")
_cstrike.register(_Bomb, "weapon_c4")
class Weapon(object):
"""Create a unique weapon object representing an individual index that can
be queried and set."""
def __init__(self, index):
"""Instantiate a Weapon object.
Arguments:
index - the individual index of the specific weapon.
"""
self.index = index
name = es.entitygetvalue(index, "classname")
if not name.startswith("weapon_"):
raise WeaponsError("%s is not a valid weapon index" % self.index)
self.weapon_type = _cstrike.weapons[name]
def _get_ammo(self):
owner = self.owner
if self.owner is None:
raise WeaponsError("weapon does not have an owner")
return es.getplayerprop(owner.user_ID, self.weapon_type.ammo_property)
def _get_clip(self):
clip = es.getindexprop(self.index,
"CBaseCombatWeapon.LocalWeaponData.m_iClip1")
if clip != -1:
return clip
# Instead of raising an exception, if the weapon has no clip value,
# return None.
return None
def _get_colour(self):
return tools.get_colour(self.index)
def _get_handle(self):
return es.getindexprop(index, "CBaseCombatWeapon.m_hOwner")
def _is_mode_on(self):
"""Determine whether the weapon's SLOT_SECONDARY attack mode is on and
return the result. Immediately return False if the weapon has no
SLOT_SECONDARY mode.
"""
if self.weapon_type.weapon_mode_property is None:
return False
return bool(es.getindexprop(self.index, self.weapon_type))
def remove(self):
"""Remove the weapon from existence on the server."""
es.server.insertcmd("es_xremove %s" % self.index)
def _set_ammo(self, value):
owner = self.owner
if self.owner is None:
raise WeaponsError("weapon does not have an owner")
return es.setplayerprop(owner.user_ID, self.weapon_type.ammo_property,
value)
ammo = property(_get_ammo, _set_ammo)
def _set_clip(self, value):
es.setindexprop(self.index,
"CBaseCombatWeapon.LocalWeaponData.m_iClip1", value)
clip = property(_get_clip, _set_clip)
def _set_colour(self, red, blue, green, alpha=255):
tools.set_colour(self.index, red, blue, green, alpha)
colour = property(_get_colour, _set_colour)
def _set_mode(self, value):
if self.weapon_type.weapon_mode_property is None:
raise AttributeError("can't set attribute")
# The property set function that will only be available if the weapon
# has a SLOT_SECONDARY weapon mode and can forcefully set the mode to
# be on or off.
es.setindexprop(self.index, self.weapon_type.weapon_mode_property,
int(value))
mode_on = property(_is_mode_on, _set_mode)
def _get_indexes(iterable):
# Internal helper function that returns a generator of indexes.
for weapon_type in iterable:
for index in weapon_type.indexes:
yield index
def idle_weapon_types_by_categories(*args):
"""Return a generator object of idle weapon indexes. If arguments are
omitted, return all.
Arguments:
args - categories to filter return results by.
"""
for index in _get_indexes(weapon_types_by_categories(*args)):
if es.getindexprop(index, "CBaseCombatWeapon.m_hOwner") == -1:
yield index
def indexes_by_categories(*args):
"""Return a generator object of indexes for weapons in specific
categories. If arguments are omitted, return all.
Arguments:
args - categories to filter return results by.
"""
return _get_indexes(weapon_types_by_categories(*args))
def indexes_by_names(*args, weapon_manager=_cstrike):
"""Return a generator object of indexes for weapons with specific names.
Arguments:
args - names to filter return results by.
"""
return _get_indexes(weapon_manager.weapons[name]
for transform_weapon_name(name) in *args)
def indexes_by_slot(slot):
"""Return a generator object of indexes for weapons in specific slots.
Arguments:
args - weapon slot to filter return results by.
"""
return _get_indexes(weapon_types_by_slot(slot))
def transform_weapon_name(name):
if name.startswith("weapon_"):
return name
return "weapon_%s" % name
def weapon_types_by_name(*args, weapon_manager=_cstrike):
"""Return a generator object weapon type objects for weapons with
particular names.
Arguments:
args - names to filter return results by.
"""
for name in args:
yield weapon_manager.weapons[transform_weapon_name(name)]
def weapon_types_by_categories(*args, weapon_manager=_cstrike):
"""Return a generator object of weapon type objects for weapons in
specific categories. If arguments are omitted, return all.
Arguments:
args - categories to filter return results by.
"""
if not args:
return weapon_manager.weapons.itervalues()
return (weapon_type for weapon_type in weapon_manager.weapons.itervalues()
if weapon_type.CATEGORY in args)
def weapon_types_by_slot(slot, weapon_manager=_cstrike):
"""Return a generator object of weapon type objects for weapons in
specific slots.
Arguments:
args - weapon slot to filter return results by.
"""
for weapon_type in weapon_manager.weapons.itervalues():
if weapon_type.SLOT == slot:
yield weapon_type
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment