1515# Engines
1616from engines .server import server
1717from engines .server import engine_server
18+ from engines .server import server_game_dll
1819from engines .trace import engine_trace
1920from engines .trace import ContentMasks
2021from engines .trace import GameTrace
2324from engines .trace import TraceFilterSimple
2425# Entities
2526from entities .constants import CollisionGroup
27+ from entities .constants import INVALID_ENTITY_INDEX
2628from entities .constants import MoveType
2729from entities .constants import TakeDamage
2830from entities .entity import Entity
31+ from entities .helpers import edict_from_index
32+ from entities .helpers import index_from_inthandle
33+ from entities .props import SendPropType
2934# Mathlib
3035from mathlib import Vector
3136from mathlib import QAngle
4146from players .helpers import uniqueid_from_playerinfo
4247from players .games import _GameWeapons
4348from players .voice import mute_manager
44- from players .weapons import _PlayerWeapons
49+ # Weapons
50+ from weapons .default import NoWeaponManager
51+ from weapons .entity import Weapon
52+ from weapons .manager import weapon_manager
4553
4654
4755# =============================================================================
5462# =============================================================================
5563# >> CLASSES
5664# =============================================================================
57- class Player (Entity , _GameWeapons , _PlayerWeapons ):
65+ class Player (Entity , _GameWeapons ):
5866 """Class used to interact directly with players."""
5967
6068 def __init__ (self , index ):
@@ -539,6 +547,122 @@ def get_stuck(self):
539547
540548 stuck = property (get_stuck , set_stuck )
541549
550+ # =========================================================================
551+ # >> PLAYER WEAPON FUNCTIONALITY
552+ # =========================================================================
553+ @property
554+ def primary (self ):
555+ """Return the player's primary weapon.
556+
557+ :rtype: Weapon
558+ """
559+ return self .get_weapon (is_filters = 'primary' )
560+
561+ @property
562+ def secondary (self ):
563+ """Return the player's secondary weapon.
564+
565+ :rtype: Weapon
566+ """
567+ return self .get_weapon (is_filters = 'secondary' )
568+
569+ @property
570+ def active_weapon (self ):
571+ """Return the player's active weapon.
572+
573+ :rtype: Weapon
574+ """
575+ # Get the player's active weapon's index
576+ index = index_from_inthandle (self .active_weapon_handle )
577+
578+ # Does the player have an active weapon?
579+ if index is not None :
580+
581+ # Return a Weapon instance for the player's active weapon
582+ return Weapon (index )
583+
584+ # If no active weapon, return None
585+ return None
586+
587+ def get_weapon (self , classname = None , is_filters = None , not_filters = None ):
588+ """Return the first found weapon for the given arguments.
589+
590+ :rtype: Weapon
591+ """
592+ # Loop through all weapons for the given arguments
593+ for weapon in self .weapons (classname , is_filters , not_filters ):
594+
595+ # Return the first found weapon
596+ return weapon
597+
598+ # If no weapon is found, return None
599+ return None
600+
601+ def weapons (self , classname = None , is_filters = None , not_filters = None ):
602+ """Iterate over the player's weapons for the given arguments.
603+
604+ :return: A generator of :class:`weapons.entity.Weapon` objects
605+ :rtype: generator
606+ """
607+ # Loop through all the players weapons for the given arguments
608+ for index in self .weapon_indexes (classname , is_filters , not_filters ):
609+
610+ # Yield the current weapon
611+ yield Weapon (index )
612+
613+ def weapon_indexes (
614+ self , classname = None , is_filters = None , not_filters = None ):
615+ """Iterate over the player's weapon indexes for the given arguments.
616+
617+ :return: A generator of indexes
618+ :rtype: generator
619+ """
620+ # Is the weapon array supported for the current game?
621+ if _weapon_prop_length is None :
622+ return
623+
624+ # Loop through the length of the weapon array
625+ for offset in range (_weapon_prop_length ):
626+
627+ # Get the player's current weapon at this offset
628+ handle = self .get_property_int (
629+ weapon_manager .myweapons + '%03i' % offset )
630+
631+ # Get the weapon's index
632+ index = index_from_inthandle (handle , raise_exception = False )
633+
634+ # Is this a valid index?
635+ if index == INVALID_ENTITY_INDEX :
636+
637+ # Move onto the next offset
638+ continue
639+
640+ # Get the weapon's classname
641+ weapon_class = edict_from_index (index ).get_class_name ()
642+
643+ # Was a classname given and the current
644+ # weapon is not of that classname?
645+ if classname is not None and weapon_class != classname :
646+
647+ # Do not yield this index
648+ continue
649+
650+ # Import WeaponClassIter to use its functionality
651+ from filters .weapons import WeaponClassIter
652+
653+ # Was a weapon type given and the
654+ # current weapon is not of that type?
655+ if not (is_filters is None and not_filters is None ):
656+ if weapon_class not in [
657+ weapon .name for weapon in WeaponClassIter (
658+ is_filters , not_filters )]:
659+
660+ # Do not yield this index
661+ continue
662+
663+ # Yield the index
664+ yield index
665+
542666
543667# =============================================================================
544668# >> CALLBACKS
@@ -552,3 +676,51 @@ def _pre_client_command(args):
552676 """
553677 if args [2 ] == 'name "%s"' :
554678 return 0
679+
680+
681+ # =============================================================================
682+ # >> HELPER FUNCTIONS
683+ # =============================================================================
684+ def _find_weapon_prop_length (table ):
685+ """Loop through a prop table to find the myweapons property length."""
686+ # Loop through the props in the table
687+ for offset in range (len (table )):
688+
689+ # Get the prop
690+ item = table [offset ]
691+
692+ # Is this the m_hMyWeapons prop?
693+ if item .name == weapon_manager .myweapons [:~ 0 ]:
694+
695+ # If so, return the length of the prop table
696+ return len (item .data_table )
697+
698+ # Is the current prop a table?
699+ if item .type == SendPropType .DATATABLE :
700+
701+ # Loop through the table
702+ _find_weapon_prop_length (item .data_table )
703+
704+ # Default the weapon prop length to None
705+ _weapon_prop_length = None
706+
707+ # Is the game supported?
708+ if not isinstance (weapon_manager , NoWeaponManager ):
709+
710+ # Get the first ServerClass object
711+ _current_class = server_game_dll .get_all_server_classes ()
712+
713+ # Use "while" to loop through all ServerClass objects
714+ while _current_class :
715+
716+ # Loop through the ServerClass' props
717+ _weapon_prop_length = _find_weapon_prop_length (_current_class .table )
718+
719+ # Was m_hMyWeapons found?
720+ if _weapon_prop_length is not None :
721+
722+ # No need to continue looping
723+ break
724+
725+ # Move to the next ServerClass
726+ _current_class = _current_class .next
0 commit comments