# WarCraft Source: Python release 0.8.7 by Steven Hartin (freddukes) and Jeff Hoogland (Jeff91)
# ./addons/eventscripts/wcs/wcs.py

# >>> To configure this addon please see wcsconfig.cfg <<<

#################################
#### DO NOT EDIT THIS FILE, #####
####    IF YOU DO, THINGS   #####
####       COULD BREAK      #####
#################################

# Import Modules
import es
import playerlib
import gamethread
import popuplib
import cPickle
import os
import time
import random
import langlib
import keyvalues
import difflib
import effectlib
import vecmath
import math

import re
from string import Template

# psyco, more unstable but a lot faster
import psyco
psyco.full() 

# Set the addon info data
info          = es.AddonInfo()
info.name     = 'WarCraft: Source'
info.version  = '0.8.7a Python'
info.url      = 'www.warcraftpython.net'
info.basename = 'wcs'
info.author   = 'Steven Hartin & Jeff Hoogland (Freddukes & J3ff)'

# Make Public Variable
es.ServerVar('wcs_version', info.version, 'WarCraft: Source Version - Made by Freddukes & Jeff').makepublic()

#Global Variables
keygroupraces = {}
    
colors = { 
'red':     ['255', '0'  , '0'  ],
'blue':    ['0'  , '0'  , '255'],
'green':   ['0'  , '255', '0'  ],
'magenta': ['139', '0'  , '139'],
'brown':   ['128', '42' , '42' ],
'grey':    ['128', '128', '128'],
'cyan':    ['0'  , '204', '204'],
'yellow':  ['255', '255', '0'  ],
'orange':  ['255', '127', '0'  ],
'white':   ['255', '255', '255'],
'pink':    ['255', '0'  , '204']
}

""" Create the 'default' language for HL2DM """
popuplib.langdata['default'] = {'prev': "Back", 'next': "Next", 'quit': "Cancel", 'pending': "Pending"}
    
defaults = {
'wcs_debug'                     : [0,   "The debug Level"],
'wcs_start_your_engines'        : [300, "The amount of xp required to level up to level 2"], 
'wcs_levelinterval'             : [100, "The amount of xp increment after level 2"],
'wcs_killxp'                    : [40, "The amount of xp gained from a kill"],
'wcs_headshotxp'                : [25, "The amount of xp gained from a headshot"],
'wcs_winroundxp'                : [15, "The amount of xp gained from winning the round"],
'wcs_bombplantxp'               : [50, "The amount of xp gained from planting the bomb"],
'wcs_bombdefusexp'              : [50, "The amount of xp gained from defusing the bomb"],
'wcs_bombexplodexp'             : [15, "The amount of xp gained from allowing the bomb to explode"],
'wcs_hostagexp'                 : [15, "The amount of xp gained from saving a hostage (per hostage)"],
'wcs_levelxp'                   : [4, "The amount of extra xp gained multiplied by the amount of levels the victim is above the attacker"],
'wcs_allhostagexp'              : [15, "The additional xp received after all hostages have been resced"],
'wcs_announcexp'                : [1, "Announce xp on start?"],
'wcs_cssdm'                     : [0, "Are you runing CSS:DM?"],
'wcs_maxitems'                  : [4, "The maximum number of items a player can buy per round"],
'wcs_minplayers'                : [0, "The minimum number of players on the server before xp is received"],
'wcs_freelevels'                : [0, "The amount of free levels a player gains from joining the server for the first time."],
'wcs_inactivity_counter'        : [7, "After this many days, the user will be deleted from the dictionary"],
'wcs_savetimer'                 : [3, "The amount of minutes that the database will save"],
'wcs_admins'                    : ["", "The admins allowed to use the wcsadmin"],
'wcs_weaponbonus'               : ["", "The bonus weapons"],
'wcs_weaponbonusxp'             : ["", "The amount of bonus xp per weapon."],
'wcs_new_race_increments_level' : [1, "Will unlocking a new race increment the players total level"]
}

text        = lambda x, y = {}, lang = "en": "strings.ini not found in the ../wcs/ directory!"
isEst       = bool(str(es.ServerVar('est_version')) != "0")
isOb        = bool(int(str(es.ServerVar('eventscripts_ver')).split('.')[1]) >= 1)
isModEvents = os.path.isfile(es.getAddonPath('wcs').replace('\\','/').replace('/wcs','/modevents/__init__.py'))

""" Custom exceptions so we can define our own errors """
class ESTError(Exception):
    """ Class to allow us to make our own Error """
    pass
""""""
    
def load():
    """ Runs when the addon is laoded... Load all the correct files into memory so they can
        be accessed via the global python vars later on. """
    global dir
    global game
    global text
    global _dict_WCSPlayers
    global race_folder
    global language_keygroup
    
    debugMsg(0, '\n************', writeTime = False )
    debugMsg(0, 'WarCraft: Source Version: %s' % info.version, writeTime = False )
    debugMsg(0, 'Created by Jeff Hoogland (Jeff91) and Steven Hartin (freddukes)', writeTime = False )
    debugMsg(0, 'Log file started at %s' % time.strftime("%A %d %B %Y - %H:%M:%S"), writeTime = False )
    debugMsg(0, '\nSystem Info:', writeTime = False )
    debugMsg(0, '\tOS: %s' % ("Windows" if os.name == "nt" else "Linux" if os.name == "posix" else os.name), writeTime = False )
    debugMsg(0, '\tEventscripts Version: %s' % es.ServerVar('eventscripts_ver') + ( " (Orange Box)" if isOb else ""), writeTime = False )
    debugMsg(0, '\tCorelib Version: %s' % es.ServerVar('es_corelib_ver'), writeTime = False )
    debugMsg(0, '\tEventscript Tools Version: %s' % (es.ServerVar('est_version') if isEst else "Not Installed"), writeTime = False )
    debugMsg(0, '\tEventscripts Noisy: %s' % es.ServerVar('eventscripts_noisy'), writeTime = False )
    debugMsg(0, '\tPopuplib version: %s' % popuplib.info.version, writeTime = False )
    debugMsg(0, '\tModEvents: %s' % isModEvents, writeTime = False) 
    debugMsg(0,'************\n', writeTime=False )
    es.keygroupcreate('WCSuserdata')
    
    
    """ Load the language keygroup into memory so we can use wcs_getlanguage """
    strFile = es.getAddonPath('wcs') + '/WCSlanguage/es_WCSlanguage_db.txt'
    if os.path.isfile(strFile):
        language_keygroup = keyvalues.KeyValues(filename = strFile)
    else:
        language_keygroup = {}
        debugMsg(0, 'WCS: ERROR - Cannot find the es_WCSlanguage_db.txt inside ../wcs/WCSlanguage/')
    
    """ Create the WCS command to control all the wcs commands """
    if not es.exists('command', 'wcs'):
        es.regcmd('wcs', 'wcs/wcscommand')
    
    """ Assign all the default values from the config file. """
    for x in defaults:
        es.ServerVar(x, defaults[x][0], defaults[x][1])
    
    """ Convert the weaponbonus, weaponbonusxp and wcs_admins into python lists. """
    gamethread.delayed(0, configweapons)
    gamethread.delayed(0, configadmins)
    """"""
    
    """Get the folder where the race is..."""
    race_folder = "Invalid Race Rolder!"
    string_path = es.getAddonPath('wcs').replace('\\','/') + '/races'
    if os.path.isdir(string_path):
        race_folder = string_path
    
    """ Load all the server commands """
    servercommands = ('wcs_dealdamage', 'wcs_setfx', 'wcs_getlanguage', 'wcs_removefx')
    for x in servercommands:
        if not es.exists('command', x):
            es.regcmd(x, 'wcs/%s'%x)
            
    """ Register all the old ESS variables """
    set_variables()
    
    """ Get the directory of the game. This is where the mod is placed. """
    dir = str(es.ServerVar('eventscripts_gamedir')).replace('\\', '/').split('/')[~0]
    if dir == 'cstrike':
        game = 'Counter-Strike: Source'
    elif dir == 'hl2mp':
        game = 'Half Life 2 Deathmatch'
    elif dir == 'dod':
        game = 'Day of Defeat: Source'
    elif dir == 'tf':
        game = 'Team Fortress 2'
    elif dir == 'pvkii':
        game = 'Pirates, Vikings, and Knights'
    else:
        game = 'Unknown'
    
    """ Load the dictionary into memory from file """
    str_path = es.getAddonPath('wcs') + '/UserSaves.db'
    if os.path.isfile(str_path):
        file_users = open(str_path)
        _dict_WCSPlayers = cPickle.load(file_users)
        file_users.close()
    else:
        debugMsg(0, 'WCS: ERROR - Unable to load UserSaves.db! Making one now!!!')
    
    """ Load the config file """
    if os.path.isfile(es.getAddonPath('wcs') + '/WCSConfig.cfg'):
        if isOb:
            es.mexec('../addons/eventscripts/wcs/WCSConfig.cfg')
        else:
            es.server.cmd('es_xmexec ../addons/eventscripts/wcs/WCSconfig.cfg')
    else:
        debugMsg(0,'WCS: ERROR - Unable to load WCSconfig.cfg! Please ensure it is in the ./wcs/ directory.')
    
    """ Load all the popups so that they are in the memory """
    popup_folder = es.getAddonPath('wcs') + '/popups'
    if os.path.isdir(popup_folder):
        for popup_file in os.listdir(popup_folder):
            languageFile = popup_folder + '/' + popup_file
            if os.path.isfile(languageFile):
                loadPopupFiles(languageFile)
            else:
                debugMsg(0, 'WCS: ERROR - An error occured whilst attempting to load popup language file: %s' % languageFile)
    else:
        debugMsg(0, 'WCS: ERROR - Unable to find the popups folder! Please ensure it is in the ./wcs directory.')
    
    """ Get the strings path, and load it with the varibale text """    
    lang_path = es.getAddonPath('wcs') + '/strings.ini'
    if os.path.isfile(lang_path):
        text = langlib.Strings(es.getAddonPath('wcs') + '/strings.ini')
    else:
        debugMsg(0, 'WCS: ERROR - Unable to load strings.ini! Please ensure it is in the ./wcs/ directory.')

    """ Load the Race Loader file so it loads all races into memory """
    if os.path.isfile(es.getAddonPath('wcs') + '/WCSRaceLoader.cfg'):
        if isOb:
            es.mexec('../addons/eventscripts/wcs/WCSRaceLoader.cfg')
        else:
            es.server.queuecmd('es_xmexec ../addons/eventscripts/wcs/WCSRaceLoader.cfg')
    else:
        debugMsg(0,'WCS: ERROR - Unable to load WCSRaceLoader.cfg! Please ensure it is in the ./wcs/ directory.')
        
    """ Load the shop loader so all the items are loaded. """
    if os.path.isfile(es.getAddonPath('wcs') + '/WCSShopLoader.cfg'):
        if isOb:
            es.mexec('../addons/eventscripts/wcs/WCSShopLoader.cfg')
        else:
            es.server.queuecmd('es_xmexec ../addons/eventscripts/wcs/WCSShopLoader.cfg')
    else:
        debugMsg(0,'WCS: ERROR - Unable to load WCSShopLoader.cfg! Please ensure it is in the ./wcs/ directory.')
    
    
    """ Turn the old style races into individule races """
    strPath = es.getAddonPath('wcs') + '/races/es_WCSraces_db.txt'
    if os.path.isfile(strPath):
        k = keyvalues.KeyValues(filename = strPath)
        for key in k:
            name = k[key.getName()]['name']
            if not name.startswith('wcs_lng'):
                try:
                    temp_keygroup = keyvalues.KeyValues(name = name)
                    temp_keygroup["race"] = keyvalues.KeyValues(name = 'race')
                    for thing in k[key.getName()]:
                        temp_keygroup["race"][thing.getName()] = k[key.getName()][thing.getName()]
                    race_folder = strPath.replace('es_WCSraces_db.txt','') + '%s' % name
                    if not os.path.isdir(race_folder):
                        os.mkdir(race_folder)
                    if not os.path.isfile(race_folder + '/%s.py' % name) and not os.path.isfile(race_folder + '/es_%s.txt' % name) and not os.path.isfile(race_folder + '/es_%s_db.txt' % name):
                        """ Only create the keygroup race if there isn't a race with the same name, either in *.py, es_*.txt or es_%s_db.txt """
                        temp_keygroup.save(race_folder + '/es_%s_db.txt' % name)
                        # Rename the file so it's in the same case
                        os.rename(race_folder + '/es_%s_db.txt' % name.lower(), race_folder + '/es_%s_db.txt' % name)
                except KeyError:
                    debugMsg(1, 'WCS: ERROR - An unknown error occured whilst attempting to convert keygroup race %s.' % name\
                    + '\nRun it through the racecheckfile first (http://warcraft-source.com/racefilecheck/index.php)')
        os.remove(strPath)
    
    """ Create a dictioanry which holds all the say and console commands """        
    command_list = {
    'wcshelp'      : ['wcs/wcsHelp'           , 'Help'                          , True],
    'wcsmenu'      : ['wcs/wcsMenu'           , 'Main'                          , True],
    'showrank'     : ['wcs/wcsShowRank'       , 'Rank'                          , True],
    'shopmenu'     : ['wcs/wcsShopMenu'       , 'Shop'                          , True],
    'shopinfo'     : ['wcs/wcsShopInfo'       , 'Shop Info'                     , True],
    'skillsinfo'   : ['wcs/wcsSkillsInfo'     , 'Info about your race\'s skills', True],
    'showskills'   : ['wcs/wcsShowSkills'     , 'Your race skills'              , True],
    'showxp'       : ['wcs/wcsShowXp'         , 'Show your XP'                  , True],
    'showtop10'    : ['wcs/Top10'             , 'Top 10 players'                , True],
    'resetskills'  : ['wcs/wcsResetSkills'    , 'Reset skills'                  , True],
    'spendskills'  : ['wcs/wcsSpendSkills'    , 'Spend Skill Points'            , True],
    'changerace'   : ['wcs/wcsChangeRace'     , 'Change Race'                   , True],
    'raceinfo'     : ['wcs/wcsRaceInfo'       , 'Shows race info'               , True],
    'playerinfo'   : ['wcs/wcsPlayerInfo'     , 'See a player\'s info'          , True],
    'wcsadmin'     : ['wcs/wcsAdmin'          , 'Admin menu'                    , True],
    'wcsgivexp'    : ['wcs/wcsAdminGiveXp'    , 'Admin Cmd'                     , False],
    'wcsgivelevel' : ['wcs/wcsAdminGiveLevel' , 'Admin Cmd'                     , False],
    'wcsshowskills': ['wcs/wcsAdminShowLevels', 'Admin Cmd'                     , False],
    '+ultimate'    : ['wcs/wcsUltiOn'         , 'Turn the WCS Ultimate on'      , False],
    '-ultimate'    : ['wcs/wcsUltiOff'        , 'Turn the WCS Ultimate off'     , False],
    '+ability'     : ['wcs/AbilityOn'         , 'Turn the WCS Ability on'       , False],
    '-ability'     : ['wcs/AbilityOff'        , 'Turn the WCS Ability off'      , False],
    '+ability2'    : ['wcs/AbilityOn2'        , 'Turn the WCS Ability 2 on'     , False],
    '-ability2'    : ['wcs/AbilityOff2'       , 'Turn the WCS Ability 2 off'    , False],
    '+ability3'    : ['wcs/AbilityOn3'        , 'Turn the WCS Ability 3 on'     , False],
    '-ability3'    : ['wcs/AbilityOff3'       , 'Turn the WCS Ability 3 off'    , False],
    '+ability4'    : ['wcs/AbilityOn4'        , 'Turn the WCS Ability 4 on'     , False],
    '-ability4'    : ['wcs/AbilityOff4'       , 'Turn the WCS Ability 4 off'    , False],
    '+ability5'    : ['wcs/AbilityOn5'        , 'Turn the WCS Ability 5 on'     , False],
    '-ability5'    : ['wcs/AbilityOff5'       , 'Turn the WCS Ability 5 off'    , False]
    }
    
    for a in command_list:
        if not es.exists('saycommand', a):
            es.regsaycmd(a, command_list[a][0], command_list[a][1])
        if not es.exists('clientcommand', a):
            es.regclientcmd(a, command_list[a][0], command_list[a][1])
        
    """ Load all the external scripts """
    es.load('wcs/admin')
    es.load('wcs/WCSultimates')
    es.load('wcs/WCSskills')
    
    """ Begin the popup creation """
    h = popuplib.create('wcs_wcshelp')
    addline(h, returnAllLanguages('wcs help', {'version': info.version}) )
    
    a = popuplib.create('wcs_WCSMenu')
    addline(a, returnAllLanguages('wcs menu') )
    a.menuselect = MenuSelect
    
    a = popuplib.create('wcs_INFO')
    addline(a, returnAllLanguages('wcs info') )
    a.menuselect = InfoSelect
    
    a = popuplib.create('wcs_general info')
    addline(a, returnAllLanguages('wcs general info') )
    a.submenu(9, 'wcs_INFO')
    
    a = popuplib.create('wcs_wcsshopinfo')
    addline(a, returnAllLanguages('wcs shopinfo') )
    a.submenu(1,'wcs_enhancementinfo')
    a.submenu(2,'wcs_powerupinfo')
    a.submenu(3,'wcs_attackinfo')
    a.submenu(4,'wcs_defenseinfo')
    a.submenu(5,'wcs_specialinfo')
    
    """ Force the es_map_start method, passing over the value 'forced' """
    gamethread.delayed(0, es_map_start, ({'forced':1}) )
    
    """ Load the events so we can announce events to other scripts """
    es.loadevents('declare', 'addons/eventscripts/wcs/events/events.res')
    
    """ Create a loop to control the damage event """
     
    if dir not in ('cstrike', 'dod') and isEst:
        UpdateHealth()
    elif dir == 'dod' and not isEst:
        if isModEvents:
            __import__('modevents').add_modder('player_hurt', modHurt)
        else:
            debugMsg(0, '\nWCS ERROR - Some races require that you download this file for DOD:S\n\thttp://addons.eventscripts.com/addons/view/modevents\n\tPlease download and restart the server\n')
    if isModEvents and not isEst:
        __import__('modevents').add_modder('player_spawn', modSpawn)
    
    """ Begin the delay to save the dictionary. """
    gamethread.delayed(0, saveloop, (float(es.ServerVar('wcs_savetimer')) * 60) ) 

def unload():
    """ Called when the mod is unloaded.. Unload all the races, extentions, and save the dictionary. """
    es.unload('wcs/admin')
    es.unload('wcs/shopmenu')
    es.unload('wcs/WCSultimates')
    es.unload('wcs/WCSLegacy')
    str_path = open(es.getAddonPath('wcs') + '/UserSaves.db', 'w')
    cPickle.dump(_dict_WCSPlayers, str_path)
    str_path.close()
    if isOb:
        es.server.wcs('unloadallraces')
    else:
        es.server.cmd('wcs unloadallraces')
    gravity.deleteGravityList()
    if not isEst and isModEvents:
        hookers = __import__('modevents').__dict__['hookers']
        if 'player_hurt' in hookers:
            __import__('modevents').del_modder('player_hurt', modHurt)
        if 'player_spawn' in hookers:
            __import__('modevents').del_modder('player_spawn', modSpawn)
    deleted = []
    for popup in popuplib.gPopups:
        if popup.startswith('wcs_'):
            deleted.append(popup)
    for popup in deleted:
        popuplib.delete(popup)
    
def player_activate(ev):
    """ Ran when a player first is activated within the server. Check if they exists within
        the databse, if not, create them. """
    debugMsg(1, '\n********************\nEvent: Player Activate\n', writeTime=False)
    if es.exists('userid', ev['userid']):
        steamid = playerlib.uniqueid(ev['userid'],True)
        debugMsg(1, 'Testing if steamid %s exists within the database'%steamid)
        if _dict_WCSPlayers.has_key(steamid):
            debugMsg(1, 'Steamid exists, overwriting their username and last active times.')
            _dict_WCSPlayers[steamid]['name'] = ev['es_username']
            _dict_WCSPlayers[steamid]['last_active'] = time.time()
        if not es.exists('key', 'WCSuserdata', ev['userid']):
            es.keycreate('WCSuserdata', ev['userid'])
    buildRaceMenu(ev['userid'])
    debugMsg(1, 'End of Player Activate\n********************', writeTime=False)

""" If EST is active then register the pre-hooks and est_map_end etc... """

if isEst:
    
    def est_map_end(ev):
        """ Ran when the map ends. Delete all players if their inactivity is too high """
        debugMsg(1, '\n********************\nEvent: EST Map End\n', writeTime=False)
        time_now = time.time()
        inactivity_length = float(es.ServerVar('wcs_inactivity_counter')) * 86400
        time_now -= inactivity_length
        dellist = []
        for a in _dict_WCSPlayers:
            if _dict_WCSPlayers[a].has_key('last_active'):
                last_active = _dict_WCSPlayers[a]['last_active']
                if time_now >= last_active:
                    # We append to another list so we don't change the size of the dict
                    # during iteration
                    dellist.append(a)
            else:
                dellist.append(a)
        for a in dellist:
            # Delete everyone in the dellist
            del _dict_WCSPlayers[a]
            debugMsg(0,'WCS: Deleting Steamid - %s'%a)
        """ Save the dict """
        str_path = open(es.getAddonPath('wcs') + '/UserSaves.db', 'w')
        cPickle.dump(_dict_WCSPlayers, str_path)
        str_path.close()
        debugMsg(1, 'End of EST Map End\n********************', writeTime=False)

    def es_map_start(ev):
        """ Ran when the map starts. Load the events, and register the pre-hooks """
        es.loadevents('declare', 'addons/eventscripts/wcs/events/events.res')
        es.server.queuecmd('est_RegEventBlock player_spawn "es_xdoblock wcs/prep_spawn"')
        es.server.queuecmd('est_RegEventBlock player_hurt "es_xdoblock wcs/prep_hurt_fire"')

else:

    def es_map_start(ev):
        """ Ran when the map starts... load the events and delete inactive people. """
        debugMsg(1, '\n********************\nEvent: Map Start\n', writeTime=False)
        time_now = time.time()
        inactivity_length = float(es.ServerVar('wcs_inactivity_counter')) * 86400
        time_now -= inactivity_length
        dellist = []
        for a in _dict_WCSPlayers:
            if _dict_WCSPlayers[a].has_key('last_active'):
                last_active = _dict_WCSPlayers[a]['last_active']
                if time_now >= last_active:
                    # We append to another list so we don't change the size of the dict
                    # during iteration
                    dellist.append(a)
            else:
                dellist.append(a)
        for a in dellist:
            # Delete everyone in the dellist
            del _dict_WCSPlayers[a]
            debugMsg(0,'WCS: Deleting Steamid - %s'%a)
        """ Save the dict """
        str_path = open(es.getAddonPath('wcs') + '/UserSaves.db', 'w')
        cPickle.dump(_dict_WCSPlayers, str_path)
        str_path.close()
        es.loadevents('declare', 'addons/eventscripts/wcs/events/events.res')
        debugMsg(1, 'End of Map Start\n********************', writeTime=False)

""" """
        
def round_start(ev):
    """ Occurs when a new round starts. Run the round_start_cmd on all players if their race is a keygrouprace. """
    debugMsg(1, '\n********************\nEvent: Round Start\n', writeTime=False)
    for a in es.getUseridList():
        race = GetRace(a)
        if keygroupraces.has_key(race):
            if 'round_start_cmd' in keygroupraces[race]['race']: 
                spawncmd = str(keygroupraces[race]['race']['round_start_cmd'])
                if spawncmd != '0' and not isinstance(spawncmd, int):
                
                    while spawncmd.find('event_var') > -1:
                        index    = spawncmd.find('event_var(')
                        event    = spawncmd[index + 10: spawncmd.find(')')]
                        spawncmd = spawncmd.replace('event_var(%s)' % event, ev[event])
                
                    debugMsg(1, '\n-----\nPlayer %s has spawned with keygroup race %s\nRunning Round Start Command: %s\n-----' % (es.getplayername(a), race, spawncmd) )
                    es.ServerVar('wcs_dice').set(random.randint(1,100))
                
                    if isOb:
                        if race in dictAlias:
                            for alias in dictAlias[race]:
                                if alias in spawncmd:
                                    spawncmd = spawncmd.replace(alias, "%s_%s" % (alias, race) )
                        for command in spawncmd.split(';'):
                            es.server.queuecmd(command)
                    else:
                        es.server.queuecmd(spawncmd)
                        
    debugMsg(1, 'End of Round Start\n********************', writeTime=False)
    
def dod_round_start(ev):
    round_start(ev)
                
def teamplay_round_start(ev):
    round_start(ev)
                
def round_end(ev):
    """ Runs when the round ends. Get the winner of the round and give them all the xp.
        Cancel all delays that are supposed to end, and change the race if a user has
        one delayed. Save the database. """
    debugMsg(1, '\n********************\nEvent: Round End\n', writeTime=False)
    winner = int(ev['winner'])
    if float(es.ServerVar('wcs_winroundxp')):
        if winner == 2:
            for userid in playerlib.getUseridList('#t'):
                Command(int(userid)).GiveXp(float(es.ServerVar('wcs_winroundxp')), text('end round xp',lang=playerlib.getPlayer(userid).get('lang')))
        if winner == 3:
            for userid in playerlib.getUseridList('#ct'):
                Command(int(userid)).GiveXp(float(es.ServerVar('wcs_winroundxp')), text('end round xp',lang=playerlib.getPlayer(userid).get('lang')))
    for player in es.getUseridList():
        #Command(int(a)).UpdateDict('DefaultGrav',0)
        Command(player)
        race = GetRace(player)
        if keygroupraces.has_key(race):
            if 'round_end_cmd' in keygroupraces[race]['race']:
                debugMsg(2, '\n-----\nPlayer %s has ended the round with a keygroup race' % es.getplayername(player) )
                endcmd = str(keygroupraces[race]['race']['round_end_cmd'])
                if endcmd != '0' and not isinstance(endcmd, int):
                
                    while endcmd.find('event_var') > -1:
                        index    = endcmd.find('event_var(')
                        event    = endcmd[index + 10: endcmd.find(')')]
                        endcmd   = endcmd.replace('event_var(%s)' % event, ev[event])
                
                    debugMsg(2, 'End Command: %s\n-----' % endcmd)
                    es.ServerVar('wcs_dice').set(random.randint(1,100))
                
                    if isOb:
                        if race in dictAlias:
                            for alias in dictAlias[race]:
                                if alias in endcmd:
                                    endcmd = endcmd.replace(alias, "%s_%s" % (alias, race) )
                        for command in endcmd.split(';'):
                            es.server.queuecmd(command)
                    else:
                        es.server.queuecmd(endcmd)
                        
    for delay in dict_commands['delay list']:
        gamethread.cancelDelayed(delay)
    dict_commands['delay list'] = []
    for player in dict_commands:
        if player != 'delay list':
            for delay in dict_commands[player]['delay list']:
                debugMsg(1, 'Canceling Player %s\'s delay %s'%(es.getplayername(player), delay))
                gamethread.cancelDelayed(delay)
            dict_commands[player]['delay list'] = []
    for userid in playerlib.getUseridList('#all'):
        playerkey = getSteam(userid)
        if playerkey['delayed race']:
            debugMsg(1, 'Player %s has a delayed race, changing to race %s now'%(es.getplayername(userid), playerkey['delayed race']) )
            playerkey['race'] = playerkey['delayed race']
            checkRace(userid, playerkey['race'])
            playerkey['delayed race'] = 0
            es.tell(userid, '#multi', text('race select change',{'race':playerkey['race']},playerlib.getPlayer(userid).get('lang') ) )
    str_path = open(es.getAddonPath('wcs') + '/UserSaves.db', 'w')
    cPickle.dump(_dict_WCSPlayers, str_path)
    str_path.close()
    debugMsg(1, 'End of Round End\n********************', writeTime=False)
    
def dod_round_win(ev):
    round_end(ev)
    
def teamplay_round_win(ev):
    round_end(ev)
    
def hostage_rescued(ev):
    """ Run when a hostage is rescued, give the relevant xp """
    if float(es.ServerVar('wcs_hostagexp')):
        Command(ev['userid']).GiveXp(float(es.ServerVar('wcs_hostagexp')), text('hostage xp',lang=playerlib.getPlayer(ev['userid']).get('lang')))
        
def bomb_defused(ev):
    """ Run when the bomb is defused, give the relevant xp """
    if float(es.ServerVar('wcs_bombdefusexp')):
        Command(ev['userid']).GiveXp(float(es.ServerVar('wcs_bombdefusexp')), text('defuse xp',lang=playerlib.getPlayer(ev['userid']).get('lang')))
        
def bomb_planted(ev):
    """ Run when the bomb is planted, give the relevant xp """
    if float(es.ServerVar('wcs_bombplantxp')):
        Command(ev['userid']).GiveXp(float(es.ServerVar('wcs_bombplantxp')), text('plant xp',lang=playerlib.getPlayer(ev['userid']).get('lang')))
        
def bomb_exploded(ev):
    """ Run when the bomb explodes, give the relevant xp """
    if float(es.ServerVar('wcs_bombexplodexp')):
        for userid in playerlib.getUseridList('#t,#alive'):
            Command(userid).GiveXp(float(es.ServerVar('wcs_bombexplodexp')), text('explode xp',lang=playerlib.getPlayer(userid).get('lang')))
            
def player_jump(ev):
    """ Runs when a player jumps; return the jump multiplier and change their velocity. """
    userid = int(ev['userid'])
    jump_multiplier = Command(userid).ReturnDict('jump multi')
    temp_multiplier = jump_multiplier - 1
    es.setplayerprop(userid, 'CBasePlayer.localdata.m_vecBaseVelocity', '%s,%s,%s' % tuple([es.getplayerprop(userid, 'CBasePlayer.localdata.m_vecVelocity[%s]' % x) * temp_multiplier for x in range(3)]))
    
def player_spawn(ev):
    """ Runs when a  player spawns. Runs the player_spawn_cmd for keygroup races, and also tells the player their XP. """
    debugMsg(1, '\n********************\nEvent: Player Spawn\n', writeTime=False)
    if not es.exists('key', 'WCSuserdata', ev['userid']):
        es.keycreate('WCSuserdata', ev['userid'])
    if not es.getplayerprop(ev['userid'], 'CBasePlayer.pl.deadflag'):
        playerkey = getSteam(ev['userid'])
        if not playerkey.has_key('race'):
            if ev['es_steamid'] != "BOT":
                debugMsg(0, '%s is trying to play without a race - Forcing race now.' % ev['es_username'])
                es.changeteam(ev['userid'],1)
                es.tell(ev['userid'], '#green', text('no race',lang=playerlib.getPlayer(userid).get('lang')))
                popuplib.send('wcs_racemenu_user%s' % ev['userid'], ev['userid'])
            else:
                pass
        elif playerkey['race'] not in race_list:
            defaultrace(ev['userid'], playerlib.uniqueid(int(ev['userid']),True))
        if float(es.ServerVar('wcs_announcexp')):
            debugMsg(1, 'Sending players rank to %s' % ev['es_username'])
            a = Command(ev['userid'])
            xp = a.GetXp()
            level = a.GetLevel()
            nextxp = a.GetNextXp()
            race = GetRace(ev['userid'])
            es.tell(ev['userid'],'#multi',text('showxp',{'level':level, 'race':race, 'currentxp':xp, 'neededxp':nextxp}, playerlib.getPlayer(ev['userid']).get('lang')))
        userid  = int(ev['userid'])
        race    = GetRace(userid)
        if keygroupraces.has_key(race):
            if 'player_spawn_cmd' in keygroupraces[race]['race']:
                spawncmd = str(keygroupraces[race]['race']['player_spawn_cmd'])
                if spawncmd != '0' and not isinstance(spawncmd, int):
                
                    debugMsg(1, '\n-----\nRunning the keygroup style race, event player_spawn_cmd')
                    debugMsg(2, 'Spawn Command: %s' % spawncmd)
                    debugMsg(1, '-----')
                    es.ServerVar('wcs_dice').set(random.randint(1,100))
                    
                    while spawncmd.find('event_var') > -1:
                        index    = spawncmd.find('event_var(')
                        event    = spawncmd[index + 10: spawncmd.find(')')]
                        spawncmd = spawncmd.replace('event_var(%s)' % event, ev[event])
                        
                    if isOb:
                        if race in dictAlias:
                            for alias in dictAlias[race]:
                                if alias in spawncmd:
                                    spawncmd = spawncmd.replace(alias, "%s_%s" % (alias, race) )
                        for command in spawncmd.split(';'):
                            es.server.queuecmd(command)
                    else:
                        es.server.queuecmd(spawncmd)
                        
            runKeygroupRace(userid, race, 'player_spawn')
        if not isModEvents:
            es.server.queuecmd('gravity %s 1.0'%ev['userid'])
            Command(userid).UpdateDict('DefaultGrav', 1)
            Command(userid).UpdateDict('CoolDownDeath', 0)
    debugMsg(1, 'End of Player Spawn\n********************', writeTime=False)

def popup_select(ev):
    """ A short event to play a sound whenever a popup is used within WCS. """
    es.playsound(ev['userid'], 'buttons/button24.wav', 0.5)

def set_variables():
    """ For all the old variables involved with keygroup style races, initialize them to 0 """
    for x in ('wcs_alive','wcs_exists','wcs_x','wcs_y','wcs_z','wcs_x1','wcs_y1','wcs_z1','wcs_x2','wcs_y2','wcs_z2','wcs_temp','wcs_userid','wcs_rand','wcs_health','wcs_dmg','wcs_health','wcs_armor','wcs_params', 'wcs_tmp', 'wcs_lang', 'wcs_team'):
        es.ServerVar(x).set(0)    

def UpdateHealth():
    """ This method runs every time the server updates the entities and sends a data package to the clients. (1/tickrate seconds) """
    for id in es.getUseridList():
        Command(id, False).key['__temp__health'] = es.getplayerprop(id, 'CBasePlayer.m_iHealth')
    gamethread.delayed(0.1, UpdateHealth)
        
def saveloop(time):
    """ This is the loop method that happens every X seconds, and saves the database """
    str_path = open(es.getAddonPath('wcs') + '/UserSaves.db', 'w')
    cPickle.dump(_dict_WCSPlayers, str_path)
    str_path.close()
    gamethread.delayed(time, saveloop, time)
    
#Handels all of our different wcs chat commands
def wcsShopInfo():
    """ Sends the shop info menu to the command user """
    popuplib.send('wcs_wcsshopinfo', es.getcmduserid())
    
def wcsRaceInfo():
    """ Send the raceinfomenu to the command user """
    popuplib.send('wcs_raceinfomenu_user%s'%es.getcmduserid(),es.getcmduserid())
    
def InfoSelect(userid, choice, popupid):
    """ A menu selection method from the menu. """
    if choice < 10:
        if choice == 9:
            popuplib.send('wcs_WCSMenu', userid)
        elif choice == 1:
            popuplib.send('wcs_general info', userid)
        elif choice == 2:
            es.sexec(userid,'say','raceinfo')
        elif choice == 3:
            es.sexec(userid,'say','shopinfo')
            
def MenuSelect(userid, choice, popupid):
    """ If the player selects a certain thing from the main WCS menu, force
        them to say the command (for lazy bums who CBA to type!) """
    if choice < 10:
        if choice == 1:
            es.sexec(userid,'say','shopmenu')
        elif choice == 2:
            es.sexec(userid,'say','showskills')
        elif choice == 3:
            es.sexec(userid,'say','resetskills')
        elif choice == 4:
            es.sexec(userid,'say','spendskills')
        elif choice == 5:
            es.sexec(userid,'say','changerace')
        elif choice == 6:
            popuplib.send('wcs_INFO', userid)
        elif choice == 7:
            es.sexec(userid,'say','playerinfo')
        elif choice == 8:
            es.sexec(userid,'say','showtop10')
        elif choice == 9:
            es.sexec(userid,'say','showrank')
            
def wcsPlayerInfo():
    """ Construct a player menu from the server. """
    userid = es.getcmduserid()
    players = popuplib.construct('wcs_TargetMenu', 'players', '#all')
    players.settitle('Chose a player')
    players.menuselectfb = TargetChosen
    players.send(userid)
    
def TargetChosen(user, choice, popupid):
    """ Get the info about another player's race skills """
    userid           = int(choice)
    race             = GetRace(userid)
    playerkey        = getSteam(userid)[race]
    skilllist        = Race(race).returnSkillList()
    skillsmenu       = popuplib.create('wcs_skillsmenu')
    player           = Command(userid)
    tokens           = {}
    tokens['name']   = es.getplayername(userid)
    tokens['race']   = race
    tokens['level']  = player.GetLevel()
    tokens['xp']     = player.GetXp()
    tokens['nextxp'] = player.GetNextXp()
    tokens['skills'] = wrapDictionaryItems(skilllist, playerkey, ':')
    addline(skillsmenu, returnAllLanguages('skillsmenu', tokens) )
    skillsmenu.send(user)
    
def configadmins():
    """ This is a function to obtain the latest admins into a global python list. """
    global wcs_admins
    wcs_admins = map(lambda x: x.strip(), str(es.ServerVar('wcs_admins')).split(','))
    
def configweapons():
    """ Make a function so we can gain the latest weapon bonus and weapon bonus xp values into
        global lists. """
    global wcs_weaponbonus
    global wcs_weaponbonusxp
    wcs_weaponbonus   = map(lambda x: x.strip(), str(es.ServerVar('wcs_weaponbonus')).split(','))
    wcs_weaponbonusxp = map(lambda x: x.strip(), str(es.ServerVar('wcs_weaponbonusxp')).split(','))
    
def wcsAdminGiveLevel():
    """ Exact same as Command().GiveLevel() except this is from the admin """
    userid  = es.getcmduserid()
    steamid = es.getplayersteamid(userid) # The only time you can use steamid!
    configadmins()
    if steamid in wcs_admins:
        steamid = target = es.getuserid(es.getargv(1))
        if not int(steamid): 
            steamid = target = es.getargv(1)
        else: 
            steamid = playerlib.uniqueid(steamid,True)
        if _dict_WCSPlayers.has_key(steamid):
            race = es.getargv(2)
            if race in race_list:
                amount = int(es.getargv(3))
                level = _dict_WCSPlayers[steamid][race]['level']
                if Race(race).returnRaceKey().has_key('max level'):
                    if not level + amount <= Race(race).returnRaceKey()['max level']:
                        amount = Race(race).returnRaceKey()['max level'] - level
                _dict_WCSPlayers[steamid][race]['level'] += amount
                _dict_WCSPlayers[steamid]['level'] += amount
                _dict_WCSPlayers[steamid][race]['unspent skills'] += amount
                
                es.event('initialize', 'wcs_levelup')
                es.event('setint',     'wcs_levelup', 'userid', target)
                es.event('setint',     'wcs_levelup', 'amount', amount)
                es.event('setint',     'wcs_levelup', 'oldlevel', level)
                es.event('setint',     'wcs_levelup', 'newlevel', _dict_WCSPlayers[steamid][race]['level'])
                es.event('setstring',  'wcs_levelup', 'race',   race )
                es.event('setstring',  'wcs_levelup', 'reason', "given by admin")
                es.event('fire',       'wcs_levelup')
                
                es.tell(userid,'#multi',text('admin give race level sucess',{'steamid':steamid,'race':race,'amount':amount},playerlib.getPlayer(userid).get('lang')))
            else:
                es.tell(userid,'#multi',text('admin give no race'),{'race':race},playerlib.getPlayer(userid).get('lang'))
        else:
            es.tell(userid,'#multi',text('admin give no steamid'),{'steamid':steamid},playerlib.getPlayer(userid).get('lang'))
    else:
        es.tell(userid,'#green',text('not admin',lang=playerlib.getPlayer(userid).get('lang')))
        
def wcsAdminGiveXp():
    """ Exact same as Command().GiveXP() except this is from the admin. """
    userid = es.getcmduserid()
    steamid = es.getplayersteamid(userid) # The only time you can use steamid!
    configadmins()
    if steamid in wcs_admins:
        steamid = target = es.getuserid(es.getargv(1))
        if not int(steamid): 
            steamid = taget = es.getargv(1)
        else: 
            steamid = playerlib.uniqueid(steamid,True)
        if _dict_WCSPlayers.has_key(steamid):
            race = es.getargv(2)
            if race in race_list:
                amount = int(es.getargv(3))
                xp = _dict_WCSPlayers[steamid][race]['xp']
                xp += amount
                level = _dict_WCSPlayers[steamid][race]['level']
                nextxp = (level - 1) * float(es.ServerVar('wcs_levelinterval')) + float(es.ServerVar('wcs_start_your_engines'))
                amount_of_levels = 0
                while xp >= nextxp:
                    amount_of_levels += 1
                    xp -= nextxp
                    nextxp += float(es.ServerVar('wcs_levelinterval'))
                if amount_of_levels:
                    if Race(race).returnRaceKey().has_key('max level'):
                        if not level + amount <= Race(race).returnRaceKey()['max level']:
                            amount_of_levels = Race(race).returnRaceKey()['max level'] - level
                    _dict_WCSPlayers[steamid][race]['unspent skills'] += amount_of_levels
                    _dict_WCSPlayers[steamid][race]['level'] += amount_of_levels
                    _dict_WCSPlayers[steamid]['level'] += amount_of_levels
                _dict_WCSPlayers[steamid][race]['xp'] = xp
                
                es.event('initialize', 'wcs_gainxp')
                es.event('setint',     'wcs_gainxp', 'userid',    target)
                es.event('setint',     'wcs_gainxp', 'amount',    amount)
                es.event('setint',     'wcs_gainxp', 'levels',    amount_of_levels)
                es.event('setint',     'wcs_gainxp', 'currentxp', xp)
                es.event('setstring',  'wcs_gainxp', 'reason',    "given by an admin")
                es.event('fire',       'wcs_gainxp')
                
                es.tell(userid,'#multi',text('admin give xp sucess',{'steamid':steamid,'race':race,'amount':amount},playerlib.getPlayer(userid).get('lang')))
            else:
                es.tell(userid,'#multi',text('admin give no race',{'race':race},playerlib.getPlayer(userid).get('lang')))
        else:
            es.tell(userid,'#multi',text('admin give no steamid',{'steamid':steamid},playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#green',text('not admin',lang=playerlib.getPlayer(userid).get('lang')))
    
def wcsAdminShowLevels():
    """ Get the steamID of the player they want to check out, and echo all their stats to their client console. """
    userid = es.getcmduserid()
    steamid = es.getplayersteamid(userid)
    configadmins()
    if steamid in wcs_admins:
        steamid = es.getuserid(es.getargv(1))
        if not int(steamid): 
            steamid = es.getargv(1)
        else: 
            steamid = playerlib.uniqueid(steamid,True)
        if _dict_WCSPlayers.has_key(steamid):
            es.cexec(userid,'echo','******************')
            es.cexec(userid,'echo','*** WCS SKILLS ***')
            es.cexec(userid,'echo','******************')
            es.cexec(userid,'echo','Steamid - %s'%steamid)
            es.cexec(userid,'echo','Total Level - %s'%_dict_WCSPlayers[steamid]['level'])
            es.cexec(userid,'echo','Current Race - %s'%_dict_WCSPlayers[steamid]['race'])
            es.cexec(userid,'echo',' ')
            for race in _dict_WCSPlayers[steamid]:
                if str(race) in race_list:
                    level = _dict_WCSPlayers[steamid][race]['level']
                    xp = _dict_WCSPlayers[steamid][race]['xp']
                    nextxp = (level - 1) * float(es.ServerVar('wcs_levelinterval')) + float(es.ServerVar('wcs_start_your_engines'))
                    sp = _dict_WCSPlayers[steamid][race]['unspent skills']
                    es.cexec(userid,'echo','Race: %s - Level: %s - XP: %s/%s - Skill Points: %s'%(race.center(max(map(lambda x: len(x), race_list))),level,xp,nextxp,sp))
            es.cexec(userid,'echo',' ')
            es.cexec(userid,'echo','******************')
            es.cexec(userid,'echo','**** FINISHED ****')
            es.cexec(userid,'echo','******************')
        else:
            es.tell(userid,'#multi',text('admin give no steamid',{'steamid':steamid},playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#green', text('not admin',lang=playerlib.getPlayer(userid).get('lang')))
    
def wcsAdmin():
    """ If the player is an admin, then send the admin menu to them; else, deny them and send a message """
    userid = es.getcmduserid()
    steamid = es.getplayersteamid(userid) # The only time you can use steamid instead of uniqueid()!
    configadmins()
    if steamid in wcs_admins:
        popuplib.send('wcs_wcsadminmenu',userid)
    else:
        es.tell(userid,'#green',text('not admin', lang = playerlib.getPlayer(userid).get('lang') ) )
        
def wcsChangeRace():
    """ A command to send the race menu to the player """
    userid = es.getcmduserid()
    popuplib.send('wcs_racemenu_user%s'%userid, userid)
    
def wcsSpendSkills():
    """ A command to send the spendskills menu to the player """
    userid = es.getcmduserid()
    spendskills(userid, True)
    
def wcsResetSkills():
    """ Reset all the players skills and return their skills back to unspent skills """
    userid = es.getcmduserid()
    dead = playerlib.getPlayer(userid).get('isdead')
    race = GetRace(userid)
    playerkey = getSteam(userid)[race]
    skilllist = Race(race).returnSkillList()
    if dead:
        for skill in skilllist:
            playerkey['unspent skills'] += playerkey[skill]
            playerkey[skill] = 0
        es.tell(userid, '#multi', text('resetskills',{'unspent':playerkey['unspent skills']},playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid, '#multi', text('reset alive',lang=playerlib.getPlayer(userid).get('lang')))
        
def wcsShopMenu():
    """ Send the shopmenu to the command user """
    userid = es.getcmduserid()
    shopmenu = popuplib.create('wcs_shopmenu')
    addline(shopmenu, returnAllLanguages('wcs shopmenu', {'cash':Command(userid).GetCash()}))
    shopmenu.submenu(1,'wcs_enhancementmenu')
    shopmenu.submenu(2,'wcs_powerupmenu')
    shopmenu.submenu(3,'wcs_attackmenu')
    shopmenu.submenu(4,'wcs_defensemenu')
    shopmenu.submenu(5,'wcs_specialmenu')
    shopmenu.send(userid)
    
def wcsShowSkills():
    """ A command to show the skills of a certain player of their current race. """
    userid           = es.getcmduserid()
    race             = GetRace(userid)
    playerkey        = getSteam(userid)[race]
    skilllist        = Race(race).returnSkillList()
    skillsmenu       = popuplib.create('wcs_skillsmenu')
    player           = Command(userid)
    tokens           = {}
    tokens['name']   = es.getplayername(userid)
    tokens['race']   = race
    tokens['level']  = player.GetLevel()
    tokens['xp']     = player.GetXp()
    tokens['nextxp'] = player.GetNextXp()
    tokens['skills'] = wrapDictionaryItems(skilllist, playerkey, ':')
    addline(skillsmenu, returnAllLanguages('skillsmenu', tokens) )
    skillsmenu.send(userid)
    
def wcsShowRank():
    """ A wrapper to message the rank to the server. """
    userid = es.getcmduserid()
    user = es.getargv(1)
    if user:
        user = es.getuserid(user)
        if user:
            SendRank(user)
    else:
        SendRank(userid)
        
def Top10():
    """ Sort the dictionary according to the players total level. Get the
        indexes of the top10 players, and retrieve info about them. Add
        their attributes to a popup, and send to the user. """
    userid = es.getcmduserid()
    a = sorted(_dict_WCSPlayers,WcsSort)
    index = 0
    top5 = popuplib.create('wcs_top5')
    format = ""
    while index < 5:
        try:
            steam     = a[index]
            index    += 1
            d         = _dict_WCSPlayers
            name      = d[steam]['name']
            if not name: 
                name  = 'Unnamed'
            level     = d[steam]['level']
            race      = d[steam]['race']
            if len(name) > 16:
                name  = name[0:14]+'...'
            format   += '->%s. %s - Level: %s Race: %s\n'%(index, name, level, race)
        except IndexError:
            index    += 1
            format   += " \n"
    bottom            = ""
    if len(a) > 5: 
        bottom       += "9. Rank 6 - %s\n" % (min(10, len(a) ) )
    bottom           += '0. Cancel'
    tokens            = {}
    tokens['minrank'] = min(5, len(a))
    tokens['ranks']   = format
    tokens['bottom']  = bottom
    addline(top5, returnAllLanguages('top5', tokens))
    if len(a) > 5: 
        top5.submenu(9,'wcs_top10')
        top10         = popuplib.create('wcs_top10')
        format        = ""
        while index < 10:
            try:
                steam = a[index]
                index += 1
                d     = _dict_WCSPlayers
                name  = d[steam]['name']
                if not name: 
                    name = 'Unnamed'
                level = d[steam]['level']
                race  = d[steam]['race']
                if len(name) > 16:
                    name = name[0:14]+'...'
                format += '->%s. %s - Level: %s Race: %s\n'%(index, name, level, race)
            except IndexError:
                index  += 1
                format += ' \n'
        top10.submenu(8,'wcs_top5')
        tokens            = {}
        tokens['minrank'] = min(10, len(a))
        tokens['ranks']   = format
        addline(top10, returnAllLanguages('top10', tokens))
    top5.send(userid)
    
def wcsHelp():
    """ Send the help menu to the player """
    userid = int(es.getcmduserid())
    popuplib.send('wcs_wcshelp',userid)
     
def wcsMenu():
    """ Send the main WCS menu to the player """
    userid = es.getcmduserid()
    popuplib.send('wcs_WCSMenu',userid)
    
def wcsShowXp():
    """ Show the current xp of the player, and tell them how long they've got until they level up """
    userid = es.getcmduserid()
    race = GetRace(userid)
    playerkey = getSteam(userid)[race]
    es.tell(userid, '#multi', text('showxp',{'race':race, 'level':playerkey['level'], 'currentxp':playerkey['xp'], 'neededxp':float(es.ServerVar('wcs_start_your_engines'))+((playerkey['level']-1)*float(es.ServerVar('wcs_levelinterval')))},playerlib.getPlayer(userid).get('lang')))
    

def wcs_getlanguage():
    """ 
        Short function to obtain a multi-lingual text for keygroup style races.
        Syntax: wcs_getlanguage <variable> <languge id> [userid/language] 
    """
    debugMsg(1, '\n----------------------------------------\nObtaining multi-lingual text for keygroup style race')
    userid = None
    lang   = None
    text   = "Invalid keygroup id text!!!"
    if es.getargc() == 4:
        debugMsg(1, 'Arg count was 4, so there was a language or userid passed... testing for userid')
        userid = es.getargv(3)
        if userid not in map(str, es.getUseridList()):
            debugMsg(1, 'The arg was not a userid, so we will use the language: %s' % userid)
            lang = userid
        else:
            lang = playerlib.getPlayer(userid).get("lang")
            debugMsg(1, 'It was a player, so we will use the player\'s lanugage: %s' % lang)
    variable = es.getargv(1)
    textid   = es.getargv(2)
    debugMsg(1, 'Attempting to find the text id "%s" and store it in variable "%s"' % (textid, variable) )
    if not lang:
        debugMsg(1, 'No language currently assigned, so we will use the wcs_language variable...')
        lang = str(es.ServerVar('wcs_language'))
        debugMsg(1, 'The language equals %s' % lang)
        if lang == '0':
            debugMsg(1, 'No variable default set, so we will use "en"')
            lang = "en"
    if lang not in language_keygroup:
        debugMsg(0, 'There is no language "%s" inside the language keygroup' % lang)
        es.set(variable, "")
        return
    if textid in language_keygroup[lang]:
        text = language_keygroup[lang][textid]
        debugMsg(1, 'We finally have the correct text: %s' % text)
    else:
        debugMsg(1, 'There is no textid "%s" inside the language "%s"' % (textid, lang) )
        if lang <> "en":
            debugMsg(1, 'Attempting to run the command again but default the language to "en"')
            es.server.cmd('wcs_getlanguage %s %s en' % (variable, textid) )
            return
    es.set(variable, text)
    debugMsg(1, 'Out of the function wcs_getlanguage\n----------------------------------------\n')

def wcs_setfx():
    """
        Runs our console command.
        
        wcs_setfx <TYPE> <USERID> <OPERATOR> <PARAMETER> <TIME>
        supported types are: 
        freeze speed god invis(0-255) invisp(in %) health armor gravity disguiser 1stclip 2ndclip longjump 
    """
    type = str(es.getargv(1))
    if type in ["freeze", "speed", "god", "invis", "invisp", "health", "armor", "gravity", "disguiser", "1stclip", "2ndclip", "longjump"]:
        userid = int(es.getargv(2))
        if not es.getplayerprop(userid, "CBasePlayer.pl.deadflag"):
            operator = str(es.getargv(3))
            if operator not in ["+", "-", "="]:
                operator = '='
            param = str(es.getargv(4))
            time  = str(es.getargv(5))
            if time:
                time = float(time)
                
            if type == 'freeze':
                """ Freeze a player for x seconds """
                if time:
                    Command(userid).Freeze(time)
                else:
                    Command(userid).Freeze()
                    
            elif type == 'longjump':
                """ Change how far the player can jump for x seconds """
                if time:
                    Command(userid).Delayed(time, Command(userid).UpdateDict, ('jump multi', Command(userid).ReturnDict('jump multi') ) )
                if operator == '=':
                    Command(userid).UpdateDict('jump multi', param)
                elif operator == '+':
                    Command(userid).UpdateDict('jump multi', Command(userid).ReturnDict('jump multi') + param)
                elif operator == '-':
                    Command(userid).UpdateDict('jump multi', Command(userid).ReturnDict('jump multi') - float(param) )
                    
            elif type == 'gravity':
                """ Change a players gravity for a certain amount of time. """
                if time:
                    Command(userid).Delayed(time, Command(userid).SetGravity, Command(userid).ReturnDict('gravity') )
                if operator == '=':
                    Command(userid).SetGravity(param)
                elif operator == '+':
                    Command(userid).ChangeGravity(param)
                elif operator == '-':
                    Command(userid).ChangeGravity(-1 * float(param) )
                    
            elif type == 'armor':
                """ Change a players armor for a certain amount of time. """
                if operator == '=':
                    Command(userid).Armor(param)
                elif operator == '+':
                    Command(userid).ArmorAdd(param)
                elif operator == '-':
                    Command(userid).ArmorAdd(-1 * float(param) )
                    
            elif type == 'health':
                """ Change a players health for a certain amount of time. """
                if time:
                    Command(userid).Delayed(time, Command(userid).Health, Command(userid).ReturnDict('maxhealth') )
                if operator == '=':
                    Command(userid).Health(param)
                elif operator == '+':
                    Command(userid).HealthAdd(param)
                elif operator == '-':
                    Command(userid).HealthAdd(-1 * float(param) )
                    
            elif type == 'invisp':
                """ Change the players alpha as a percentage """
                es.server.queuecmd('wcs_setfx invis %s %s %s %s'%(userid, operator, int(param) * 2.55, time) )
                
            elif type == 'speed':
                """ Increase a players speed for x seconds """
                if time:
                    Command(userid).Delayed(time, Command(userid).Speed, Command(userid).ReturnDict('Speed') )
                    
                if operator == '=':
                    Command(userid).Speed(param)
                    
                elif operator == '+':
                    Command(userid).SpeedAdd(param)
                    
                elif operator == '-':
                    Command(userid).SpeedAdd(-1*float(param))
                    
            elif type == 'god':
                """ Turn a player into god for x seconds """
                if time:
                    Command(userid).God(time)
                else:
                    Command(userid).God()
                    
            elif type == 'invis':
                """ Change the players alpha """
                if time:
                    Command(userid).Delayed(time, Command(userid).Color, (None, 255, 255, 255, Command(userid).ReturnDict('alpha') ) )
                if operator == '=':
                    Command(userid).Color(alpha = param)
                elif operator == '+':
                    Command(userid).Color(alpha = int(param) + Command(userid).ReturnDict('alpha'))
                elif operator == '-':
                    Command(userid).Color(alpha = Command(userid).ReturnDict('alpha') - int(param))
                    
    else:
        debugMsg(0, 'WCS Error: WCS Does not currently support wcs_setfx %s !'%type)
        
def wcs_removefx():
    """
        Runs our console command. This is only for backwards compatibility, use
        wcs_setfx in future.
        
        wcs_removefx <type> <userid>
        supported types are: 
            freeze speed god 
    """
    fxtype = es.getargv(1)
    userid = es.getargv(2)
    
    if fxtype == "freeze":
        Command(userid).UnFreeze()
        
    elif fxtype == "speed":
        Command(userid).Speed(1.0)
    
    elif fxtype == "god":
        """ 
            Not the best way to do it but still...
            Maybe try setting player's movement
            prop to 2 (walking). 
        """
        Command(userid).UnGod()
    else:
        debugMsg(0, 'WCS Error: WCS Does not currently support wcs_removefx: %s !'%type)
        
def wcs_dealdamage():
    """ A wrapper from Keygroup races to use the damage wrapper. """
    Command(es.getargv(2) ).Damage( int( float( es.getargv(3) ) ), '32', es.getargv(1))
    
temp_load = []
def wcscommand():
    """ Controls the WCS command usage (console command). Get the arg, and do the following command. """
    arg1 = es.getargv(1).lower()
    if arg1 == 'itemload':
        """ Load an ESP item into memory. """
        item = es.getargv(2)
        if os.path.isfile(es.getAddonPath('wcs') + '/shopmenu/%s/%s.py' % (item, item) ) or os.path.isfile(es.getAddonPath('wcs') + '/shopmenu/%s/es_%s.txt' %  (item, item) ):
            es.server.queuecmd('es_xload "wcs/shopmenu/%s"'%item)
        else:
            debugMsg(0, 'WCS Error: Cannot find the %s item file! Please be sure it is in the ..addons/eventscripts/wcs/shopmenu/%s folder!'%(item, item))
            
    elif arg1 == 'loadallraces' or arg1 == 'loadall':
        """ For every race in the race folder, load it into memory.  """
        for race in os.listdir(race_folder):
            if os.path.isdir(race_folder + '/' + race):
                es.server.queuecmd('wcs load "%s"' % race)
            
    elif arg1 == 'unloadallraces' or arg1 == 'unloadall':
        """ For every loaded race, unload it from memory """
        for race in race_list:
            if race in race_list:
                race_list.remove(race)
            if racecheck(race) == 'script':
                es.server.cmd('esnq es_xunload "wcs/races/%s"' % race)
            else:
                es.server.cmd('es_xkeygroupdelete %s'%(race))
                del keygroupraces[race]
            del _dict_races_instances[race]
        buildRaceMenu()
            
    elif arg1 == 'load':
        """ Load a race into memory... Get whether it's a keygroup race, ESP or ESS race
            add it to the list, and update them all etc etc yada yada """
        race  = es.getargv(2)
        check = racecheck(race)
        if check:
            gamethread.cancelDelayed('reload')
            gamethread.cancelDelayed('loadRaces')
            temp_load.append(race)
            gamethread.delayedname(1, 'reload', buildRaceMenu)
            gamethread.delayedname(0.1, 'loadRaces', loadRaces)
            
    elif arg1 == 'unload':
        """ Unload a race from memory """
        race  = es.getargv(2)
        check = racecheck(race)
        if check:
            race_list.remove(race)
            if check == 'script':
                debugMsg(1, 'Attempting to unload race %s' % race)
                es.server.queuecmd('esnq es_xunload "wcs/races/%s"'%race)
            elif check == 'keygroup':
                debugMsg(1, 'Attempting to unload keygroup race %s' % race)
                es.server.queuecmd('es_xkeygroupdelete %s'%(race))
                del keygroupraces[race]
            buildRaceMenu()
            del _dict_races_instances[race]
            
    elif arg1 == 'reload':
        """ Reload a race. (unload then load again) """
        es.server.queuecmd('wcs unload %s'%es.getargv(2))
        es.server.queuecmd('wcs load %s'%es.getargv(2))
        
    elif arg1 == 'install':
        """ Installs a wcs from ESAM... It must be an approved addon. """
        es.server.queuecmd('es_xinstall %s'%es.getargv(2))
        es.server.queuecmd('wcs load %s'%es.getargv(2))
        loader = open('%s/WCSRaceLoader.cfg'%es.getAddonPath('wcs'), 'a')
        loader.writelines('\nwcs load %s'%str(es.getargv(2)))
        loader.close()
        
        """ Start the ESS Wrappers... All getargv's return strings, convert them... You can't convert a floatstring... e.g.  '1.0245' to an int;
        first convert to a float, then an int... e.g. damage command.. int(float(es.getargv(#))) """
        
    elif arg1 == 'weaponbonus':
        """ wcs weaponbonus <weapon> <bonus xp> """
        es.ServerVar('wcs_weaponbonus').set(str(es.ServerVar('wcs_weaponbonus') + ',' + es.getargv(1) ) )
        es.ServerVar('wcs_weaponbonusxp').set(str(es.ServerVar('wcs_weaponbonusxp') + ',' + es.getargv(2) ) )
        
    elif arg1 == 'heal':
        """ wcs Heal <userid> <amount>  """
        Command(es.getargv(2)).Heal(int(float(es.getargv(3))))
        
    elif arg1 == 'savelife':
        """ wcs SaveLife <userid> <amount>  """
        Command(es.getargv(2)).SaveLife(int(float(es.getargv(3))))
        
    elif arg1 == 'damage':
        """ wcs damage <userid> <amount> [type] [attacker] """
        Command(es.getargv(2)).Damage(int(float(es.getargv(3))),'%s'%'32' if not es.getargv(4) else es.getargv(4),es.getargv(5))
        
    elif arg1 == 'getlevel':
        """ wcs GetLevel <userid> <race name> <skill name> """
        es.ServerVar(es.getargv(2)).set(GetLevel(es.getargv(3),es.getargv(4),es.getargv(5)))
        
    elif arg1 == 'setcooldown':
        """ wcs SetCoolDown <userid> <skill> <time> """
        Command(es.getargv(2)).SetCoolDown(es.getargv(3),int(es.getargv(4)))
        
    elif arg1 == 'getcooldown':
        """ wcs GetCoolDown <variable> <userid> <skill> """
        es.ServerVar(es.getargv(2)).set(Command(es.getargv(3)).GetCoolDown(es.getargv(4)))
        
    elif arg1 == 'updatedict':
        """ wcs UpdateDict <userid> <key> <key-value> """
        Command(es.getargv(2)).UpdateDict(es.getargv(3),int(es.getargv(4)))
        
    elif arg1 == 'returndict':
        """ wcs ReturnDict <variable> <userid> <key> """
        es.ServerVar(es.getargv(2)).set(Command(es.getargv(3)).ReturnDict(es.getargv(4)))
        
    elif arg1 == 'moddict':
        """ wcs ModDict <userid> <key> <value to +/-> """
        Command(es.getargv(2)).ModDict(es.getargv(3),float(es.getargv(4)))
        
    elif arg1 == 'regen':
        """ wcs Regen <userid> <amount to delay> <amount to add each loop> """
        Command(es.getargv(2)).Regen(int(es.getargv(3)),int(es.getargv(4)))
        
    elif arg1 == 'color':
        """ wcs Color [Color] [red] [green] [blue] [alpha] """
        color = es.getargv(3)
        if color in colors:
            Command(es.getargv(2)).Color(es.getargv(3),int(float('%s'%'255' if not es.getargv(4) else es.getargv(4))))
        else:
            Command(es.getargv(2)).Color(None,int(es.getargv(3)),int(es.getargv(4)),int(es.getargv(5)),int(float('%s'%'255' if not es.getargv(6) else es.getargv(6))))
            
    elif arg1 == 'fade':
        """ wcs Fade <userid> <fade-to alpha> <time to fade> """
        Command(es.getargv(2)).Fade(int(float(es.getargv(3))),int(es.getargv(4)))
        
    elif arg1 == 'freeze':
        """ wcs Freeze <userid> <time> """
        Command(es.getargv(2)).Freeze(float(es.getargv(3)))
        
    elif arg1 == 'god':
        """ wcs God <userid> <time> """
        Command(es.getargv(2)).God(float(es.getargv(3)))
        
    elif arg1 == 'blind':
        """ wcs Blind <userid> <time> [alpha] """
        Command(es.getargv(2)).Blind(es.getargv(3),float(es.getargv(4)),int(float('%s'%'255' if not es.getargv(5) else es.getargv(5))))
        
    elif arg1 == 'changegravity':
        """ wcs ChangeGravity <userid> <amount to +/-> """
        Command(es.getargv(2)).ChangeGravity(float(es.getargv(3)))
        
    elif arg1 == 'setgravity':
        """ wcs SetGravity <userid> <amount> """
        Command(es.getargv(2)).SetGravity(float(es.getargv(3)))
        
    elif arg1 == 'speed':
        """ wcs Speed <userid> <amount> """
        Command(es.getargv(2)).Speed(float(es.getargv(3)))
        
    elif arg1 == 'speedadd':
        """ wcs SpeedAdd <userid> <amount to +/-> """
        Command(es.getargv(2)).SpeedAdd(float(es.getargv(3)))
        
    elif arg1 == 'heal':
        """ wcs Heal <userid> <amount> """
        Command(es.getargv(2)).Heal(int(es.getargv(3)))
        
    elif arg1 == 'health':
        """ wcs Health <userid> <amount> """
        Command(es.getargv(2)).Health(int(es.getargv(3)))
        
    elif arg1 == 'healthadd':
        """ wcs HealthAdd <userid> <amount to +/-> """
        Command(es.getargv(2)).HealthAdd(int(es.getargv(3)))
        
    elif arg1 == 'armor':
        """ wcs Armor <userid> <amount> """
        Command(es.getargv(2)).Armor(int(es.getargv(3)))
        
    elif arg1 == 'armoradd':
        """ wcs ArmorAdd <userid> <amount> """
        Command(es.getargv(2)).ArmorAdd(int(es.getargv(3)))
        
    elif arg1 == 'clip':
        """ wcs Clip <userid> <amount> """
        Command(es.getargv(2)).Clip(es.getargv(3),int(es.getargv(4)))
        
    elif arg1 == 'clipadd':
        """ wcs ClipAdd <userid> <amount to +/-> """
        Command(es.getargv(2)).ClipAdd(es.getargv(3),int(es.getargv(4)))
        
    elif arg1 == 'ammo':
        """ wcs Ammo <userid> <amount> """
        Command(es.getargv(2)).Ammo(es.getargv(3),int(es.getargv(4)))
        
    elif arg1 == 'ammoadd': 
        """ wcs AmmoAdd <userid> <amount to +/-> """
        Command(es.getargv(2)).AmmoAdd(es.getargv(3),int(es.getargv(4)))
        
    elif arg1 == 'drain':
        """ wcs Drain <userid> <damage each loop> <delay between loops> <total time to drain> """
        Command(es.getargv(2)).Drain(int(es.getargv(3)),float(es.getargv(4)),float(es.getargv(5)))
        
    elif arg1 == 'drop':
        """ wcs Drop <userid> """
        Command(es.getargv(2)).Drop()
        
    elif arg1 == 'model':
        """ wcs Model <userid> <model path> """
        Command(es.getargv(2)).Model(es.getargv(3),es.getargv(4))
        
    elif arg1 == 'arearegen':
        """ wcs AreaRegen <userid> <team to heal> <distance> <amount each loop> <delay each loop> """
        Command(es.getargv(2)).AreaRegen(es.getargv(3),float(es.getargv(4)),int(es.getargv(5)),float(es.getargv(6)))
        
    elif arg1 == 'areadamage':
        """ wcs AreaDamage <userid> <team to damage> <distance to damage> <damage amount> [attacker] """
        Command(es.getargv(2)).AreaDamage(es.getargv(3),float(es.getargv(4)),int(es.getargv(5)),es.getargv(6))
        
    elif arg1 == 'givexp':
        """ wcs GiveXp <userid> <amount> ["reason"] """
        Command(es.getargv(2)).GiveXp(int(es.getargv(3)),'%s'%'' if not es.getargv(4) else es.getargv(4))
        
    elif arg1 == 'givelevel':
        """ wcs GiveLevel <userid> <amount> ["reason"] """
        Command(es.getargv(2)).GiveLevel(int(es.getargv(3)),'%s'%'' if not es.getargv(4) else es.getargv(4))
        
    elif arg1 == 'getxp':
        """ wcs GetXp <variable> <userid> """
        es.ServerVar(es.getargv(2)).set(Command(es.getargv(3).GetXp()))
        
    elif arg1 == 'getracelevel':
        """ wcs GetRaceLevel <variable> <userid> """
        es.ServerVar(es.getargv(2)).set(Command(es.getargv(3)).GetLevel())
        
    elif arg1 == 'getnextxp':
        """ wcs GetNextXp <variable> <userid> """
        es.ServerVar(es.getargv(2)).set(Command(es.getargv(3)).GetNextXp())
        
    elif arg1 == 'blockabil':
        """ wcs BlockAbil <userid> <time> """
        Command(es.getargv(2)).BlockAbil(float(es.getargv(3)))
        
    elif arg1 == 'blockulti':
        """ wcs BlockUlti <userid> <time> """
        Command(es.getargv(2)).BlockUlti(float(es.getargv(3)))
        
    elif arg1 == 'race':
        name = es.getargv(2)
        arg3 = es.getargv(3).lower()
        if arg3 == 'registerskill':
            """ wcs Race <race name> registerSkill <skill name> <maximum level> <level interval> <"description"> """
            Race(name).registerSkill(es.getargv(4),int(es.getargv(5)),int(es.getargv(6)),es.getargv(7),es.getargv(8),es.getargv(9))
            
        elif arg3 == 'registerultimate':
            """ wcs Race <race name> registerUltimate <skill name> <level needed> <maximum level> <level interval> <"description"> """
            Race(name).registerUltimate(es.getargv(4),int(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)),es.getargv(8),es.getargv(9),es.getargv(10))
            
        elif arg3 == 'registerteam':
            """ wcs Race <race name> registerTeam <team number/name> """
            Race(name).registerTeam(es.getargv(4))
            
        elif arg3 == 'registerweaponrestriction':
            """ wcs Race <race name> registerWeaponRestriction <'allow/block only'> <"weapon1,weapon2,weapon3,weapon4"> """
            Race(name).registerWeaponRestriction(es.getargv(4),es.getargv(5).split(','))
            
        elif arg3 == 'registerminlevel':
            """ wcs Race <race name> registerMinLevel <level> """
            Race(name).registerMinLevel(int(es.getargv(4)))
            
        elif arg3 == 'registermaxlevel':
            """ wcs Race <race name> registerMaxLevel <level> """
            Race(name).registerMaxLevel(int(es.getargv(5)))
            
        elif arg3 == 'registersteamid':
            """ wcs Race <race name> registerSteamid <steamid1,steamid2,steamid3> """
            Race(name).registerSteamid(es.getargv(4).split(';'))
            
        elif arg3 == 'registerteamlimit':
            """ wcs Race <race name> registerTeamLimit <amount> """
            Race(name).registerTeamLimit(int(es.getargv(4)))
            
    elif arg1 == 'beam1':
        """ wcs Beam1 <start userid> <end userid> <life> <red> <green> <blue> """
        effect.Beam1(es.getargv(2),es.getargv(3),float(es.getargv(4)),int(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)))
        
    elif arg1 == 'beam2':
        """ wcs Beam2 <start userid> <end userid> <life> <red> <green> <blue> """
        effect.Beam2(es.getargv(2),es.getargv(3),float(es.getargv(4)),int(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)))
        
    elif arg1 == 'beam3':
        """ wcs Beam3 <start x y z> <end userid1,enduserid2,enduserid3> <life> <red> <green> <blue> """
        effect.Beam3(float(es.getargv(2)),float(es.getargv(3)),float(es.getargv(4)),es.getargv(5).split(','),float(es.getargv(6)),int(es.getargv(7)),int(es.getargv(8)),int(es.getargv(9)))
        
    elif arg1 == 'beam4':
        """ wcs Beam4 <start userid> <end userid> <life> <red> <green> <blue> """
        effect.Beam4(es.getargv(2),es.getargv(3),float(es.getargv(4)),int(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)))
        
    elif arg1 == 'ring1':
        """ wcs Ring1 <userid> <end distance> <life> <red> <green> <blue> """
        effect.Ring1(es.getargv(2),int(es.getargv(3)),float(es.getargv(4)),int(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)))
        
    elif arg1 == 'ring2':
        """ wcs Ring2 <userid> <size of ring> <life> <red> <green> <blue> """ 
        effect.Ring2(es.getargv(2),int(es.getargv(3)),float(es.getargv(4)),int(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)))
        
    elif arg1 == 'ring3':
        """ wcs Ring3 <userid> <end distance> <life> <red> <green> <blue> """
        effect.Ring3(es.getargv(2),int(es.getargv(3)),float(es.getargv(4)),int(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)))
        
    elif arg1 == 'ring4':
        """ wcs Ring4 <userid> <start distance> <end distance> <life> <size> <spread> <red> <green> <blue> """ 
        effect.Ring4(es.getargv(2),int(es.getargv(3)),int(es.getargv(4)),float(es.getargv(5)),int(es.getargv(6)),int(es.getargv(7)),int(es.getargv(8)),int(es.getargv(9)),int(es.getargv(10)))
        
    elif arg1 == 'misc1':
        """ wcs Misc1 <userid> <life> """
        effect.Misc1(es.getargv(2),float(es.getargv(3)))
        
    elif arg1 == 'misc2':
        """ wcs Misc2 <userid> <life> <size> """
        effect.Misc2(es.getargv(2),float(es.getargv(3)),float(es.getargv(4)))
        
    elif arg1 == 'misc3':
        """ wcs Misc3 <userid> <life> <size> """
        effect.Misc3(es.getargv(2),float(es.getargv(3)),float(es.getargv(4)))
        
    elif arg1 == 'misc4':
        """ wcs Misc4 <userid> <life> <size> """
        effect.Misc4(es.getargv(2),float(es.getargv(3)),float(es.getargv(4)))
        
    elif arg1 == 'misc5':
        """ wcs Misc5 <userid> <life> <size> """
        effect.Misc5(es.getargv(2),float(es.getargv(3)),float(es.getargv(4)))
        
    elif arg1 == 'misc6':
        """ wcs Misc6 <userid> <life> <size> """
        effect.Misc6(es.getargv(2),float(es.getargv(3)),float(es.getargv(4)))
        
    elif arg1 == 'follow':
        """ wcs Follow <userid> <red> <green> <blue> """
        effect.Follow(es.getargv(2),int(es.getargv(3)),int(es.getargv(4)),int(es.getargv(5)))
        
    elif arg1 == 'smoke':
        """ wcs Smoke <userid> """
        effect.Smoke(es.getargv(3))
    else:
        debugMsg(0,'Sorry but %s is not a valid WC:Source command.'%arg1)
        
if isOb:
    dictAlias = {}
    
    def aliasCommand(shortName, alias, race):
        """ A function to control alias' in the orange box without the source engine
            because they FAIL! """
        if not es.exists('command', shortName):
            if not race in dictAlias:
                dictAlias[race] = {} 
            dictAlias[race][shortName] = alias.split(';')
            es.regcmd('%s_%s' % (shortName, race), 'wcs/runAlias', 'An alias for keygroup races')
        
    def runAlias():
        command = es.getargv(0).split('_')
        race    = command.pop(-1)
        while race not in dictAlias:
            if len(command):
                race = command.pop(-1) + '_' + race
            else:
                raise ValueError, "Incorrect alias for the alias command %s" % command
        command = '_'.join(command)
        debugMsg(2, 'Running alias %s with race %s' % (command, race) )
        if command in dictAlias[race]:
            for tempCommand in dictAlias[race][command]:
                es.server.cmd(tempCommand)
    
                
currentDelay = 0.05 
def loadRaces():
    """ Make it load each race 1 by 1 in 0.1 second intervals so it doesn't
        crash the server with annoying memory errors etc etc... """
    global currentDelay
    if len(temp_load):
        race  = temp_load.pop(0)
        if race not in race_list:
            check = racecheck(race)
            if check == 'keygroup':
                #if not isOb:
                gamethread.cancelDelayed('reload_keygroup')
                strFile = race_folder + '/%(race)s/es_%(race)s_db.txt' % {'race':race}
                if os.path.isfile(strFile):
                    keygroupraces[race] = keyvalues.KeyValues(filename = strFile)
                    for i in keygroupraces[race]['race']:
                        i = str(i)
                        if 'racealias' in i:
                            if isOb:
                                aliasCommand(i, keygroupraces[race]['race'][i], race)
                            else:
                                es.delayed(currentDelay, 'es alias %s "%s"'%(i, keygroupraces[race]['race'][i]))
                        elif i == 'preloadcmd' and int(keygroupraces[race]['race'][i]):
                            es.server.queuecmd(i)
                        if i in ('required_level', 'teamlimit', 'maximum_level'):
                            if int(keygroupraces[race]['race'][i]):
                                if i == 'required_level':
                                    Race(race).registerMinLevel(int(keygroupraces[race]['race'][i]))
                                elif i == 'teamlimit':
                                    Race(race).registerTeamLimit(int(keygroupraces[race]['race'][i]))
                                elif i == 'maximum_level':
                                    Race(race).registerMaxLevel(int(keygroupraces[race]['race'][i]))
                    number     = int(keygroupraces[race]['race']['numberofskills'])
                    levels     = int(keygroupraces[race]['race']['numberoflevels'])
                    skillnames = str(keygroupraces[race]['race']['skillnames']).split('|')
                    skilldes   = str(keygroupraces[race]['race']['skilldescr']).split('|')
                    current    = 1
                    good       = True
                    while current <= number:
                        if current != number:
                            if current <= len(skillnames) and current <= len(skilldes):
                                currentDelay += 0.5
                                gamethread.delayed(currentDelay, Race(race).registerSkill, (skillnames[current-1], levels, 1, skilldes[current-1]))
                            else:
                                debugMsg(0, 'WCS ERROR - The keygroup race %s has incorrect \'numberofskills\' and \'numberoflevels\'' % race)
                                good = False
                        else:
                            if current <= len(skillnames) and current <= len(skilldes):
                                currentDelay += 0.5
                                gamethread.delayed(currentDelay, Race(race).registerUltimate, (skillnames[current-1], 8, levels, 1, skilldes[current-1]) )
                            else:
                                debugMsg(0, 'WCS ERROR - The keygroup race %s has incorrect \'numberofskills\' and \'numberoflevels\'' % race)
                                good = False
                        current += 1
                    gamethread.delayedname(1, 'reload_keygroup', es.reload, ('wcs/WCSultimates'))
                    gamethread.delayedname(1, 'reload_keygroup', es.reload, ('wcs/WCSskills'))
                    if good:
                        race_list.append(race)
                        if not isOb:
                            print "Loaded:races.%(race)s.%(race)s" % {'race':race}
                        else:
                            es.dbgmsg(0, 'Loaded:races.%(race)s.%(race)s' % {'race':race} )
                else:
                    debugMsg(0, 'Sorry Keygroup races don\'t work on the Orange Box engine.')
            elif check == 'script':
                es.load("wcs/races/%s"%race)
                race_list.append(race)
        gamethread.delayedname(0.1, 'loadRaces', loadRaces)
        
def racecheck(race):
    """ Checks to see if the given race name has a .py file in the races sub folder """
    if os.path.isfile(race_folder + '/%s/%s.py'%(race, race)) or os.path.isfile(race_folder + '/%s/es_%s.txt'%(race,race)):
        return 'script'
    elif os.path.isfile(race_folder + '/%s/es_%s_db.txt'%(race, race)):
        return 'keygroup'
    debugMsg(0,'WCS ERROR: Cannot find race %s'%race)
    return None
        
def spendskills(userid, forced = False):
    """ Builds our spend skills menu """
    playerrace = GetRace(userid)
    playerkey  = getSteam(userid)[playerrace]
    if playerkey['unspent skills']:
        playerlevel = playerkey['level']
        skillskey   = Race(playerrace).returnRaceKey()['skills']
        spendmenu   = popuplib.easymenu('wcs_spendmenu', '_popup_choice', spendSelect)
        spendmenu.settitle(str(text("spendskills title", {'unspentskills':playerkey['unspent skills']}, playerlib.getPlayer(userid).get("lang") ) ) )
        #spendmenu.settitle('You have %s Unspent Skills - Spend a Rank Into:'%playerkey['unspent skills'])
        skilllist = Race(playerrace).returnSkillList()
        good = 0
        for skill in skilllist:
            currentranks = playerkey[skill]
            if currentranks < skillskey[skill]['levels']:
                curlevel      = 0
                requiredlevel = 0
                reqskill      = None
                if skillskey[skill].has_key('required level'):
                    requiredlevel = skillskey[skill]['required level']
                    if skillskey[skill].has_key('required skill'):
                        reqskill = skillskey[skill]['required skill']
                        curlevel = playerkey[reqskill]
                    else:
                        curlevel = playerlevel
                if curlevel >= requiredlevel:
                    if not reqskill:
                        intcheck = intervalCheck(currentranks, skillskey[skill]['interval'], playerlevel-requiredlevel)
                    else:
                        intcheck = intervalCheck(currentranks, skillskey[skill]['interval'], playerlevel)
                    if intcheck == 1:
                        spendmenu.addoption((playerrace, skill), '%s (Current Ranks: %s)'%(skill,playerkey[skill]))
                        good = 1
                    else:
                        if not reqskill:
                            spendmenu.addoption(('Low', intcheck, currentranks+1, skill), '%s (Level Needed: %s)'%(skill, intcheck+requiredlevel))
                        else:
                            spendmenu.addoption(('Low', intcheck, currentranks+1, skill), '%s (Level Needed: %s)'%(skill, intcheck))
                else:
                    if not reqskill:
                        spendmenu.addoption(('Low', requiredlevel, currentranks+1, skill), '%s (Level Needed: %s)'%(skill, requiredlevel))
                    else:
                        spendmenu.addoption(('Low', requiredlevel, currentranks+1, skill), '%s (%s Ranks Needed: %s)'%(skill, reqskill, requiredlevel))
            else:
                option = '%s (MAXED)'%skill
                spendmenu.addoption(('Max', skill), option, False)
        if good or forced:
            """ There is at least 1 skill which requires leveling up """
            spendmenu.send(userid)
    else:
        es.tell(userid, '#lightgreen', text('spend skill no points',lang=playerlib.getPlayer(userid).get('lang')))
        
def spendSelect(userid, choice, popupid):
    """ Gets the choice of the skill the player decided to upgrade, do checks, if all is good, upgrade the skill
        and deducts the credits required to upgrade. """
    if choice[0] != 'Low':
        if choice[0] != 'Max':
            playerkey = getSteam(userid)[choice[0]]
            if playerkey['unspent skills']:
                if playerkey.has_key(choice[1]):
                    if playerkey[choice[1]] < Race(GetRace(userid)).returnRaceKey()['skills'][choice[1]]['levels']:
                        playerkey[choice[1]] += 1
                        playerkey['unspent skills'] -= 1
                        es.tell(userid, '#multi', text('spend skill sucess',{'skill':choice[1], 'rank':playerkey[choice[1]]},playerlib.getPlayer(userid).get('lang')))
                        if playerkey['unspent skills'] and es.getplayersteamid(userid) != "BOT":
                            spendskills(userid)
                    else:
                        checkRace(userid, GetRace(userid))
                        spendskills(userid)
            else:
                es.tell(userid, '#lightgreen', text('spend skill no points',lang=playerlib.getPlayer(userid).get('lang')))
        else:
            es.tell(userid, '#multi', text('spend skill max',{'skill':choice[1]},playerlib.getPlayer(userid).get('lang')))
            spendskills(userid)
    else:
        es.tell(userid, '#multi', text('spend skill low level',{'level':choice[1], 'skill':choice[3], 'rank':choice[2]},playerlib.getPlayer(userid).get('lang')))
        spendskills(userid, True)
        
def intervalCheck(ranks, interval, level):
    """ Determins if a user has enough levels to gain the level skill rank in a skill """
    levelneeded = 1+(ranks*interval)
    if level >= levelneeded:
        return 1
    return levelneeded
        
def buildRaceMenu(userid = None ):
    """ Builds the race popup menu, and adds the relevant info to it. """
    if userid is None:
        userid = es.getUseridList()
    if isinstance(userid, list) or isinstance(userid, tuple):
        for user in userid:
            buildRaceMenu(user)
    elif es.exists('userid', userid):
        racemenu     = popuplib.easymenu('wcs_racemenu_user%s' % userid,     '_popup_choice', raceMenuSelect)
        raceinfomenu = popuplib.easymenu('wcs_raceinfomenu_user%s' % userid, '_popup_choice', raceInfoSelect)
        racemenu.settitle('WCS Race Menu:')
        raceinfomenu.settitle('WCS Race Info Menu:')
        """ Sort the race_list so that it's minimum level first """
        race_list.sort(lambda x,y: -1 if Race(x).returnRaceKey()['Min Level'] < Race(y).returnRaceKey()['Min Level'] else 0 if Race(x).returnRaceKey()['Min Level'] == Race(y).returnRaceKey()['Min Level'] else 1)
        for race in race_list:
            racekey   = Race(race).returnRaceKey()
            steamid   = getSteam(userid)
            checkRace(userid, race)
            raceDict = steamid[race]
            if racekey.has_key('Min Level') and (not racekey.has_key('Team') or es.getplayerteam(userid) == int(racekey['Team'])) and racekey['Min Level'] and steamid['level'] < racekey['Min Level']:
                racemenu.addoption(race, '%s (Level Required: %i)'%(race, racekey['Min Level']), False)
                raceinfomenu.addoption(race, '%s (Level Required: %i)'%(race, racekey['Min Level']))
                
            elif racekey.has_key('Team') and (not racekey.has_key('Min Level') or not racekey['Min Level'] or steamid['level'] >= racekey['Min Level']) and es.getplayerteam(userid) <> int(rackey['Team']):
                racemenu.addoption(race, '%s (Team Required: %i)'%(race, racekey['Team']), False)
                raceinfomenu.addoption(race, '%s (Team Required: %i)'%(race, racekey['Team']))
                
            elif (racekey.has_key('Team') and es.getplayerteam(userid) != int(racekey['Team']) ) and (racekey.has_key('Min Level') and racekey['Min Level'] and steamid['level'] < racekey['Min Level']):
                racemenu.addoption(race, '%s (Team Required: %i, Level Required: %i)'%(race, racekey['Team'], racekey['Min Level']), False)
                raceinfomenu.addoption(race, '%s (Team Required: %i, Level Required: %i)'%(race, racekey['Team'], racekey['Min Level']))
                
            else:
                racemenu.addoption(race, '%s (Current Level: %s)' % (race, raceDict['level']) )
                raceinfomenu.addoption(race, '%s (Current Level: %s)' % (race, raceDict['level']) )
                
            racemenu.update(userid)
            raceinfomenu.update(userid)
            
def canUserActivateRace(userid, race = None):
    if race is None:
        race = GetRace(userid)
    racekey = Race(race).returnRaceKey()
    steamid = getSteam(userid)
    if race not in steamid:
        checkRace(userid, race)
    raceDict = steamid[race]
    return (bool (racekey.has_key('Min Level') and racekey['Min Level'] and steamid['level'] < racekey['Min Level']) == False)
        
def raceMenuSelect(userid, choice, popupid):
    """ Handels what happens when a user selects a race. Do several checks, if
        at the end all the checks passed, change their race. """
    good = 1
    
    """ If the race has a minum level, check if their level is past this """
    if Race(choice).returnRaceKey().has_key('Min Level'):
        if not getSteam(userid)['level'] >= Race(choice).returnRaceKey()['Min Level']:
            good = 0
            es.tell(userid, '#multi', text('race select low',{'race':choice},playerlib.getPlayer(userid).get('lang')))
            
    """ If the race is only registered for a certain steamID list, check if they are in this. """
    if Race(choice).returnRaceKey().has_key('steam allow'):
        if es.exists('userid',userid):
            if not playerlib.uniqueid(userid,True) in Race(choice).returnRaceKey()['steam allow']:
                good = 0
                es.tell(userid, '#multi', text('race select restricted steamid',{'race':choice},playerlib.getPlayer(userid).get('lang')))
                
    """ If the race has a team limit, check the amount already on that team. """
    if Race(choice).returnRaceKey().has_key('teamlimit'):
        limit = Race(choice).returnRaceKey()['teamlimit']
        team = int(es.getplayerteam(userid))
        count = 0
        if team == 2:
            filter = '#t'
        elif team == 3:
            filter = '#ct'
        for id in playerlib.getUseridList(filter):
            if GetRace(id) == choice:
                count += 1
        if count >= limit:
            good = 0
            es.tell(userid, '#multi', text('race select team limit',{'limit':limit,'race':choice},playerlib.getPlayer(userid).get('lang')))
            
    """ If all checks passed okay, then set the players race. """
    if good:
        es.event('initialize', 'wcs_changerace')
        es.event('setint',     'wcs_changerace', 'userid',  userid)
        es.event('setstring',  'wcs_changerace', 'newrace', choice)
        es.event('setstring',  'wcs_changerace', 'oldrace', getSteam(userid)['race'])
        if playerlib.getPlayer(userid).get('isdead'):
            es.event('setint', 'wcs_changerace', 'delayed', 0)
            getSteam(userid)['race'] = choice
            es.tell(userid, '#multi', text('race select change',{'race':choice},playerlib.getPlayer(userid).get('lang') ) )
            checkRace(userid, choice)
            es.server.queuecmd('gravity %s %s' % (userid, 1.0) )
        else:
            es.event('setint', 'wcs_changerace', 'delayed', 1)
            getSteam(userid)['delayed race'] = choice
            es.tell(userid, '#multi', text('race select alive',{'race':choice},playerlib.getPlayer(userid).get('lang') ) )
        es.event('fire', 'wcs_changerace')
            
def raceInfoSelect(userid, choice, popupid):
    """ Finds out more info about the race, and puts all info into a popup. """
    raceInstance   = Race(choice)
    skilllist      = raceInstance.returnSkillList()
    infomenu       = popuplib.create('wcs_infomenu')
    tokens         = {}
    tokens['race'] = choice
    racekey        = raceInstance.returnRaceKey()
    tokens['top']  = "\n"
    if raceInstance.author is not None:
        tokens['top'] += "\nRace Author: %s\n" % raceInstance.author
    if racekey.has_key('Min Level') and racekey['Min Level']:
        tokens['top'] += "Required Level: %s\n" % racekey['Min Level']
    if racekey.has_key('max level'):
        tokens['top'] += "Maximum Level: %s\n" % racekey['max level']
    if getSteam(userid).has_key(choice):
        tokens['top'] += "Your Level: %s\n" % getSteam(userid)[choice]['level']
    if racekey.has_key('Team'):
        ident = 'Any'
        if wcs.game == 'Counter-Strike: Source':
            if racekey['Team'] == 2:
                ident = 'Terorist'
            elif racekey['Team'] == 3:
                ident = 'Counter Terorist'
        elif 'Deathmatch' in game:
            if racekey['Team'] == 2:
                ident = 'Rebel'
            elif racekey['Team'] == 3:
                ident = 'Combine'
        else:
            if racekey['Team'] == 2:
                ident = 'Team 2'
            elif racekey['Team'] == 3:
                ident = 'Team 3'
        tokens['top'] += "Required Team: %s\n" % ident    
    if racekey.has_key('restriction type'):
        if racekey['restriction type'] == 'block only':
            mystring = 'Disallowed Weapons: '
        elif racekey['restriction type'] == 'allow only':
            mystring = 'Allowed Weapons: '
        for w in racekey['weapons list']:
            mystring = '%s %s'%(mystring, w)
        tokens['top'] += mystring + "\n"
    if racekey.has_key('teamlimit'):
        tokens['top'] += "Max Per Team: %s\n" % racekey['teamlimit']
    index = 0
    tokens['skills'] = ""
    for skill in skilllist:
        index += 1
        tokens['skills'] += "->%s. %s\n" % (index, skill)
        tokens['skills'] += "  - %s\n" % (Race(choice).returnRaceKey()['skills'][skill]['description'])
    tokens['skills'] = tokens['skills'][:-1]
    addline(infomenu, returnAllLanguages('infomenu', tokens))
    infomenu.send(userid)
    
def wcsSkillsInfo():
    """ Retrieves the person who ran the command, and show all the skills in a popup of their race. """
    userid           = int(es.getcmduserid())
    choice           = GetRace(userid)
    skilllist        = Race(choice).returnSkillList()
    infomenu         = popuplib.create('wcs_infomenu')
    tokens           = {}
    tokens['race']   = choice
    tokens['skills'] = ""
    index = 0
    for skill in skilllist:
        index += 1
        tokens['skills'] += "->%s. %s\n" % (index, skill)
        tokens['skills'] += "  - %s\n" % (Race(choice).returnRaceKey()['skills'][skill]['description'])
    tokens['skills'] = tokens['skills'][:-1]
    addline(infomenu, returnAllLanguages('infomenu2', tokens))
    infomenu.send(userid)
    
def wcsUltiOn():
    """ A custom client command which fires upon +ultimate. Globalise the event if the cooldown
        time has passed, otherwise send a message to the client. """
    userid = int(es.getcmduserid())
    player = Command(userid)
    if not es.getplayerprop(userid,'CBasePlayer.pl.deadflag'):
        if not dict_commands.has_key(userid):
            player.ResetDefault()
        if not player.ReturnDict('UltiBlock'): 
            race = GetRace(userid)
            skillname = None
            skilllist = Race(race).returnSkillList()
            for a in skilllist:
                if _dict_races[race]['skills'][a]['type'] == 'Ulti':
                    skillname = str(a)
            cool_down_period = 0
            start_cool_down_time = 0
            if skillname:
                if dict_commands[userid]['CoolDownTime'].has_key(skillname):
                    cool_down_period = dict_commands[userid]['CoolDownTime'][skillname]['CoolTime']
                    start_cool_down_time = dict_commands[userid]['CoolDownTime'][skillname]['start']
                time_elapsed = time.time() - start_cool_down_time
                if time_elapsed >= cool_down_period:
                    if es.exists('userid',userid):
                        es.event('initialize', 'player_ultimate_on')
                        es.event('setint','player_ultimate_on','userid',userid)
                        es.event('fire','player_ultimate_on')
                else:
                    es.tell(userid,'#multi',text('ultimate cool down',{'time':int(round(cool_down_period - time_elapsed))},playerlib.getPlayer(userid).get('lang')))
        else:
            es.tell(userid,'#multi',text('ultimate blocked',lang=playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#multi',text('ultimate dead',lang=playerlib.getPlayer(userid).get('lang')))
        
def wcsUltiOff():
    """ A custom client command which fires upon -ultimate. Globalise the event """
    userid = int(es.getcmduserid())
    player = Command(userid)
    if es.exists('userid',userid):
        if not player['UltiBlock']:
            if not player['CoolDownDeath']:
                race = GetRace(userid)
                skillname = None
                skilllist = Race(race).returnSkillList()
                for a in skilllist:
                    if _dict_races[race]['skills'][a]['type'] == 'Ulti':
                        skillname = str(a)
                cool_down_period = 0
                start_cool_down_time = 0
                if skillname:
                    if dict_commands[userid]['CoolDownTime'].has_key(skillname):
                        cool_down_period = dict_commands[userid]['CoolDownTime'][skillname]['CoolTime']
                        start_cool_down_time = dict_commands[userid]['CoolDownTime'][skillname]['start']
                    time_elapsed = time.time() - start_cool_down_time
                    cooldown_time = cool_down_period - time_elapsed
                    if cooldown_time < 0: 
                        cooldown_time = 0
                    es.event('initialize', 'player_ultimate_off')
                    es.event('setint','player_ultimate_off','userid',userid)
                    es.event('setint','player_ultimate_off','cooldown',int(cooldown_time))
                    es.event('fire','player_ultimate_off')
        else:
            es.tell(userid,'#multi',text('ultimate blocked',lang=playerlib.getPlayer(userid).get('lang')))
            
def AbilityOn():
    """ A custom client command which fires upon +ability. Globalise the event """
    userid = es.getcmduserid()
    if not es.getplayerprop(userid,'CBasePlayer.pl.deadflag'):
        if not Command(userid).ReturnDict('AbilBlock'):
            if es.exists('userid',userid): 
                es.event('initialize', 'player_ability_on')
                es.event('setint','player_ability_on','userid',userid)
                es.event('fire','player_ability_on')
        else:
            es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#multi',text('ability dead',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOff():
    """ A custom client command which fires upon -ability. Globalise the event """
    userid = es.getcmduserid()
    if not Command(userid).ReturnDict('AbilBlock'):
        if not Command(userid).ReturnDict('CoolDownDeath'):
            if es.exists('userid',userid):
                es.event('initialize', 'player_ability_off')
                es.event('setint','player_ability_off','userid',userid)
                es.event('fire','player_ability_off')
    else:
        es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOn2():
    """ A custom client command which fires upon +ability2. Globalise the event """
    userid = es.getcmduserid()
    if not es.getplayerprop(userid,'CBasePlayer.pl.deadflag'):
        if not Command(userid).ReturnDict('AbilBlock'):
            if es.exists('userid',userid): 
                es.event('initialize', 'player_ability_on2')
                es.event('setint','player_ability_on2','userid',userid)
                es.event('fire','player_ability_on2')
        else:
            es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#multi',text('ability dead',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOff2():
    """ A custom client command which fires upon -ability2. Globalise the event """
    userid = es.getcmduserid()
    if not Command(userid).ReturnDict('AbilBlock'):
        if not Command(userid).ReturnDict('CoolDownDeath'):
            if es.exists('userid',userid):
                es.event('initialize', 'player_ability_off2')
                es.event('setint','player_ability_off2','userid',userid)
                es.event('fire','player_ability_off2')
    else:
        es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOn3():
    """ A custom client command which fires upon +ability3. Globalise the event """
    userid = es.getcmduserid()
    if not es.getplayerprop(userid,'CBasePlayer.pl.deadflag'):
        if not Command(userid).ReturnDict('AbilBlock'):
            if es.exists('userid',userid): 
                es.event('initialize', 'player_ability_on3')
                es.event('setint','player_ability_on3','userid',userid)
                es.event('fire','player_ability_on3')
        else:
            es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#multi',text('ability dead',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOff3():
    """ A custom client command which fires upon -ability3. Globalise the event """
    userid = es.getcmduserid()
    if not Command(userid).ReturnDict('AbilBlock'):
        if not Command(userid).ReturnDict('CoolDownDeath'):
            if es.exists('userid',userid):
                es.event('initialize', 'player_ability_off3')
                es.event('setint','player_ability_off3','userid',userid)
                es.event('fire','player_ability_off3')
    else:
        es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOn4():
    """ A custom client command which fires upon +ability4. Globalise the event """
    userid = es.getcmduserid()
    if not es.getplayerprop(userid,'CBasePlayer.pl.deadflag'):
        if not Command(userid).ReturnDict('AbilBlock'):
            if es.exists('userid',userid): 
                es.event('initialize', 'player_ability_on4')
                es.event('setint','player_ability_on4','userid',userid)
                es.event('fire','player_ability_on4')
        else:
            es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#multi',text('ability dead',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOff4():
    """ A custom client command which fires upon -ability4. Globalise the event """
    userid = es.getcmduserid()
    if not Command(userid).ReturnDict('AbilBlock'):
        if not Command(userid).ReturnDict('CoolDownDeath'):
            if es.exists('userid',userid):
                es.event('initialize', 'player_ability_off4')
                es.event('setint','player_ability_off4','userid',userid)
                es.event('fire','player_ability_off4')
    else:
        es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOn5():
    """ A custom client command which fires upon +ability5. Globalise the event """
    userid = es.getcmduserid()
    if not es.getplayerprop(userid,'CBasePlayer.pl.deadflag'):
        if not Command(userid).ReturnDict('AbilBlock'):
            if es.exists('userid',userid): 
                es.event('initialize', 'player_ability_on5')
                es.event('setint','player_ability_on5','userid',userid)
                es.event('fire','player_ability_on5')
        else:
            es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
    else:
        es.tell(userid,'#multi',text('ability dead',lang=playerlib.getPlayer(userid).get('lang')))
        
def AbilityOff5():
    """ A custom client command which fires upon -ability5. Globalise the event """
    userid = es.getcmduserid()
    if not Command(userid).ReturnDict('AbilBlock'):
        if not Command(userid).ReturnDict('CoolDownDeath'):
            if es.exists('userid',userid):
                es.event('initialize', 'player_ability_off5')
                es.event('setint','player_ability_off5','userid',userid)
                es.event('fire','player_ability_off5')
    else:
        es.tell(userid,'#multi',text('ability blocked',lang=playerlib.getPlayer(userid).get('lang')))
        
def prep_spawn():
    """ Before a player respawns, ensure their dictionary is reset to default. """
    userid = ReturnEV('userid') 
    if es.exists('userid', userid):
        Command(userid).ResetDefault()
    
ph_fire = 0
def prep_hurt_fire():
    """ Before a player_hurt event is globalised, fire this prep hook so people
        can change values before they 'happen'. """
    global ph_fire
    userid = ReturnEV('userid')
    if es.exists('userid', userid):
        if not ph_fire:
            ph_fire  = 1
            userid   = int(userid)
            attacker = int(ReturnEV('attacker') )
            fireNormalDamageEvent  = False
            if dir not in ('cstrike', 'dod'):
                damage   = Command(userid, False).key['__temp__health'] - es.getplayerprop(userid, 'CBasePlayer.m_iHealth')
                weapon   = playerlib.getPlayer(attacker).get('weapon') if attacker else "World"
            else:    
                weapon   = ReturnEV('weapon')
                if dir == 'cstrike':
                    damage   = int(ReturnEV('dmg_health') ) 
                else:
                    damage   = int(ReturnEV('damage'))
                    fireNormalDamageEvent = True
            health   = es.getplayerprop(userid, 'CBasePlayer.m_iHealth')
            es.event('initialize', 'prep_hurt' )
            es.event('setint',     'prep_hurt', 'userid',     userid )
            es.event('setint',     'prep_hurt', 'dmg_health', damage )
            es.event('setint',     'prep_hurt', 'attacker',   attacker )
            es.event('setint',     'prep_hurt', 'health',     health )
            es.event('setstring',  'prep_hurt', 'weapon',     weapon )
            es.event('fire',       'prep_hurt' )

            es.event('initialize', 'player_hurt')
            es.event('setint',    'player_hurt', 'userid',             userid )
            es.event('setint',    'player_hurt', 'dmg_health',         damage )
            if fireNormalDamageEvent:
                es.event('setint',     'player_hurt', 'damage',        damage )
            es.event('setint',    'player_hurt', 'attacker',           attacker )
            es.event('setint',    'player_hurt', 'health',             health )
            es.event('setstring', 'player_hurt', 'weapon',             weapon )
            
            es.event('fire','player_hurt')
        ph_fire = 0
            
def modHurt(ev):
    ev['dmg_health'] = ev['damage']
    return True
           
def modSpawn(ev):
    userid = ev['userid']
    es.server.queuecmd('gravity %s %s' % (userid, 1.0) )
    player = Command(userid)
    player.UpdateDict('DefaultGrav', 1)
    player.UpdateDict('CoolDownDeath', 0)
    return True
            
def player_team(ev):
    """ Runs when a player changes their team. Check how many races of that type are on that team,
        If there's too many, stop him. """
    userid = int(ev['userid'])
    buildRaceMenu(userid)    
    if es.exists('userid',userid):
        if Race(GetRace(userid)).returnRaceKey().has_key('teamlimit'):
            limit = Race(GetRace(userid)).returnRaceKey()['teamlimit']
            choice = GetRace(userid)
            team = int(es.getplayerteam(userid))
            count = 0
            filter = None
            if team == 2:
                filter = '#t'
            elif team == 3:
                filter = '#ct'
            if filter:
                for id in playerlib.getUseridList(filter):
                    if id != userid:
                        if GetRace(id) == choice:
                            count += 1
                if count >= limit:
                    if es.exists('userid',userid):
                        es.tell(userid, '#multi', text('team limit join',{'race':GetRace(userid)},playerlib.getPlayer(userid).get('lang')))
                        defaultrace(userid, playerlib.uniqueid(int(userid),True))
                        
def item_pickup(ev):
    """ Runs when an item is picked up. Check for restricted weapons """
    userid  = int(ev['userid'])
    race    = GetRace(userid)
    racekey = Race(race).returnRaceKey()
    handle  = es.getplayerhandle(userid)
    weapon  = ev['item'].replace('weapon_','').lower()
    if racekey.has_key('restriction type'):
        if ev['item'] != 'c4':
            if racekey['restriction type'] == 'allow only':
                if ev['item'] not in racekey['weapons list']:
                    if isEst:
                        es.server.queuecmd('est_removeweapon %s weapon_%s' % (userid, ev['item']) )
                    else:
                        for weaponIndex in es.createentitylist('weapon_%s' % ev['item']):
                            if es.getindexprop(weaponIndex, 'CBaseEntity.m_hOwnerEntity') == handle:
                                if isOb:
                                    es.remove(weaponIndex)
                                else:
                                    es.server.queuecmd('es_remove %s' % weaponIndex)
                                break
            elif racekey['restriction type'] == 'block only':
                if ev['item'] in racekey['weapons list']:
                    if isEst:
                        es.server.queuecmd('est_removeweapon %s weapon_%s' % (userid, ev['item']) )
                    else:
                        for weaponIndex in es.createentitylist('weapon_%s' % ev['item']):
                            if es.getindexprop(weaponIndex, 'CBaseEntity.m_hOwnerEntity') == handle:
                                if isOb:
                                    es.remove(weaponIndex)
                                else:
                                    es.server.queuecmd('es_xremove %s' % weaponIndex)
                                break
    if weapon in Command(userid)['Restricted']:
        Command(userid).RemoveWeapon(weapon)
                    
def player_hurt(ev):
    """ Runs when a player is hurt... """
    userid   = int(ev['userid'])
    attacker = int(ev['attacker'])
    """ If the race is a keygroup race, run the player_victim """
    race     = GetRace(userid)
    runKeygroupRace(userid, race, 'player_victim')
    """ If the race is a keygroup race, run the player_attacker """
    race = GetRace(attacker)
    runKeygroupRace(userid, race, 'player_attacker')
    """ Regen the player if damaged """
    if dict_commands.has_key(userid) and not dict_commands[userid]['RegenLoop']:
        dict_commands[userid]['RegenLoop'] = 1
        amount = Command(userid).ReturnDict('RegenAmount')
        delay = Command(userid).ReturnDict('RegenDelay')
        Command(userid).Regen(amount,delay)
        
def player_disconnect(ev):
    """ Runs when a player disconnects... delete the player from dict_commands and command_instances. """
    userid = ev['userid']
    if es.exists('key', 'WCSuserdata', userid):
        es.keydelete('WCSuserdata', userid)
    if dict_commands.has_key(userid):
        for d in dict_commands[userid]['delay list']:
            gamethread.cancelDelayed(d)
        del dict_commands[userid]
        es.keydelete('WCSuserdata', userid)
    if command_instances.has_key(userid):
        del command_instances[userid]
    gravity.removeGravityChange(userid)
    deleted = []
    for popup in popuplib.gPopups:
        if popup.startswith('wcs_') and popup.endswith('user%s' % userid):
            deleted.append(popup)
    for popup in deleted:
        popuplib.delete(popup)
        
def player_ultimate_on(ev):
    """ Runs when the ultimate is on. Run the keygroup races ultimate event """
    userid  = int(ev['userid'])
    race    = GetRace(userid)
    runKeygroupRace(userid, race, 'player_ultimate', True)
            
def player_say(ev):
    """ Called when a player says something; run the keygroupraces say event crappy thing. """
    userid  = int(ev['userid'])
    race    = GetRace(userid)
    runKeygroupRace(userid, race, 'player_say')
        
def player_death(ev):
    """ Called upon when a player dies. """
    userid   = int(ev['userid'])
    attacker = int(ev['attacker'])
    race     = GetRace(userid)
    """ If the user's race is a keygroup race """
    runKeygroupRace(userid, race, 'player_death')
    runKeygroupRace(userid, GetRace(attacker), 'player_kill')
    if attacker:
        """ If there was an attacker give xp, and the relevant headshot xp yada yada.. """
        configweapons()
        user_team = int(ev['es_userteam'])
        attacker_team = int(ev['es_attackerteam'])
        if ev['headshot']:
            headshot = int(ev['headshot'])
        else:
            headshot = 0
        if game != 'Counter-Strike: Source':
            Command(attacker).GiveCash(400)
        if attacker_team != user_team:
            if float(es.ServerVar('wcs_killxp')):
                Command(attacker).GiveXp(float(es.ServerVar('wcs_killxp')), text('kill xp',lang=playerlib.getPlayer(attacker).get('lang')))
            if float(es.ServerVar('wcs_levelxp')):
                if (Command(userid).GetLevel()-Command(attacker).GetLevel()) >= 1:
                    Command(attacker).GiveXp((Command(userid).GetLevel()-Command(attacker).GetLevel())*float(es.ServerVar('wcs_levelxp')),text('higher level xp',lang=playerlib.getPlayer(attacker).get('lang')))
            if headshot:
                if float(es.ServerVar('wcs_headshotxp')):
                    Command(attacker).GiveXp(float(es.ServerVar('wcs_headshotxp')), text('headshot xp',lang=playerlib.getPlayer(attacker).get('lang')))
            if ev['weapon'] in wcs_weaponbonus:
                if int(weaponbonusxp[wcs_weaponbonus.index(ev['weapon'])]):
                    Command(attacker).GiveXp(weaponbonusxp[wcs_weaponbonus.index(ev['weapon'])], text('weapon xp',{'weapon':ev['weapon']},playerlib.getPlayer(attacker).get('lang')))
    playerkey = getSteam(int(userid))
    if playerkey and playerkey['delayed race']:
        playerkey['race'] = playerkey['delayed race']
        checkRace(userid, playerkey['race'])
        playerkey['delayed race'] = 0
        es.tell(int(userid), '#multi', text('race select change',{'race':playerkey['race']},playerlib.getPlayer(userid).get('lang')))
        es.server.queuecmd('gravity %s %s' % (userid, 1.0) )
    if dict_commands.has_key(userid):
        for d in dict_commands[userid]['delay list']:
            gamethread.cancelDelayed(d)
        dict_commands[userid]['delay list'] = []
        if dict_commands[userid]['RegenLoop']:
            dict_commands[userid]['RegenLoop'] = 0
        if dict_commands[userid]['DrainLoop']:
            drain_delayed = 'drain_%s' % userid
            gamethread.cancelDelayed(drain_delayed)
            dict_commands[userid]['DrainLoop'] = 0
    gamethread.delayed(0.1, Command(userid).UpdateDict,('CoolDownDeath', 1))
    gamethread.delayed(0.2, Command(userid).ResetDefault)
    gamethread.delayed(0.2, Command(userid).SetGravity, (1.0) )
    
def hostage_rescued_all(ev):
    """ Called when ALL hostages are rescued. Give XP """
    if float(es.ServerVar('wcs_allhostagexp')):
        for userid in playerlib.getUseridList('#ct,#alive'):
            Command(userid).GiveXp(allfloat(es.ServerVar('wcs_hostagexp')), text('hostage all xp', lang=playerlib.getPlayer(userid).get('lang')))
            
#Gets/Sets event_var for our prep events
def ReturnEV(variable):
    """ A little wrapper to set the Event Info in a pre event to return the value  """
    es.ServerVar('wcs_temp').set(0)
    if isOb:
        es.server.est_geteventinfo('wcs_temp', variable)
    else:
        es.server.cmd('est_geteventinfo wcs_temp %s'%variable)
    return str(es.ServerVar('wcs_temp'))
    
def SetEV(variable, value):
    """ A little wrapper to set the Event Info in a pre event to hold the value """
    if isOb:
        es.server.est_seteventinfo(variable, value)
    else:
        es.server.cmd('est_seteventinfo %s %s'%(variable, value))
    
_dict_WCSPlayers = {}
def getSteam(userid):
    """ his code handles our user data base. It returns the players dict within the database """
    steamid = None
    if not es.exists('userid', userid):
        if userid.startswith(('STEAM', 'BOT_')):
            steamid = userid
        else:
            userid = es.getuserid(userid)
            if userid:
                steamid = es.getplayersteamid(steamid)
    else:
        steamid = playerlib.uniqueid(int(userid),True)
    if steamid is not None:
        if not _dict_WCSPlayers.has_key(steamid):
            es.sexec(userid,'say','wcshelp')
            _dict_WCSPlayers[steamid] = {}
            _dict_WCSPlayers[steamid]['getlevel'] = float(es.ServerVar('wcs_freelevels'))
            defaultrace(userid, steamid)
        return _dict_WCSPlayers[steamid]
    return None
            
def defaultrace(userid, steamid):
    """ This sets a player to have the default race, and attributes (fresh database) """
    if not _dict_WCSPlayers[steamid].has_key('level'):
        _dict_WCSPlayers[steamid]['level'] = 0
    _dict_WCSPlayers[steamid]['race']         = race_list[0]
    _dict_WCSPlayers[steamid]['delayed race'] = 0
    _dict_WCSPlayers[steamid]['last_active']  = time.time()
    _dict_WCSPlayers[steamid]['name']         = es.getplayername(userid)
    for race in race_list:
        checkRace(userid, race)
    
def checkRace(userid, race):
    """ This checks if the user has an active race, if not, it sets them to default race """
    userKey = getSteam(userid)
    if not userKey.has_key(race):
        userKey[race] = {}
        userKey[race]['unspent skills'] = 0
        userKey[race]['xp']             = 0
        if canUserActivateRace(userid, race):
            userKey[race]['level']      = 1
            userKey['level']           += 1
        else:
            userKey[race]['level']      = 0
    elif not userKey[race]['level']:
        if canUserActivateRace(userid, race):
            userKey[race]['level']  = 1
            if int(es.ServerVar('wcs_new_race_increments_level')):
                userKey['level']       += 1
    for skill in Race(race).returnSkillList():
        if not userKey[race].has_key(skill):
            userKey[race][skill] = 0
            
def GetRace(userid):
    """ Retrieves the race of the user """
    if es.exists('userid',userid):
        return getSteam(userid)['race']
    return None
        
def GetLevel(userid, raceName, skillName):
    """ This retrieves the players skill level of any given race """
    race = GetRace(int(userid))
    if race == raceName:
        if Race(raceName).has_key(skillName):
            return getSteam(userid)[raceName][skillName]
    return 0
    
   
def BotLevel(userid,steamid):
    """ Mimics the 'spendskills' popup for bots, builds a list
        of available skills, then changes the race if its maxed
        out all of its skills. """
    race = GetRace(userid)
    playerkey = getSteam(userid)[race]
    playerlevel = playerkey['level']
    skilllist = Race(race).returnSkillList()
    random_list = []
    skillskey = _dict_races[race]['skills']
    maximums = 0
    if playerkey['unspent skills']:
        for a in skilllist:
            level = GetLevel(userid, race, a)
            currentranks = playerkey[a]
            if skillskey[a]['type'] == 'Skill':
                if currentranks < skillskey[a]['levels']:
                    intcheck = intervalCheck(currentranks, skillskey[a]['interval'], playerlevel)
                    if intcheck:
                        random_list.append(a)
                else:
                    maximums += 1
            else:
                if currentranks < skillskey[a]['levels']:
                    requiredlevel = skillskey[a]['levels']
                    if playerlevel >= requiredlevel:
                        intcheck = intervalCheck(currentranks, skillskey[a]['interval'], playerlevel - requiredlevel)
                        if intcheck:
                            random_list.append(a)
                else:
                    maximums += 1
        if random_list:
            random_skill = random.choice(random_list)
            spendSelect(userid, (race, random_skill), None)
            BotLevel(userid,steamid)
        else:
            if maximums >= len(skilllist):
                # All the skills maxed out, change race.
                random_list = []
                player_team = int(es.getplayerteam(userid)) 
                for race in race_list:
                    racekey = Race(race).returnRaceKey()
                    if racekey.has_key('Min Level') and not racekey.has_key('Team') and racekey['Min Level']:
                        if playerlevel >= racekey['Min Level']:
                            random_list.append(race)
                    elif racekey.has_key('Team') and (not racekey.has_key('Min Level') or not racekey['Min Level']):
                        if player_team == racekey['Team']:
                            random_list.append(race)
                    elif racekey.has_key('Team') and racekey.has_key('Min Level') and racekey['Min Level']:
                        if player_team == racekey['Team'] and playerlevel >= racekey['Min Level']:
                            random_list.append(race)
                    else:
                        random_list.append(race)
                if random_list:
                    random_skill = random.choice(random_list)
                    raceMenuSelect(userid,random_skill,0)

class Effect_Effect():
    """ Start with an ES only effect class with the same class methods """
    
    def PixieEffect(self, userid, life, r, g, b):
        self._createEntity(userid, 'env_Smokestack', 'trail%s' % userid, {"basespread" :13, 
                                                                           "spreadspeed" :25, 
                                                                           "WindSpeed" :0, 
                                                                           "initial" :0, 
                                                                           "speed" :100, 
                                                                           "startsize" :5, 
                                                                           "endsize":2, 
                                                                           "rate" : 350, 
                                                                           "jetlength" : 100,
                                                                           "twist" : 0,
                                                                           "SmokeMaterial" : "sprites/light_glow02_add_noz",
                                                                           "angles" : "0 0 0",
                                                                           "rendermode" : 18,
                                                                           "renderamt" : 100,
                                                                           "redercolor": "%s %s %s" % (r, g, b)
                                                                           })
        if isOb:
            es.fire(userid, 'trail%s' % userid, 'setparent', '!activator')
            gamethread.delayed(life, es.fire, (userid, 'trail%s' % userid, 'kill') )
        else:
            es.server.queuecmd('es_xfire %s trail%s setparent !activator' % (userid, userid) )
            es.delayed(life,'es_xfire %s trail%s kill' % (userid, userid) )
        
    def Smoke(self, userid):
        self._createEntity(userid, 'env_Smokestack', 'smoke%s' % userid, {"basespread" : 400, 
                                                                           "spreadspeed" : 25, 
                                                                           "WindSpeed" : 30, 
                                                                           "initial" : 1, 
                                                                           "speed" : 100, 
                                                                           "startsize" : 250, 
                                                                           "endsize" : 400, 
                                                                           "rate" : 350, 
                                                                           "jetlength" : 100,
                                                                           "twist" : 360,
                                                                           "SmokeMaterial" : "sprites/smoke",
                                                                           "angles" : "0 0 0",
                                                                           "redercolor": "127 127 127"
                                                                           })
        
    def Ring1(self, player, end, life, r, g, b):
        effectlib.drawCircle(es.getplayerlocation(player), end, seconds = life, red = r, green = g, blue = b)
        
    def Ring2(self, player, diameter, life, r, g, b):
        self.Ring1(player, diameter, life, r, g, b)
    
    def Ring3(self, player, end, life, r, g, b):
        effectlib.drawCircle(es.getplayerlocation(player), end, seconds = life, red = r, green = g, blue = b, noise = 150)
    
    def Ring4(self, player, start, end, life, size, spread, r, g, b):
        effectlib.drawCircle(es.getplayerlocation(player), end, seconds = life, red = r, green = g, blue = b, noise = spread, width = size, endwidth = size)
    
    def RingCustom(self, ident, delay, model, x, y, z, start, end, life, size, spread, amplitude, r, g, b, a, speed):
        gamethread.delayed(float(delay), effectlib.drawCircle, a = ((x, y, z), end ), kw = {'seconds': life, 'red': r, 'green': g, 'blue': b, 'brightness': a, 'noise': spread, 'width': size, 'endwidth': size})
    
    def Follow(self, player, r, g, b):
        debugMsg(1, "The effect 'Follow' requires EST, sorry")
    
    def Beam1(self, player1, player2, life, r, g, b):
        effectlib.drawLine(es.getplayerlocation(player1), es.getplayerlocation(player2), seconds = life, red = r, green = g, blue = b)

    def Beam2(self,player1,player2,life,r,g,b):
        effectlib.drawLine(es.getplayerlocation(player1), es.getplayerlocation(player2), seconds = life, red = r, green = g, blue = b)
    
    def Beam3(self, x, y, z, players, life, r, g, b):
        if not type(player) in (list, tuple):
            return
        for player in players:
            effectlib.drawLine((x, y, z), es.getplayerlocation(player), seconds = life, red = r, green = g, blue = b)
    
    def Beam4(self, player1, player2, life, r, g, b):
        effectlib.drawLine(es.getplayerlocation(player1), es.getplayerlocation(player2), seconds = life, red = r, green = g, blue = b)
    
    def BeamCustom(self, ident, delay, model, x, y, z, x1, y1, z1, life, swidth, ewidth, r, g, b, a):
        gamethread.delayed(float(delay), effectlib.drawLine, a = ((x, y, z), (x1, y1, z1)), kw = {'model': model, 'seconds': life, 'red': r, 'green': g, 'blue': b, 'brightness': a, 'width': swidth, 'endwidth': ewidth} )
    
    def Misc1(self,player,life):
        debugMsg(1, "The effect 'Misc1' requires EST, sorry")
    
    def Misc2(self, player, life, size):
        debugMsg(1, "The effect 'Misc2' requires EST, sorry")
    
    def Misc3(self, player, life, size):
        debugMsg(1, "The effect 'Misc3' requires EST, sorry")
    
    def Misc4(self, player, life, size, brightness):
        debugMsg(1, "The effect 'Misc4' requires EST, sorry")
    
    def Misc5(self, player, life, size):
        debugMsg(1, "The effect 'Misc5' requires EST, sorry")
    
    def Misc6(self, player, life, size):
        debugMsg(1, "The effect 'Misc6' requires EST, sorry")
    
    def Misc7(self, player, life, size):
        debugMsg(1, "The effect 'Misc7' requires EST, sorry")
    
    def MiscCustom(self, ident, delay, model, x, y, z, life, size, brightness):
        debugMsg(1, "The effect 'MiscCustom' requires EST, sorry")
        
    def Box(self, x, y, z, effect_time, size, red, green, blue):
        effectlib.drawBox((x, y, z), (x + size, y + size, z + size), seconds = effect_time, red = red, green = green, blue = blue)
    
    def Lightning(self, x_origin, y_origin, z_origin, lightning_range, lightning_time, damage, attacker, team): # By Bonbon
        debugMsg(1, "The effect 'Lightning' requires EST, sorry")
    
    def Laser(self, x, y, z, effect_time):
        debugMsg(1, "The effect 'Laser' requires EST, sorry")

    def _createEntity(self, player, entity, targetName, outputs = {}, turnOn = 'turnon', location = None):
        if isOb:
            index = es.createentity(entity, targetName)
            for output in outputs:
                es.entitysetvalue(index, output, outputs[output])
            es.spawnentity(index)
            if location is not None:
                if location[0] is not None and location[0]:
                    location = map(str, location)
                    es.setindexprop(index, 'CBaseEntity.m_vecOrigin', ','.join(location))
            if turnOn:
                es.fire(player, targetName, turnOn)
            gamethread.delayed(3, es.fire, (player, targetName, 'kill') )
        else:
            es.server.queuecmd('es_xentcreate %s %s' % (player, entity))
            es.server.queuecmd('es_xfire %s !picker addoutput "targetname %s"' % (player, targetName) )
            for output in outputs:
                es.server.queuecmd('es_xfire %s %s addoutput "%s %s"' % (player, targetName, output, outputs[output]) )
            if location is not None:
                es.setindexprop(str(es.ServerVar('eventscripts_lastgive')), 'CBaseEntity.m_vecOrigin', ','.join(location))
            if turnOn:
                es.server.queuecmd('es_xfire %s %s %s' % (player, targetName, turnOn) )
            es.delayed(3,'es_xfire %s %s kill' % (player, targetName) )

if isEst:
                        
    #Awesome New effects by bonbon added as of 0.8.4f
    class Effect_Effect:
        """ Effect class so users can easilly create sexy effects if EST is installed, it will use
            these effects by default."""

        def PixieEffect(self,userid,life, r, g, b):
            """ Call pixie trail effect which follows a user, Created by the awsome Nowayz """
            es.server.queuecmd('es_xgive %s env_Smokestack' % (userid))
            es.server.queuecmd('es est_setentname server_var(eventscripts_lastgive) trail%s' %userid)
            es.server.queuecmd('es_xfire %s trail%s addoutput "basespread 13"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "spreadspeed 25"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "WindSpeed 0"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "initial 0"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "speed 100"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "startsize 5"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "endsize 2"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "rate 350"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "jetlength 100"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "twist 0"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "SmokeMaterial sprites/light_glow02_add_noz"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "angles 0 0 0"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "rendermode 18"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "renderamt 100"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "rendermode 18"' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s addoutput "rendercolor %s %s %s"' % (userid,str(userid),r,g,b))
            es.server.queuecmd('es_xfire %s trail%s turnon' % (userid,str(userid)))
            es.server.queuecmd('es_xfire %s trail%s setparent !activator' % (userid,str(userid)))
            es.delayed(life,'es_xfire %s trail%s kill' % (userid,str(userid)))
     
        def Smoke(self, player):
            """ Smoke effect """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 7 #a 0 sprites/smoke.vmt %s %s %s 100 20'%(x,y,z))
            
        def Ring1(self, player, end, life, r, g, b):
            """ Normal beam effect. """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 10 #a 0 "sprites/lgtning.vmt" %s %s %s 1 %s %s 10 20 10 %s %s %s 255 30'%(x,y,z,end,life,r,g,b))
            
        def Ring2(self, player, diameter, life, r, g, b):
            """ A ring which doesn't move... static circle """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 10 #a 0 sprites/lgtning.vmt %s %s %s %s %s %s 5 0 2 %s %s %s 128 10'%(x,y,z,diameter-20,diameter,life,r,g,b))
            
        def Ring3(self, player, end, life, r, g, b):
            """ A very 'harsh' ring which has a big amplitude. """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_Effect 10 #a 0 sprites/xfireball3.vmt %s %s %s 20 %s %s 10 20 150 %s %s %s 200 100'%(x,y,z,end,life,r,g,b))
            
        def Ring4(self, player, start, end, life, size, spread, r, g, b):
            """ Cool ring with spread """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 10 #a 0 sprites/purplelaser1.vmt %s %s %s %s %s %s %s %s 0 %s %s %s 200 3'%(x,y,z,start,end,life,size,spread,r,g,b))
        
        def Ring5(self, x, y, z, effect_time, red, green, blue): # By Bonbon
            """ Makes lots of loops on top of each other """
            loc = (x, y, z)
            height = 0
            effect_loop2(loc, effect_time, red, green, blue, height, effect_time)
            
        def RingCustom(self, ident, delay, model, x, y, z, start, end, life, size, spread, amplitude, r, g, b, a, speed):
            """ Normal ring with all the functions """
            es.server.queuecmd('est_effect 10 %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s'%(ident, delay, model, x, y, z, start, end, life, size, spread, amplitude, r, g, b, a, speed ) )
            
        def Follow(self, player, r, g, b):
            """ Follows the user wherever he goes until he stops """
            es.server.queuecmd('est_effect 4 #a 0 sprites/steam1.vmt %s 1 5 5 1 %s %s %s 200'%(player,r,g,b))
            
        def Beam1(self,player1,player2,life,r,g,b):
            """ Connects 2 users together via a normal beam """
            x,y,z = es.getplayerlocation(player1)
            x1,y1,z1 = es.getplayerlocation(player2)
            es.server.queuecmd('est_effect 3 #a 0 sprites/lgtning.vmt %s %s %s %s %s %s %s 40 10 %s %s %s 255'%(x,y,z + 30,x1,y1,z1 + 30,life,r,g,b))
            
        def Beam2(self,player1,player2,life,r,g,b):
            """ Connects 2 users together via a more rough beam """
            x,y,z = es.getplayerlocation(player1)
            x1,y1,z1 = es.getplayerlocation(player2)
            es.server.queuecmd('est_effect 3 #a 0 effects/tp_eyefx/tpeye3.vmt %s %s %s %s %s %s %s 7 3 %s %s %s 255'%(x,y,z + 30,x1,y1,z1 + 30,life,r,g,b))
            
        def Beam3(self,x,y,z,players,life,r,g,b):
            """ Connects lots of people together """
            if type(players) == list:
                for a in players:
                    x1,y1,z1 = es.getplayerlocation(players)
                    es.server.queuecmd('est_effect 3 #a 0 sprites/halo01.vmt %s %s %s %s %s %s %s 13 16 %s %s %s 255'%(x,y,z + 30,x1,y1,z1 + 30,life,r,g,b))
            else:
                x1,y1,z1 = es.getplayerlocation(players)
                es.server.queuecmd('est_effect 3 #a 0 sprites/halo01.vmt %s %s %s %s %s %s %s 7 3 %s %s %s 255'%(x,y,z + 30,x1,y1,z1 + 30,life,r,g,b))
                
        def Beam4(self,player1,player2,life,r,g,b): 
            """ Cool beam joining people up.. more of a wavering line """
            x,y,z = es.getplayerlocation(player1)
            x1,y1,z1 = es.getplayerlocation(player2)
            es.server.queuecmd('est_effect 3 #a 0 sprites/halo01.vmt %s %s %s %s %s %s %s 5 5 %s %s %s 255'%(x,y,z,x1,y1,z1,life,r,g,b))
            
        def BeamCustom(self,ident,delay,model,x,y,z,x1,y1,z1,life,swidth,ewidth,r,g,b,a):
            """ Normal beam using all variables """
            es.server.queuecmd('est_effect 3 %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s'%(ident,delay,model,x,y,z,x1,y1,z1,life,swidth,ewidth,r,g,b,a))
            
        def Misc1(self,player,life):
            """ A crystal like effect where the user is. """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 10 #a 0 effects/tp_eyefx/tpeye3.vmt %s %s %s 9 0 %s 66 1 0 255 255 255 255 1'%(x,y,z,life))
            
        def Misc2(self, player, life, size):
            """ Electrical Field """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 11 #a 0 sprites/physring1.vmt %s %s %s %s %s 255'%(x,y,z+15,life,size))
            
        def Misc3(self, player, life, size):
            """ Force Field """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 11 #a 0 sprites/strider_blackball.vmt %s %s %s %s %s 255'%(x,y,z+15,life,size))
            
        def Misc4(self, player, life, size, brightness):
            """ Bright Light """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 11 #a 0 sprites/physcannon_bluecore1b.vmt %s %s %s %s %s %s'%(x,y,z+15,life, size, brightness))
            
        def Misc5(self, player, life, size):
            """ red glow """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 11 #a 0 sprites/purpleglow1.vmt %s %s %s %s %s 150'%(x,y,z,life,size))
            
        def Misc6(self, player, life, size):
            """ Combine shield things """
            es.server.queuecmd('est_effect 11 #a 0 effects/com_shield003a.vmt %s %s %s %s %s 255'%(x,y,z,life,size))
            
        def Misc7(self, player, life, size):
            """ Fire """
            x,y,z = es.getplayerlocation(player)
            es.server.queuecmd('est_effect 11 #a 0 sprites/xfireball3.vmt %s %s %s %s %s 255'%(x,y,z,life,size))
            
        def MiscCustom(self, ident, delay, model, x, y, z, life, size, brightness):
            """ Normal 11 effect """
            es.server.queuecmd('est_effect 11 %s %s %s %s %s %s %s %s %s'%(ident, delay, model, x, y, z, life, size, brightness))
            
        def Lightning(self, x_origin, y_origin, z_origin, lightning_range, lightning_time, damage, attacker, team): # By Bonbon
            """ Makes random lgihtning bolts everywhere around the player """
            loc = (x_origin, y_origin, z_origin)
            effect_time = 0
            effect_loop(loc, lightning_time, lightning_range, damage, effect_time, attacker, team)
            
        def Box(self, x, y, z, effect_time, size, red, green, blue):
            """ Creates a box around the user made of lasers """
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x, y, z, x, y, z + (50 * size), effect_time, red, green, blue))
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x, y, z + (50 * size), x + (50 * size), y, z + (50 * size), effect_time, red, green, blue))
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x + (50 * size), y, z + (50 * size), x + (50 * size), y, z, effect_time, red, green, blue))
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x + (50 * size), y, z, x, y, z, effect_time, red, green, blue))
           
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x, y, z, x, y - (50 * size), z, effect_time, red, green, blue))
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x + (50 * size), y - (50 * size), z, x + (50 * size), y, z, effect_time, red, green, blue))
           
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x + (50 * size), y - (50 * size), z + (50 * size), x + (50 * size), y, z + (50 * size), effect_time, red, green, blue))
           
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x, y - (50 * size), z, x, y - (50 * size), z + (50 * size), effect_time, red, green, blue))
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x, y - (50 * size), z + (50 * size), x + (50 * size), y - (50 * size), z + (50 * size), effect_time, red, green, blue))
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x + (50 * size), y - (50 * size), z + (50 * size), x + (50 * size), y - (50 * size), z, effect_time, red, green, blue))
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x + (50 * size), y - (50 * size), z, x, y - (50 * size), z, effect_time, red, green, blue))
           
            es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s %s %s 255' % (x, y, z + (50 * size), x, y - (50 * size), z + (50 * size), effect_time, red, green, blue))
           
        def Laser(self, x, y, z, effect_time):
            """ Makes a laser effect """
            colors = ('255 0 0', '0 255 0', '0 0 255', '255 255 0', '255 0 255', '0 255 255')
            a = -24
            while a <= 24:
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x, y + (a / 5), z, x, y + a, z + 20, effect_time, random.choice(colors)))
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x + (a /5), y, z, x + a, y, z + 20, effect_time, random.choice(colors)))
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x + (a / 5), y + (a / 5), z, x + a, y + a, z + 20, effect_time, random.choice(colors)))
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x + (a / 5), y - (a / 5), z, x + a, y - a, z + 20, effect_time, random.choice(colors)))
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x, y + (a / 5), z, x, y + a, z - 20, effect_time, random.choice(colors)))
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x + (a /5), y, z, x + a, y, z - 20, effect_time, random.choice(colors)))
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x + (a / 5), y + (a / 5), z, x + a, y + a, z - 20, effect_time, random.choice(colors)))
                es.server.queuecmd('est_effect 3 #a 0 "sprites/lgtning.vmt" %s %s %s %s %s %s %s 4 3 %s 255' % (x + (a / 5), y - (a / 5), z, x + a, y - a, z - 20, effect_time, random.choice(colors)))
                a += 12
     
    def effect_loop(loc, lightning_time, lightning_range, damage, effect_time, attacker, team):
        """ Creates a loop to do the Lightning effect """
        if effect_time <= lightning_time:
            random1 = random.randint(lightning_range * -1, lightning_range)
            random2 = random.randint(lightning_range * -1, lightning_range)
            es.server.queuecmd('est_effect 3 #all 0 sprites/lgtning.vmt %s %s %s %s %s %s 1 10 20 40 250 255 255'%(loc[0] + random1, loc[1] + random2, loc[2], loc[0] + random1, loc[1] + random2, loc[2] + 120))
            effect_time += 0.03
            if damage:
                Command(attacker).NearCoord(loc[0] + random1, loc[1] + random2, loc[2], 45, 45, 45, lightning_damage, team)
            gamethread.delayedname(0.03, 'effect_%s'%attacker, effect_loop, args=(loc, lightning_time, lightning_range, damage, effect_time, attacker, team))
            
    def lightning_damage(userid, attacker):
        """ Creates a lighting effect around the user, lots of lighting bolts """
        random_number  = (random.randint(1, 6) * random.randint(1, 6)) - random.randint(1, 10)
        random_number2 = (random.randint(1, 7) * random.randint(1, 7)) - random.randint(1, 10)
        random_number3 = (random.randint(1, 7) * random.randint(1, 7)) - random.randint(1, 10)
        if random_number > 0:
            es.server.queuecmd('damage %s %s 32 %s'%(userid, random_number, attacker))
            es.tell(attacker, '#multi', '#greenYou have dealt #lightgreen%s #greendamage to #lightgreen%s'%(random_number, playerlib.getPlayer(userid).attributes['name']))
        else:
            if random_number2 > 0:
                es.server.queuecmd('damage %s %s 32 %s'%(userid, random_number2, attacker))
                es.tell(attacker, '#multi', '#greenYou have dealt #lightgreen%s #greendamage to #lightgreen%s'%(random_number2, playerlib.getPlayer(userid).attributes['name']))
            else:
                es.server.queuecmd('damage %s %s 32 %s'%(userid, random_number3, attacker))
                es.tell(attacker, '#multi', '#greenYou have dealt #lightgreen%s #greendamage to #lightgreen%s'%(random_number3, playerlib.getPlayer(userid).attributes['name']))
                
    def effect_loop2(loc, effect_time, red, green, blue, height, beam_time):
        """ Creates a loop to do the ring5 effect """
        if effect_time >= 0:
            es.server.queuecmd('est_effect 10 #all 0 "sprites/lgtning.vmt" %s %s %s 90 100 1 8 10 8 40 240 255 255 10'%(loc[0], loc[1], loc[2] + height))
            height += 10
            effect_time -= float(beam_time) / 12
            gamethread.delayed(float(beam_time / 12), effect_loop2, args=(loc, effect_time, red, green, blue, height, beam_time))
            
def Effect():
    """ Quick wrapper just to ensure backwards compatibility... Return the effect variable
        so it's the only 1 instance. """
    return effect
    
""" This is just a python var to ensure there is only ever 1 instance of the Effect_Effect() class... """
effect = Effect_Effect()
        
command_instances = {}
def Command(userid, printThing = True):
    """ Command to ensure that there is only ever 1 instance per player... If the user
        doesn't have an instance within the dictionary, create one. Finally return
        the players instance. """
    userid = str(userid)
    if not command_instances.has_key(userid):
        command_instances[userid] = CommandManager(userid)
    player = command_instances[userid]
    if printThing is not False:
        player.PrintDebug()
    return player

es.keygroupcreate('WCSuserdata')
dict_commands = {}
safe_queue    = []
dict_commands['delay list'] = []
class CommandManager:
    """ A class to control all the player's commands. It keeps lots of values
        so all values can be retrieved, modified and changed internally and 
        externally. """
    def __init__(self, userid):
        """ This method is ran when an instance is initialized. Set the default values. """
        self.userid = int(es.getuserid(userid))
        if not dict_commands.has_key(self.userid):
            dict_commands[self.userid] = {}
            self.key                   = dict_commands[self.userid]
            self.key['UltiBlock']      = 0
            self.key['jump multi']     = 1.0
            self.key['AbilBlock']      = 0
            self.key['RegenLoop']      = 0
            self.key['RegenAmount']    = 0
            self.key['RegenDelay']     = 0
            self.key['Gravity']        = 1.0
            self.key['DrainLoop']      = 0
            self.key['MaxHealth']      = 100
            self.key['MaxArmor']       = 0
            self.key['Speed']          = 1.0
            self.key['CoolDownTime']   = {'start':0, 'CoolTime':0}
            self.key['Alpha']          = 255
            self.key['AlphaLoop']      = 0
            self.key['DefaultGrav']    = 0
            self.key['delay list']     = []
            self.key['CoolDownDeath']  = 0
            self.key['Cash']           = 2500
            self.key['items']          = []
            self.key['Restricted']     = []
            self.key['printTime']      = 0
            es.keycreate('WCSuserdata', self.userid)
            es.keysetvalue('WCSuserdata', self.userid, 'gravity',      1.0)
            es.keysetvalue('WCSuserdata', self.userid, 'speed',        1.0)
            es.keysetvalue('WCSuserdata', self.userid, 'longjump',     1.0)
            es.keysetvalue('WCSuserdata', self.userid, 'race',         GetRace(self.userid))
            es.keysetvalue('WCSuserdata', self.userid, 'regeneration', 0)
        self.key = dict_commands[self.userid]
        
    def __setitem__(self, key, value):
        """ Short internal command to make the Command(userid) instance dictionary like """
        self.UpdateDict(key, value)
        
    def __getitem__(self, key):
        """ Short internal command to make the Command(userid) instance dictionary like """
        return self.ReturnDict(key)
        
    def __delitem__(self, key):
        if key not in self.key:
            return
        del self.key[key]
        
    def __contains__(self, key):
        return key in self.key
        
    def __iter__(self):
        return self.key.iterkeys()
        
    def __eq__(self, player):
        return bool(self.userid == int(player))
        
    def PrintDebug(self):
        if int(es.ServerVar('wcs_debug')) >= 3:
            if time.time() - self.ReturnDict('printTime') > 2:
                debugMsg(3, "\nPlayer %s's key:\n--------------------------------" % (es.getplayername(self.userid) ) )
                for key in self.key:
                    debugMsg(3, "%s - %s"% (key, self.key[key]) )
                debugMsg(3, "--------------------------------\n")
                self.UpdateDict('printTime', time.time() )
        
    def HudHint(self, text):
        """ A short wrapper to make HudHints compatible with HL2 as well... """
        if not es.exists('userid', self.userid):
            return
        if dir in ("hl2mp", 'tf'):
            '''
            def hudmsg(users,msg,channel=1,x=-1,y=-1,
            r1=255,g1=255,b1=255,a1=255,r2=255,g2=255,b2=255,a2=255,
            effect=0,fadein=0.1,fadeout=0.1,holdtime=4.0,fxtime=0.0):
            '''
            es.usermsg('create','hudmsg','HudMsg')
            es.usermsg('write','byte','hudmsg', 1 & 0xff)
            es.usermsg('write','float', 'hudmsg', -1)
            es.usermsg('write','float', 'hudmsg', 0.75)
            es.usermsg('write','byte', 'hudmsg', 255)
            es.usermsg('write','byte', 'hudmsg', 0)
            es.usermsg('write','byte', 'hudmsg', 0)
            es.usermsg('write','byte', 'hudmsg', 255)
            es.usermsg('write','byte', 'hudmsg', 255)
            es.usermsg('write','byte', 'hudmsg', 0)
            es.usermsg('write','byte', 'hudmsg', 0)
            es.usermsg('write','byte', 'hudmsg', 255)
            es.usermsg('write','byte', 'hudmsg', 0)
            es.usermsg('write','float', 'hudmsg', 0.1)
            es.usermsg('write','float', 'hudmsg', 0.1)
            es.usermsg('write','float', 'hudmsg', 4)
            es.usermsg('write','float', 'hudmsg', 0.0)
            es.usermsg('write','string', 'hudmsg', text)
            es.usermsg('send','hudmsg', self.userid)
            es.usermsg('delete','hudmsg')
        else:
            es.usermsg('create','hudhint','HintText')
            es.usermsg('write','short','hudhint',-1)
            es.usermsg('write','string','hudhint',text)
            es.usermsg('send','hudhint',self.userid)
            es.usermsg('delete','hudhint')
            
    def AddItem(self, item):
        """ Adds an item to the players dict['items'] key """
        self.key['items'].append(item)
        
    def RemoveItem(self, item, count=None):
        if count is None:
            count = self.GetItemCount(item)
        while count:
            if item in self.key['items']:
                self.key['items'].remove(item)
            count -= 1
        
    def GetItemCount(self, item):
        count = self.key['items'].count(item)
        return count
        
    def doblock(self, block, command, args, send=False):
        """ A wrapper to wrap queuecmd's which accept 3 variables (e.g. x,y,z or yaw, pitch, roll) """
        if not send:
            for x in ('x', 'y', 'z'):
                es.ServerVar(x).set(0)
            es.server.queuecmd(command)
            gamethread.delayed(0, self.doblock, (block, command, args, True))
        elif callable(block):
            block(self.userid, str(es.ServerVar('x')), str(es.ServerVar('y')), str(es.ServerVar('z')), *args)
            #else:
                #gamethread.delayed(0, block, (self.userid, es.ServerVar('x'), es.ServerVar('y'), es.ServerVar('z')))
        
    def Distance(self, target):
        """ Returns the distance between 2 players in game units """
        if not es.exists('userid', self.userid):
            return
        x,   y,  z = es.getplayerlocation(self.userid)
        xx, yy, zz = es.getplayerlocation(target)
        return (((x - xx) ** 2 + (y - yy) ** 2 + (z - zz) ** 2) ** 0.5)
        
    def BeaconTimed(self, duration):
        """ Creates a beacon loop, so it iterates every 'duration' """
        if not es.exists('userid', self.userid):
            return
        while duration > 0:
            self.Delayed(duration,self.Beacon)
            duration -= 1
            
    def Beacon(self):
        """ Creates a beacon around the player """
        if not es.exists('userid', self.userid):
            return
        x,y,z = es.getplayerlocation(self.userid)
        effect.RingCustom('#a', 0, 'sprites/purpleglow1.vmt', x, y, z + 35, 100, 350, .5, 4, 2, 2, 255, 0, 0, 255, 100)
        es.emitsound('player',self.userid,'buttons/blip2.wav',1.0,0.7)
        
    def BlockUlti(self, duration):
        """ Blocks the user from using their ultimate """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            self.key['UltiBlock'] = 1
            if duration:
                gamethread.delayed(duration,self.UpdateDict,('UltiBlock',0))
                
    def BlockAbil(self, duration):
        """ Blocks the user from using their ability """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            self.key['AbilBlock'] = 1
            if duration:
                gamethread.delayed(duration,self.UpdateDict,('AbilBlock',0))
                
    def ReturnUserKey(self):
        """ Returns the player's dictionary """
        if dict_commands.has_key(self.userid): 
            return self.key
        return {}
        
    def SetCoolDown(self, skill,amount):
        """ Sets a time limit before a user can use that skill again """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            self.key['CoolDownTime'][skill] = {}
            self.key['CoolDownTime'][skill]['start']    = time.time()
            self.key['CoolDownTime'][skill]['CoolTime'] = float(amount)
            
    def GetCoolDown(self, skill):
        """ Returns the time left (in rounded seconds) before a user can use their cooldown again """
        if not es.exists('userid', self.userid):
            return True
        if dict_commands.has_key(self.userid):
            if self.key['CoolDownTime'].has_key(skill):
                startcd = self.key['CoolDownTime'][skill]['start']
                now = time.time()
                time_elapsed = now - startcd
                if time_elapsed <= self.key['CoolDownTime'][skill]['CoolTime']: return int(round((self.key['CoolDownTime'][skill]['CoolTime'] - time_elapsed)))
            return 0
            
    def ResetDefault(self):
        """ Sets all the values in the player's dict to their default values. """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            self.key['UltiBlock']      = 0
            self.key['jump multi']     = 1.0
            self.key['AbilBlock']      = 0
            self.key['RegenLoop']      = 0
            self.key['RegenAmount']    = 0
            self.key['RegenDelay']     = 0
            self.key['Gravity']        = 1.0
            self.key['DrainLoop']      = 0
            self.key['MaxHealth']      = 100
            self.key['MaxArmor']       = 0
            self.key['Speed']          = 1.0
            self.key['CoolDownTime']   = {'start':0, 'CoolTime':0}
            self.key['Alpha']          = 255
            self.key['AlphaLoop']      = 0
            self.key['DefaultGrav']    = 1
            self.key['delay list']     = []
            self.key['Cash']           = 2500
            if 'Pirates' in game:
                self.key['MaxArmor']   = es.getplayerprop(self.userid,'CBasePlayer.m_iArmor')
            else:
                self.key['MaxArmor']   = 0
            self.key['printTime']      = 0
            es.keysetvalue('WCSuserdata', self.userid, 'gravity', 1.0)
            es.keysetvalue('WCSuserdata', self.userid, 'speed', 1.0)
            es.keysetvalue('WCSuserdata', self.userid, 'longjump', 1.0)
            es.keysetvalue('WCSuserdata', self.userid, 'race', GetRace(self.userid))
            es.keysetvalue('WCSuserdata', self.userid, 'regeneration', 0)
            
    def UpdateDict(self, key, value):
        """ Creates/Sets a new value of a key in the player's dict """
        if dict_commands.has_key(self.userid):
            # Overwrites/sets a new value for a dict
            self.key[key] = value
            
    def ReturnDict(self, key):
        """ Returns the value in the player's dict """
        if dict_commands.has_key(self.userid):
            # Returns a value to a local variable
            if self.key.has_key(key): 
                return self.key[key]
            elif key == 'items':
                return []
            return None
            
    def ModDict(self, key, value):
        """ Adds a value to a key inside the players dict """
        if dict_commands.has_key(self.userid):
            # Adds a value to the dict
            if self.key.has_key(key):
                self.key[key] += int(value)
            else: 
                debugMsg(0,'WCS ERROR: There is no key in dict_commands called %s'%key)
                
    def Regen(self, AmountPerDelay, Delay, stop=False, start=True):
        """ Begins a regeneration loop, looping every <delay> seconds and healing <AmountPerDelay> each iteration """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            self.key['RegenAmount'] = AmountPerDelay
            self.key['RegenDelay']  = Delay
            if start:
                self.key['RegenLoop'] = 1
                es.keysetvalue('WCSuserdata', self.userid, 'regeneration', 1)
            if self.key['RegenLoop']:
                if es.exists('userid',self.userid):
                    health    = es.getplayerprop(self.userid,'CBasePlayer.m_iHealth')
                    health   += int(AmountPerDelay)
                    MaxHealth = self.key['MaxHealth']
                    if health <= int(MaxHealth) and not es.getplayerprop(self.userid, 'CBasePlayer.pl.deadflag'):
                        if stop:
                            if health <= stop:
                                es.setplayerprop(self.userid, 'CBasePlayer.m_iHealth', health)
                                gamethread.delayed(float(Delay), 'regen_%s' % self.userid, self.Regen, (AmountPerDelay, Delay, stop, False) )
                            else:
                                es.setplayerprop(self.userid, 'CBasePlayer.m_iHealth', MaxHealth)
                                self.key['RegenLoop'] = 0        
                                es.keysetvalue('WCSuserdata', self.userid, 'regeneration', 0)
                        else:
                            es.setplayerprop(self.userid, 'CBasePlayer.m_iHealth', health)
                            gamethread.delayedname(float(Delay), 'regen_%s' % self.userid, self.Regen, (AmountPerDelay, Delay, stop, False) )        
                    else:
                        es.setplayerprop(self.userid, 'CBasePlayer.m_iHealth', MaxHealth)
                        self.key['RegenLoop'] = 0
                        es.keysetvalue('WCSuserdata', self.userid, 'regeneration', 0)
                        
    def StopRegen(self):
        if not es.exists('userid', self.userid):
            return
        gamethread.cancelDelayed('regen_%s' % self.userid)
        self.key['RegenLoop'] = 0
        es.keysetvalue('WCSuserdata', self.userid, 'regeneration', 0)
                        
    def Damage(self, AmountOfDamage, DamageType=32, Attacker=0):
        """ Damages a player... If the health is less than the damage, damage them, else 'de-heal' them so it's not a damage loop """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if es.getplayerprop(self.userid,'CBasePlayer.m_iHealth') <= AmountOfDamage:
                es.server.queuecmd('damage %s %s %s %s'%(self.userid, AmountOfDamage, DamageType, Attacker))
            else:
                self.Heal(AmountOfDamage*(-1))
                
    def Color(self, cColor=None, red=255, green=255, blue=255, alpha=255):
        """ Changes the players color to either a defined color, or to a rgba value. """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if cColor:
                if colors.has_key(cColor):
                    if isEst:
                        r, g, b = colors[cColor]
                        es.server.queuecmd('est_setplayercolor %s %s %s %s %s 1' % (self.userid, r, g, b, alpha) )
                    else:
                        r, g, b  = map(int, colors[cColor])
                        
                        if alpha > 255:
                            alpha = 255
                        if alpha < 0:
                            alpha = 0
                                                
                        color  = int(r)
                        color += int(g)     << 8
                        color += int(b)     << 16
                        color += int(alpha) << 24
                        
                        if color >= 2**31: 
                            color -= 2**32
                        oldRenderMode = es.getplayerprop(self.userid, "CBaseEntity.m_nRenderMode")
                        oldRenderFX   = es.getplayerprop(self.userid, "CBaseEntity.m_nRenderFX")
                        newRenderMode = oldRenderMode | 1
                        newRenderFX   = oldRenderFX | 256
                        es.setplayerprop(self.userid, "CBaseEntity.m_nRenderMode", newRenderMode)
                        es.setplayerprop(self.userid, "CBaseEntity.m_nRenderFX", newRenderFX)
                        es.setplayerprop(self.userid, "CBaseEntity.m_clrRender", color)
                        for entity in es.createentitylist(playerlib.getPlayer(self.userid).get("weapon")):
                            if es.getplayerhandle(self.userid) == es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity'):
                                oldRenderMode = es.getindexprop(entity, "CBaseEntity.m_nRenderMode")
                                oldRenderFX   = es.getindexprop(entity, "CBaseEntity.m_nRenderFX")
                                newRenderMode = oldRenderMode | 1
                                newRenderFX   = oldRenderFX | 256
                                es.setindexprop(entity, "CBaseEntity.m_nRenderMode", newRenderMode)
                                es.setindexprop(entity, "CBaseEntity.m_nRenderFX", newRenderFX)
                                es.setindexprop(entity, "CBaseEntity.m_clrRender", color)
                                break
                        
                    self.key['Alpha'] = alpha
                else:
                    debugMsg(0,'WCS ERROR: No color named %s'%cColor)
            else:
                if isEst:
                    es.server.queuecmd('est_setplayercolor %s %s %s %s %s 1' % (self.userid, red, green, blue, alpha) )
                else:
                    
                    if alpha > 255:
                        alpha = 255
                    if alpha < 0:
                        alpha = 0
                
                    color  = int(red)
                    color += int(green) << 8
                    color += int(blue)  << 16
                    color += int(alpha) << 24
                    if color >= 2**31: 
                        color -= 2**32
                    oldRenderMode = es.getplayerprop(self.userid, "CBaseEntity.m_nRenderMode")
                    oldRenderFX   = es.getplayerprop(self.userid, "CBaseEntity.m_nRenderFX")
                    newRenderMode = oldRenderMode | 1
                    newRenderFX   = oldRenderFX | 256
                    es.setplayerprop(self.userid, "CBaseEntity.m_nRenderMode", newRenderMode)
                    es.setplayerprop(self.userid, "CBaseEntity.m_nRenderFX", newRenderFX)
                    es.setplayerprop(self.userid, "CBaseEntity.m_clrRender", color)
                    for entity in es.createentitylist(playerlib.getPlayer(self.userid).get("weapon")):
                        if es.getplayerhandle(self.userid) == es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity'):
                            oldRenderMode = es.getindexprop(entity, "CBaseEntity.m_nRenderMode")
                            oldRenderFX   = es.getindexprop(entity, "CBaseEntity.m_nRenderFX")
                            newRenderMode = oldRenderMode | 1
                            newRenderFX   = oldRenderFX | 256
                            es.setindexprop(entity, "CBaseEntity.m_nRenderMode", newRenderMode)
                            es.setindexprop(entity, "CBaseEntity.m_nRenderFX", newRenderFX)
                            es.setindexprop(entity, "CBaseEntity.m_clrRender", color)
                            break
                self.key['Alpha'] = alpha
                
    def Fade(self, Alpha, Length):
        """ Begins fading the players alpha. FInds out if the alpha changing to is
            greater than or less than; if greater, find out over how long the fade is
            do a devision and create a loop to add that every X iterations, else do
            the same thing, but deduct it instead. """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            sAlpha = self.key['Alpha']
            self.key['AlphaLoop'] = 0
            if sAlpha >= Alpha: 
                tAlphaChange  = sAlpha - Alpha
                tAlphaChange /= float(Length) # each second will fade this much
                tAlphaChange  = int( round( tAlphaChange / 10.0) ) # get milliseconds
                self.key['AlphaLoop'] = Length * 10
                gamethread.delayed(0.1, fadeplayer, (self.userid, tAlphaChange, False) )
            else: 
                tAlphaChange  = Alpha - sAlpha
                tAlphaChange /= float(Length) # each second will fade this much
                tAlphaChange  = int( round( tAlphaChange / 10.0) ) # get milliseconds
                self.key['AlphaLoop'] = Length * 10
                gamethread.delayed(0.1, fadeplayer, (self.userid, tAlphaChange, True) )
                
    def Freeze(self, delay = None):
        """ Freezes a player for X seconds. """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            playerlib.getPlayer(self.userid).set("freeze", 1)
            if delay:
                gamethread.delayed(float(delay), self.UnFreeze)
        else:
            debugMsg(0,'WCS ERROR: Cannot delay \'freeze\' command for %s seconds!'%delay)
            
    def UnFreeze(self):
        """ This is just a short wrapper to unfreeze a frozen player """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            playerlib.getPlayer(self.userid).set("freeze", 0)
            
    def God(self, delay = 0):
        """ Turns a player god for X seconds. """
        if not es.exists('userid', self.userid):
            return
        if isEst:
            es.server.queuecmd('est_god %s 1'%self.userid)
        else:
            es.setplayerprop(self.userid, "CBaseAnimating.m_nHitboxSet", 2)
        if float(delay):
            gamethread.delayed(float(delay), self.UnGod)
            
    def UnGod(self):
        if not es.exists('userid', self.userid):
            return
        if isEst:
            es.server.queuecmd('est_god %s 0'%self.userid)
        else:
            es.setplayerprop(self.userid, "CBaseAnimating.m_nHitboxSet", 0)
            
    def Blind(self, delay, alpha=255, type = 2, red = 0, green = 0, blue = 0):
        """ Blinds a player with X alpha for X seconds """
        if not es.exists('userid', self.userid):
            return
        if delay and not self.IsDead():
            if isEst:
                es.server.queuecmd('est_Fade %s %s 0 %s %s %s %s %s'%(self.userid, type, delay, red, green, blue, alpha))
            else:
                self.UpdateBlind(time.time() + delay, alpha, type, red, green, blue)
        else:
            debugMsg(0, 'WCS ERROR: Cannot delay \'Blind\' command for %s seconds!'%delay)
            
    def UpdateBlind(self, totalTime, alpha, type = 2, red = 0, green = 0, blue = 0):
        if not es.exists('userid', self.userid):
            return
        if time.time() < totalTime:
            es.usermsg('create', 'fade', 'Fade')
            es.usermsg('write', 'short', 'fade', 5)    # Frames To fade 
            es.usermsg('write', 'short', 'fade', 45)   # Frames to stay faded as
            es.usermsg('write', 'short', 'fade', type) # No Fade(0), out(1), in(2)
            es.usermsg('write', 'byte', 'fade', red)   # Red
            es.usermsg('write', 'byte', 'fade', green) # Green
            es.usermsg('write', 'byte', 'fade', blue)  # Blue
            es.usermsg('write', 'byte', 'fade', alpha) # Alpha
            es.usermsg('send', 'fade', self.userid)
            es.usermsg('delete', 'fade')
            self.Delayed(0.1, self.UpdateBlind, (totalTime, alpha), True)
            
    def Burn(self, delay):
        """ Burns a player for X seconds """
        if not es.exists('userid', self.userid):
            return
        if isOb:
            es.fire(self.userid, '!self', 'ignite')
        else:
            es.server.queuecmd('es_xfire %s !self ignite' % self.userid)
        if delay:
            gamethread.delayed(delay, self.UnBurn)

    def UnBurn(self):
        if not es.exists('userid', self.userid):
            return
        flameList = es.createentitylist("entityflame") 
        handle    = es.getplayerhandle(self.userid) 
        for flameEntity in flameList: 
            string = es.getindexprop(flameEntity, 'CEntityFlame.m_hEntAttached') 
            if string == handle: 
                es.setindexprop(flameEntity, 'CEntityFlame.m_flLifetime', 0) 
                break
            
    def ChangeGravity(self, amount):
        """ Adds/Takes away a value from the player's current gravity and updates their internal dictionary """
        if not es.exists('userid', self.userid):
            return
        amount = float(amount)
        if abs(amount):
            if dict_commands[self.userid]['DefaultGrav']:
                current_grav = dict_commands[self.userid]['Gravity']
                current_grav += amount
                if current_grav:
                    es.server.queuecmd('gravity %s %s'%(self.userid,current_grav))
                    dict_commands[self.userid]['Gravity'] = current_grav
                    es.keysetvalue('WCSuserdata', self.userid, 'gravity', current_grav)
                else:
                    debugMsg(0,'WCS ERROR: Cannot change %s\'s gravity to %s'%(es.getplayername(self.userid),current_grav))
            else:
                gamethread.delayed(0.1, self.ChangeGravity, (amount) )
        else:
            debugMsg(0,'WCS ERROR: Cannot alter the ChangeGravity skill with a value of 0')
                
    def SetGravity(self, amount):
        """ Sets a players gravity and updates the player's internal dictionary """
        if not es.exists('userid', self.userid):
            return
        amount = float(amount)
        if amount:
            if dict_commands[self.userid]['DefaultGrav']:
                dict_commands[self.userid]['Gravity'] = amount
                es.keysetvalue('WCSuserdata', self.userid, 'gravity', amount)
                es.server.queuecmd('gravity %s %s'%(self.userid, amount))
            else:
                gamethread.delayed(0.1, self.SetGravity, (amount) )
        else:
                debugMsg(0,'WCS ERROR: Cannot change %s\'s gravity to %s'%(es.getplayername(self.userid),amount))
                
    def Speed(self, amount):
        """ Sets a new value to their speed and updates the player's internal dictionary """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            amount = float(amount)
            if amount:
                dict_commands[self.userid]['Speed'] = amount
                es.setplayerprop(self.userid, 'CBasePlayer.localdata.m_flLaggedMovementValue', amount)
                es.keysetvalue('WCSuserdata', self.userid, 'speed', amount)
            else:
                debugMsg(0,'WCS ERROR: Cannot change %s\'s speed to %s'%(es.getplayername(self.userid), amount))
                
    def SpeedAdd(self, amount):
        """ Adds a value to their current speed and updates the players internal dictionary """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            amount = float(amount)
            if abs(amount):
                speed = self.key['Speed']
                speed += amount
                self.key['Speed'] = speed
                es.keysetvalue('WCSuserdata', self.userid, 'speed', speed)
                self.Speed(speed)
            else:
                debugMsg(0,'WCS ERROR: Cannot add %s speed to %s'%(amount,es.getplayername(self.userid)))
                
    def Heal(self, amount):
        """ Adds some health to the currents health, but DOESNT update the players maximum health """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            health = es.getplayerprop(self.userid, 'CBasePlayer.m_iHealth')
            health += amount
            max_health = dict_commands[self.userid]['MaxHealth']
            if health <= max_health:
                es.setplayerprop(self.userid, 'CBasePlayer.m_iHealth',health)
            else:
                es.setplayerprop(self.userid,'CBasePlayer.m_iHealth',max_health)
                
    def Health(self, amount):
        """ Changes the current health of the player, and updates the internal dictionary to hold the new value """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if amount:
                dict_commands[self.userid]['MaxHealth'] = amount
                es.setplayerprop(self.userid,'CBasePlayer.m_iHealth',amount)
                if 'Pirates' in game:
                    es.setplayerprop(self.userid,'CBasePlayer.m_iMaxHealth',amount)
            else:
                debugMsg(0,'WCS ERROR: Cannot change %s\'s health to %s'%(es.getplayername(self.userid), amount))
                
    def HealthAdd(self, amount):
        """ Adds health to the current maximum health, and updates the internal dictionary to hold the new value """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if abs(amount):
                props = ['CBasePlayer.m_iHealth']
                if 'Pirates' in game:
                    props.append('CBasePlayer.m_iMaxHealth')
                for prop in props:
                    cur_health = es.getplayerprop(self.userid,prop)
                    cur_health += amount
                    if cur_health > 0:
                        dict_commands[self.userid]['MaxHealth'] = cur_health
                        es.setplayerprop(self.userid, prop, cur_health)
                    else:
                        debugMsg(0,'WCS ERROR: Cannot change %s\'s health to %s'%(es.getplayername(self.userid), cur_health))
            else:
                debugMsg(0,'WCS ERROR: Cannot add %s health to %s'%(amount,es.getplayername(self.userid)))
                
    def SaveLife(self,amount):
        """ Exact same as AddHealth except it doesn't change the internal dictionary """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if amount > 0:
                es.setplayerprop(self.userid, 'CBasePlayer.m_iHealth' , es.getplayerprop(self.userid,'CBasePlayer.m_iHealth') + int(amount) )
                
    def Armor(self, amount, max=0):
        """ Sets the players armor to a new value """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if amount:
                dict_commands[self.userid]['MaxArmor'] = amount
                if game == 'Counter-Strike: Source':
                    es.setplayerprop(self.userid,'CCSPlayer.m_ArmorValue',amount)
                elif 'Deathmatch' in game:
                    es.setplayerprop(self.userid,'CHL2MP_Player.baseclass.m_HL2Local.m_flSuitPower',amount)
                elif 'Pirates' in game:
                    if max:
                        es.setplayerprop(self.userid,'CPVK2Player.m_iMaxArmor',amount)
                    es.setplayerprop(self.userid,'CPVK2Player.m_Armor',amount)
            else:
                debugMsg(0,'WCS ERROR: Cannot change %s\'s armor to %s'%(es.getplayername(self.userid),amount))
                
    def ArmorAdd(self, amount, max=0):
        """ Add armor to the players current armor """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if abs(amount):
                if game == 'Counter-Strike: Source':
                    prop = 'CCSPlayer.m_ArmorValue'
                elif 'Deathmatch' in game:
                    prop = 'CHL2MP_Player.baseclass.m_HL2Local.m_flSuitPower'
                elif 'Pirates' in game:
                    prop = 'CPVK2Player.m_ArmorValue'
                cur_armor = es.getplayerprop(self.userid, prop)
                cur_armor += int(amount)
                if cur_armor < 0: 
                    cur_armor = 0
                es.setplayerprop(self.userid, prop, cur_armor)
                if max:
                    prop = 'CPVK2Player.m_iMaxArmor'
                    cur_armor = es.getplayerprop(self.userid, prop)
                    cur_armor += int(amount)
                    if cur_armor < 0: 
                        cur_armor = 0
                    es.setplayerprop(self.userid, prop, curarmor)
            else:
                debugMsg(0,'WCS ERROR: Cannot add %s armor to %s'%(amount,es.getplayername(self.userid)))
                
    def Clip(self, amount, slot):
        """ Set the players clip with the weapon in slot <slot> """
        if not es.exists('userid', self.userid):
            return
        a = playerlib.getPlayer(self.userid)
        a.set('clip', [str(slot), amount])
        
    def ClipAdd(self, amount, slot):
        """ Add the players clip with the weapon in slot <slot> """
        if not es.exists('userid', self.userid):
            return
        a = playerlib.getPlayer(self.userid)
        clip = int(a.get('clip',str(slot)))
        clip += amount
        a.set('clip', [str(slot), clip])
        
    def Ammo(self, amount, slot):
        """ Set the players ammo with the weapon in slot <slot> """
        if not es.exists('userid', self.userid):
            return
        a = playerlib.getPlayer(self.userid)
        a.set('ammo', [str(slot), amount])
        
    def AmmoAdd(self, amount, slot):
        """ Add ammo to the players slot """
        if not es.exists('userid', self.userid):
            return
        a = playerlib.getPlayer(self.userid)
        ammo = int(a.get('ammo',str(slot)))
        ammo += amount
        a.set('ammo', [str(slot), amount])
        
    def Drain(self, damage, delay, time, Attacker=None):
        """ Begin a drain... This command takes health off a player every x seconds """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid) and not self.IsDead():
            if (time-delay) >= 0:
                self.Damage(damage,32,Attacker)
                self.Delayed(delay, self.Drain, (damage,delay,time-delay,Attacker))
                
    def ResetDrain(self):
        """ Resets the drain key to 0 and stops the current drain """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            self.key['DrainLoop'] = 0
            
    def Drop(self):
        """ Force a player to drop their weapons """
        if not es.exists('userid', self.userid):
            return
        es.sexec(self.userid,'drop')
        
    def Drug(self,time=None):
        """ Drug the player for x seconds """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead(): 
            if isEst:
                es.server.queuecmd('est_Drug %s %s'%(self.userid,time))
            else:
                es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', 155)
                if time is not None:
                    gamethread.delayed(time, self.UnDrug)
                    
    def UnDrug(self):
        """ Set the players FOV back to it's original """
        if not es.exists('userid', self.userid):
            return
        es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', 90)
        
    def Drunk(self, delay=None):
        """ 'Drunk' the player for X seconds """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead(): 
            if isEst:
                es.server.queuecmd('est_Drunk %s %s'%(self.userid,time))
            else:
                self.DrunkLoop(time.time() + delay)
                
    def DrunkLoop(self, totalTime, boolDown = True):
        """ A small method to get the current FOV of the player, then
            either plus or deduct a value of 10 from it """
        if not es.exists('userid', self.userid):
            return
        if time.time() <= totalTime:
            fov = es.getplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV')
            if 40 < fov < 90:
                if boolDown:
                    fov -= 10
                else:
                    fov += 10
            elif fov == 40:
                fov += 10
                boolDown = False
            elif fov == 90:
                boolDown = True
                fov -= 10
            es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', fov)
            self.Delayed(0.2, self.DrunkLoop, (totalTime, boolDown), True)
        else:
            es.setplayerprop(self.userid, 'CBasePlayer.m_iDefaultFOV', 90)
        
    def GetTeleSafe(self, x, y, z, callback=False, *args):
        """ Returns if the spot the player is looking at is safe to teleport or not """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                if not callback:
                    if isOb:
                        es.server.est_TeleportSafe(wcs_x, "%s,%s,%s" % (x, y, z), 1)
                    else:
                        debugMsg(0, 'Race %s is not very linux friendly. Tell the race owner to update his command to the new GetTeleSafe' % GetRace(self.userid))
                        es.server.cmd('est_TeleportSafe wcs_x "%s,%s,%s" 1'%(x,y,z))
                    return int(es.ServerVar('wcs_x'))
                else:
                    es.ServerVar('isSafe').set(0)
                    safe_queue.append((callback, args, self.userid))
                    es.server.queuecmd('est_TeleportSafe isSafe "%s,%s,%s" 1;es_xdoblock wcs/SafeReturnTeleport'%(x, y, z))
            else:
                raise ESTError, "GetTeleSafe requires EST, sorry"
            
    def _isSafeReturn(self, callback, isSafe, args):
        """ The 'middle' function so that the queuecmd can wait a tick before sending it's value """
        if not es.exists('userid', self.userid):
            return
        callback(self.userid, int(isSafe), *args)
        
    def GetWallBetween(self, id1, callback=False, *args):
        """ Returns if there is a wall between 2 people """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                if not callback:
                    x, y, z    = es.getplayerlocation(id1)
                    xx, yy, zz = es.getplayerlocation(self.userid)
                    if isOb:
                        es.server.est_GetWallBetween('isWallBetween', x, y, z, xx, yy, zz)
                    else:
                        debugMsg(0, 'Race %s is not very linux friendly. Tell the race owner to update his command to the new GetWallBetween' % GetRace(self.userid))
                        es.server.cmd('est_GetWallBetween isWallBetween %s %s %s %s %s %s'%(x, y, z, xx, yy, zz) )
                    return int(es.ServerVar('wcs_x'))
                else:
                    es.ServerVar('isWallBetween').set(0)
                    x, y, z    = es.getplayerlocation(id1)
                    xx, yy, zz = es.getplayerlocation(self.userid)
                    safe_queue.append((callback, args, self.userid)) 
                    es.server.queuecmd('est_GetWallBetween isWallBetween %s %s %s %s %s %s;es_xdoblock wcs/SafeReturnWall'%(x, y, z, xx, yy, zz) )
            else:
                raise ESTError, "GetWallBetween requires EST, sorry"
        
    def _isWallBetween(self, callback, isWallBetween, args):
        """ The 'middle' function so that the queuecmd can wait a tick before sending it's value """
        if not es.exists('userid', self.userid):
            return
        callback(self.userid, isWallBetween, *args)
            
    def GetViewAngles(self):
        """
        Returns a list of Pitch, Yaw, Roll
        Either use it in
        angles = wcs.Command(userid).GetViewAngles
        angles == [pitch, yaw, roll]
        or...
        pitch, yaw, roll = wcs.Command(userid).GetViewAngles
        """
        if not es.exists('userid', self.userid):
            return (0, 0, 0)
        if not self.IsDead():
            eyeAngleDict                           = {}
            eyeAngleDict['Team Fortress']          = "CTFPlayer.m_angEyeAngles[%s]"
            eyeAngleDict['Counter-Strike: Source'] = "CCSPlayer.m_angEyeAngles[%s]"
            eyeAngleDict['Day of Defeat: Source']  = "CDODPlayer.m_angEyeAngles[%s]"
            eyeAngleDict['Deathmatch']             = "CHL2MPPlayer.m_angEyeAngles[%s]"
            correctEyeAngles                       = [es.getplayerprop(self.userid, eyeAngleDict[es.getgame()] % x) for x in range(3)] 
            return map(float, correctEyeAngles)
            
    def GetViewCoord(self, callback=False, *args):
        """ Returns the co-ords which the user is looking at """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                if not callback:
                    if isOb:
                        es.server.est_GetViewCoord(self.userid, 'wcs_x', 'wcs_y', 'wcs_x')
                    else:
                        debugMsg(0, 'Race %s is not very linux friendly. Tell the race owner to update his command to the new GetViewCoord' % GetRace(self.userid))
                        es.server.cmd('est_GetViewCoord %s wcs_x wcs_y wcs_z'%self.userid)
                    return [float(es.ServerVar('wcs_x')), float(es.ServerVar('wcs_y')), float(es.ServerVar('wcs_z'))]
                elif callable(callback):
                    self.doblock(callback, 'est_GetViewCoord %s x y z'%self.userid, args)
            else:
                return playerlib.getPlayer(self.userid).get("viewcoord")
            
    def GetViewPlayer(self, callback=False, *args):
        """ Returns the player the user is looking at; if none, then return None """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                if not callback: 
                    """ wcs_x is a variable for the userid he is looking at """
                    if isOb:
                        es.server.est_GetViewPlayer(self.userid, 'wcs_x')
                    else:
                        debugMsg(0, 'Race %s is not very linux friendly. Tell the race owner to update his command to the new GetViewPlayer' % GetRace(self.userid))
                        es.server.cmd('est_GetViewPlayer %s wcs_x'%self.userid)
                    target = int(es.ServerVar('wcs_x'))
                    if target:
                        return target
                    return None
                else:
                    es.server.queuecmd('est_GetViewPlayer %s viewplayer'%self.userid)
                    gamethread.delayed(0, self._getExistsPlayer, (callback, es.ServerVar('viewplayer'), args ) )
            else:
                raise ESTError, "The command \'GetViewPlayer\' requires ESTools."
            
    def _getExistsPlayer(self, callback, player, args):
        """ This is a method that runs from a queuecmd so it doesn't dump linux boxes. """
        if not es.exists('userid', self.userid):
            return
        callback(self.userid, str(player), *args)
            
    def GetViewProp(self, callback=False, *args):
        """ Returns the prop index the user is looking at; if none, then return None """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                if not callback:
                    """ wcs_x is a variable for the prop index he is looking at """
                    if isOb:
                        es.server.est_GetViewProp(self.userid, 'wcs_x')
                    else:
                        debugMsg(0, 'Race %s is not very linux friendly. Tell the race owner to update his command to the new GetViewProp' % GetRace(self.userid))
                        es.server.cmd('est_GetViewProp %s wcs_x' % self.userid)
                    prop_index = int(es.ServerVar('wcs_x'))
                    if prop_index:
                        return prop_index
                    return None
                else:
                    es.ServerVar('prop').set(0)
                    es.server.queuecmd('est_GetViewProp %s prop' % self.userid,)
                    gamethread.delayed(0, self._getExistsProp, (callback, es.ServerVar('prop'), args ) )
            else:
                if callback is not False:
                    if isOb:
                        es.fire(self.userid, '!picker', 'color', "254 255 255")
                    else:
                        es.server.queuecmd('es_xfire %s !picker color "254 255 255"' % self.userid)
                    gamethread.delayed(0, gamethread.delayed, (0, self.checkProp, (callback, args) ) )
                else:
                    raise ESTError, "Because ESTools is not installed, this command requires a callback function."
                
    def checkProp(self, callback, args):
        """ Checks for all the props, and tests to see if the color value is (254 255 255 255)
            if so, then the player is looking at a prop. """
        if not es.exists('userid', self.userid):
            return
        for index in es.createentitylist():
            if es.getindexprop(index, "CBaseEntity.m_clrRender") == -2:
                es.setindexprop(index, "CBaseEntity.m_clrRender", -1)
                if callable(callback):
                    callback(index, *args)
                    return
        if callable(callback):
            callback(0, *args)
            
    def _getExistsProp(self, callback, prop, args):
        """ This is a method that runs from a queuecmd so it doesn't dump linux boxes. """
        if not es.exists('userid', self.userid):
            return
        callback(self.userid, str(prop), *args)
            
    def IsStuck(self, callbackFunction, *args, **kw):
        wcs.Command(userid).Push(0, 0, 10)
        gamethread.delayed(0.1, self._checkIsStuck, (es.getplayerlcoation(self.userid), callbackFunction, args, kw) )
        
    def _checkIsStuck(self, location, callbackFunction, args, kw):
        if callable(callbackFunction):
            callbackFunction(bool(location == es.getplayerlocation(self.userid)), self.userid, *args, **kw)
            
    def IsDead(self):
        """ Retuns whether or not the player is dead """
        if es.exists('userid', self.userid):
            return es.getplayerprop(self.userid,'CBasePlayer.pl.deadflag')
        return 1
        
    def ViewCone(self, filter, coneSize, coneDistance, method):
        """ Gets the viewcone of the player, and sends everyone inside that viewcode to a python function """
        global ViewConeFn
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst: 
                es.ServerVar('wcs_x').set(self.userid)
                ViewConeFn = method
                es.server.queuecmd('est_viewcone wcs_y %s %s %s 0 %s "es_xdoblock wcs/ViewConeReturn"'%(self.userid, filter, coneSize, coneDistance))
            else:
                raise ESTError, "ViewCone requires ESTools"
            
    def NearCoord(self,targetx,targety,targetz,x,y,z,function,ident='#all'):
        """ wcs.Command(userid).NearCoord(identifier,xrange,yrange,zrange,function) """
        if not es.exists('userid', self.userid):
            return
        for player in playerlib.getPlayerList(ident):
            if int(player) != self.userid:
                qx,qy,qz = es.getplayerlocation(int(player))
                qx -= targetx
                qy -= targety
                qz -= targetz
                if abs(qx) <= x and abs(qy) <= y and abs(qz) <= z:
                    if callable(function):
                        function(int(player),self.userid)
                        
    def GetNearCoordList(self,targetx,targety,targetz,x,y,z,ident='#all'):
        """ Returns a list of all the players inside the area close to the player """
        list = []
        if not es.exists('userid', self.userid):
            return
        for player in playerlib.getPlayerList(ident+',#alive'):
            if int(player) != self.userid:
                qx,qy,qz = es.getplayerlocation(int(player))
                qx -= targetx
                qy -= targety
                qz -= targetz
                if abs(qx) <= x and abs(qy) <= y and abs(qz) <= z:
                    list.append(int(player))
        return list
        
    def Near(self,distance,function,ident='#all'):
        """ wcs.Command(userid).Near(identifier,range,function) """
        if not es.exists('userid', self.userid):
            return
        x, y, z = es.getplayerlocation(self.userid)
        for player in playerlib.getPlayerList(ident + ',#alive'):
            if int(player) != self.userid:
                xx, yy, zz = es.getplayerlocation(int(player))
                distanceb = ((x - xx) ** 2 + (y - yy) ** 2 + (z - zz) ** 2) ** 0.5
                if distanceb <= distance:
                    if callable(function):
                        function(int(player),self.userid)
                        
    def Shake(self,time,violence):
        """ Shakes the players screen """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                es.server.queuecmd('est_Shake %s %s %s %s'%(self.userid, time, violence, violence))
            else:
                es.usermsg('create', 'shake', 'Shake')
                es.usermsg('write', 'byte',  'shake', 0)
                es.usermsg('write', 'float', 'shake', violence)
                es.usermsg('write', 'float', 'shake', 1.0)
                es.usermsg('write', 'float', 'shake', time)
                es.usermsg('send', 'shake', self.userid)
                es.usermsg('delete', 'shake')
        
    def Model(self,path):
        """ Sets a new model for the player """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                es.server.queuecmd('est_SetModel %s "%s"'%(self.userid,path))
            else:
                playerlib.getPlayer(self.userid).set("model", path)
        
    def Spawn(self):
        """ Force spawn a player """
        if not es.exists('userid', self.userid):
            return
        if isEst:
            es.server.queuecmd('est_spawn %s 1'%self.userid)
        elif isOb:
            es.spawnplayer(self.userid)
        else:
            raise ESTError, "The command Spawn requires ESTools"
        
    def Push(self,x,y,z):
        """ Push a player with an x, y and z force """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst: 
                es.server.queuecmd('est_PhysPush %s %s %s %s'%(self.userid,x,y,z) )
            else:
                playerlib.getPlayer(self.userid).set("push", (x,y,z) )
        
    def PushTo(self,x,y,z,force):
        """ Push a player to a certain x, y, z area on the map with a certain force """
        if not es.exists('userid', self.userid):
            return
        if not self.IsDead():
            if isEst:
                es.server.queuecmd('est_PushTo %s %s %s %s %s'%(self.userid,x,y,z,force))
            else:
                raise ESTError, "The command PushTo requires ESTools"
        
    def AreaRegen(self, teamFilter, distance, amount, delay):
        """ Regenerate everyone inside an area """
        if not es.exists('userid', self.userid):
            return
        teamFilter = returnPlayerlibFilters(teamFilter, True)
        x, y, z    = es.getplayerlocation(self.userid)
        team       = es.getplayerteam(self.userid)
        for player in filter(lambda x: es.getplayerteam(x) != team, playerlib.getUseridList(teamFilter) ):
            xx, yy, zz = es.getplayerlocation(player)
            if ((xx - x) ** 2 + (yy - y) ** 2 + (zz - z) ** 2) ** 0.5 <= distance:
                Command(player).Heal(amount)
        gamethread.delayed(delay, self.AreaRegen, (team, distance, amount, delay) )
        
    def AreaDamage(self, team, distance, amount, attacker = None):
        """ Give everyone inside the area a certain amount of damage """
        if not es.exists('userid', self.userid):
            return
        teamFilter = returnPlayerlibFilters(team, True)
        x, y, z    = es.getplayerlocation(self.userid)
        team       = es.getplayerteam(self.userid)
        for player in filter(lambda x: es.getplayerteam(x) != team, playerlib.getUseridList(teamFilter) ):
            xx, yy, zz = es.getplayerlocation(player)
            if ((xx - x) ** 2 + (yy - y) ** 2 + (zz - z) ** 2) ** 0.5 <= distance:
                if attacker is not None:
                    self.Damage(amount, 32, attacker)
                else:
                    self.Damage(amount)
            
    def GiveCash(self, amount):
        """ Give the player additional cash on top of the cash they've already got """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            if game == 'Counter-Strike: Source':
                amount = es.getplayerprop(self.userid,'CCSPlayer.m_iAccount') + amount
                es.setplayerprop(self.userid,'CCSPlayer.m_iAccount', min(amount, 16000))
            else:
                cur_cash = self.ReturnDict('Cash')
                cur_cash += amount
                if cur_cash > 16000: 
                    cur_cash = 16000
                elif cur_cash < 0: 
                    cur_cash = 0
                self.UpdateDict('Cash',cur_cash)
                
    def GetCash(self):
        """ Retrieve the cash of the player """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            if game == 'Counter-Strike: Source':
                return es.getplayerprop(self.userid, 'CCSPlayer.m_iAccount')
            else:
                return self.ReturnDict('Cash')
                
    def SetCash(self, amount):
        """ Set the players cash to a new value """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            if game == 'Counter-Strike: Source':
                es.setplayerprop(self.userid, 'CCSPlayer.m_iAccount', amount)
            else:
                if amount > 16000: 
                    amount = 16000
                self.UpdateDict('Cash', abs(amount))
                
    def TakeCash(self, amount):
        """ Remove the cash from the player """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            if game == 'Counter-Strike: Source':
                amount = es.getplayerprop(self.userid,'CCSPlayer.m_iAccount') - int(amount)
                es.setplayerprop(self.userid, 'CCSPlayer.m_iAccount', max(amount, 0))
            else:
                cur_cash = self.ReturnDict('Cash')
                cur_cash -= int(amount)
                if cur_cash > 16000: 
                    cur_cash = 16000
                elif cur_cash < 0: 
                    cur_cash = 0
                self.UpdateDict('Cash',cur_cash)
                
    def Delayed(self, duration, function, parama=(), Endround=None, name=None):
        """ Creates a custom delay per user, so we can track delays on a user purpose and give
            the choice to end the delay upon round_end """
        if not es.exists('userid', self.userid):
            return
        if dict_commands.has_key(self.userid):
            if not Endround:
                gamethread.delayedname(duration, (len(self.key['delay list'])+1 if not name else name), function, parama)
                self.key['delay list'].append((len(self.key['delay list'])+1 if not name else name))
            else:
                gamethread.delayedname(duration, (len(dict_commands['delay list'])+1 if not name else name), function, parama)
                dict_commands['delay list'].append((len(dict_commands['delay list'])+1 if not name else name))
                
    def CancelDelayed(self, name):
        if not es.exists('userid', self.userid):
            return
        gamethread.cancelDelayed(name)
        if name in self.key['delay list']:
            self.key['delay list'].remove(name)
        if name in dict_commands['delay list']:
            dict_commands['delay list'].remove(name)
                
    def RemoveWeapon(self, weaponType):
        """ Return the true name of the weapon, then iterate throug an entity list, testing
            if the classname is equa too the weapon or the player owns the weapon; if so, increment
            a counting value, if the counting value is only 1, strip player so they can't see their
            weapon, else, just remove the weapon index. """
        if not es.exists('userid', self.userid):
            return
        weapon = returnWeaponNameFromEstSyntax(weaponType, self.userid)
        if weapon is None:
            return
        if not weapon.startswith('weapon_'):
            weapon = 'weapon_' + weapon
        if weapon != 'weapon_' and weapon != 'weapon_0':
            handle      = es.getplayerhandle(self.userid)
            weaponCount = 0
            entityList  = es.createentitylist()
            gotWeapon   = False
            for weaponEntity in entityList:
                if not entityList[weaponEntity]['classname'].startswith('weapon_'):
                    continue
                if es.getindexprop(weaponEntity, 'CBaseEntity.m_hOwnerEntity') == handle:
                    weaponCount += 1
                    if entityList[weaponEntity]['classname'] == weapon:
                        gotWeapon = True
            if gotWeapon:
                if weaponCount > 1:
                    for entity in es.createentitylist(weapon):
                        if es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity') == handle:
                            es.server.queuecmd('es_xremove %s' % entity)
                            gamethread.delayed(0, es.cexec, (self.userid, 'lastinv' ) )
                            return
                else:
                    es.server.queuecmd('es_xfire %s player_weaponstrip kill' % self.userid)
                    es.server.queuecmd('es_xgive %s player_weaponstrip' % self.userid)
                    es.server.queuecmd('es_xfire %s player_weaponstrip strip' % self.userid)
                
    def Restrict(self, weaponType):
        """ Appends a weapon to the players 'restricted liist' so we can test if the player has a restricted weapon on clientCommandFilter
            or event item_pickup """
        if not es.exists('userid', self.userid):
            return
        weaponType = returnWeaponNameFromEstSyntax(weaponType, self.userid)
        if weaponType is None:
            return
        weaponType = weaponType.replace('weapon_', '').lower()
        self.RemoveWeapon(weaponType)
        self.key['Restricted'].append(weaponType)
        
    def UnRestrict(self, weaponType):
        """ Removes a weapon to the players 'restricted liist' so we can test if the player has a restricted weapon on clientCommandFilter
            or event item_pickup """
        if not es.exists('userid', self.userid):
            return
        weaponType = returnWeaponNameFromEstSyntax(weaponType, self.userid)
        if weaponType is None:
            return
        weaponType = weaponType.replace('weapon_', '').lower()
        if weaponType in self.key['Restricted']:
            self.key['Restricted'].remove(weaponType)
                
    def GiveXp(self, amount, reason="", race = None):
        """ Give the player some XP """
        if len(es.getUseridList() ) >= float(es.ServerVar('wcs_minplayers') ):
            steamid     = getSteam(self.userid)
            if race is None:
                race    = GetRace(self.userid)
            xp          = steamid[race]['xp']
            xp         += int(amount)
            level       = steamid[race]['level']
            total_level = steamid['level']
            nextlevelxp = (level - 1) * float(es.ServerVar('wcs_levelinterval') ) + float(es.ServerVar('wcs_start_your_engines') )
            amount_of_levels = 0
            while xp >= nextlevelxp:
                xp -= nextlevelxp
                amount_of_levels += 1
                nextlevelxp += float(es.ServerVar('wcs_levelinterval') )
            if amount_of_levels:
                self.GiveLevel(amount_of_levels, text('levelup xp', lang = playerlib.getPlayer(self.userid).get('lang') ), race )
            steamid[race]['xp'] = xp
            
            es.event('initialize', 'wcs_gainxp')
            es.event('setint',     'wcs_gainxp', 'userid',    self.userid)
            es.event('setint',     'wcs_gainxp', 'amount',    amount)
            es.event('setint',     'wcs_gainxp', 'levels',    amount_of_levels)
            es.event('setint',     'wcs_gainxp', 'currentxp', xp)
            es.event('setstring',  'wcs_gainxp', 'reason',    reason)
            es.event('fire',       'wcs_gainxp')
            
            if reason:
                es.tell(self.userid, '#multi', text('gain xp', {'amount' : amount, 'reason' : reason}, playerlib.getPlayer(self.userid).get('lang') ) )
                
    def GiveLevel(self, amount, reason=None, race = None):
        """ Give the player some levels """
        steamid  = getSteam(self.userid)
        if race is None:
            race = GetRace(self.userid)
        if amount:
            good = 1
            if Race(race).returnRaceKey().has_key('max level'):
                curlevel = steamid[race]['level']
                if not curlevel + amount <= Race(race).returnRaceKey()['max level']:
                    good = 0
            if good:
                steamid[race]['level']          += amount
                steamid['level']                += amount
                steamid[race]['unspent skills'] += amount
                if not es.getplayerprop(self.userid,'CBasePlayer.pl.deadflag'):
                    location = es.getplayerlocation(self.userid)
                    if isEst:
                        es.server.queuecmd('est_effect 10 #a 0 "sprites/steam1.vmt" %s %s %s 20 50 3 20 5 2 255 200 0 200 1' % (location[0], location[1], location[2]) )
                es.emitsound('player', self.userid, 'ambient/energy/whiteflash.wav', '0.7', '0.5')
                if es.getplayersteamid(self.userid) != "BOT":
                    spendskills(self.userid)
                else:
                    if es.exists('userid', self.userid):
                        steam = playerlib.uniqueid(self.userid, True)
                        BotLevel(self.userid, steam)
                        
                es.event('initialize', 'wcs_levelup')
                es.event('setint',     'wcs_levelup', 'userid',   self.userid)
                es.event('setint',     'wcs_levelup', 'amount',   amount)
                es.event('setint',     'wcs_levelup', 'oldlevel', steamid[race]['level'] - amount)
                es.event('setint',     'wcs_levelup', 'newlevel', steamid[race]['level'])
                es.event('setstring',  'wcs_levelup', 'race',   GetRace(self.userid) )
                es.event('setstring',  'wcs_levelup', 'reason', reason if reason is not None else "")
                es.event('fire',       'wcs_levelup')
                
        if reason:
            es.tell(self.userid, '#multi', text('level reason', {'level' : steamid[race]['level'], 'reason' : reason}, playerlib.getPlayer(self.userid).get('lang') ) )
            
    def GetXp(self, race = None):
        """ Return the current race xp of the player """
        steamid  = getSteam(self.userid)
        if race is None:
            race = GetRace(self.userid)
        xp       = steamid[race]['xp']
        return xp
        
    def GetLevel(self, race = None):
        """ Return the current race level of the player """
        if race is None:
            race = GetRace(self.userid)
        steamid  = getSteam(self.userid)
        level    = steamid[race]['level']
        return level
        
    def GetNextXp(self):
        """ Returns how much XP the player needs to level up """
        level         = Command(self.userid).GetLevel()
        next_level_xp = (level - 1) * float(es.ServerVar('wcs_levelinterval') ) + float(es.ServerVar('wcs_start_your_engines') )
        return next_level_xp
        
def ViewConeReturn():
    """ Handles our est_viewcone wrapper """
    if callable(ViewConeFn):
        ViewConeFn(int(es.ServerVar('wcs_y')), int(es.ServerVar('wcs_x')))
        
# Handels our FadePlayer repeat loop
def fadeplayer(userid, alpha_change, addition):
    """ A method which loops the change of the alpha from max to min. """
    if not es.exists('userid', self.userid):
        return
    if not Command(userid).IsDead():
        AlphaLoop = Command(userid).ReturnDict('AlphaLoop')
        if AlphaLoop:
            AlphaLoop -= 1
            Command(userid).UpdateDict('AlphaLoop',AlphaLoop)
            Alpha = Command(userid).ReturnDict('Alpha')
            if addition:
                Alpha += alpha_change
                if Alpha > 255: 
                    Alpha = 255
            else:
                Alpha -= alpha_change
                if Alpha < 0: 
                    Alpha = 0
            Command(userid).UpdateDict('Alpha',Alpha)
            
            color = -1
            color += int(Alpha) << 24
            if color >= 2**31: 
                color -= 2**32
            oldRenderMode = es.getplayerprop(userid, "CBaseEntity.m_nRenderMode")
            oldRenderFX   = es.getplayerprop(userid, "CBaseEntity.m_nRenderFX")
            newRenderMode = oldRenderMode | 1
            newRenderFX   = oldRenderFX | 256
            es.setplayerprop(userid, "CBaseEntity.m_nRenderMode", newRenderMode)
            es.setplayerprop(userid, "CBaseEntity.m_nRenderFX", newRenderFX)
            es.setplayerprop(userid, "CBaseEntity.m_clrRender", color)
            for entity in es.createentitylist(playerlib.getPlayer(userid).get("weapon")):
                if es.getplayerhandle(userid) == es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity'):
                    oldRenderMode = es.getindexprop(entity, "CBaseEntity.m_nRenderMode")
                    oldRenderFX = es.getindexprop(entity, "CBaseEntity.m_nRenderFX")
                    newRenderMode = oldRenderMode | 1
                    newRenderFX = oldRenderFX | 256
                    es.setindexprop(entity, "CBaseEntity.m_nRenderMode", newRenderMode)
                    es.setindexprop(entity, "CBaseEntity.m_nRenderFX", newRenderFX)
                    es.setindexprop(entity, "CBaseEntity.m_clrRender", color)
                    break
                    
            gamethread.delayed(0.1,fadeplayer,(userid,alpha_change,addition))
             
def SafeReturnWall():
    """ A method to return the queuecmd result from the getWallBetween command """
    callback, args, userid = safe_queue.pop(0)
    callback(userid, int(es.ServerVar('isWallBetween')), *args)
             
def SafeReturnTeleport():
    """ A method to return the queuecmd result from the getTeleportSafe command """
    callback, args, userid = safe_queue.pop(0)
    callback(userid, int(es.ServerVar('isSafe')), *args)

""" This dictionary registers all of the est_ commands """
estCommands = {
#'est_*' : [<arg count needed>, <command reference>]
# 'The est_ prefix is automatically added!'
'Spawn'           : [(2,3),        'est_Spawn <identifier> [force respawn]'],
'GetViewProp'     : [(3,),         'est_GetViewProp <variable> <player>'],
'RemoveWeapon'    : [(3,),         'est_RemoveWeapon <identifier> <weapon slot/ weapon name>'],
'RandPlayer'      : [(3,),         'est_RandPlayer <variable> <identifier>'],
'PlayPlayer'      : [(3,4,5),      'est_PlayPlayer <identifier> <sound> [volume] [attenuation]'],
'Freeze'          : [(3,),         'est_Freeze <identifier> <on/off>'],
'Fade'            : [(9,),         'est_Fade <identifier> <type> <fade time> <total time> <red> <green> <blue> <alpha>'],
'RoundDecimal'    : [(4,),         'est_RoundDecimal <variable> <floating number> <number of places>'],
'CSay'            : [(3,),         'est_CSay <identifier> <message>'],
'Shake'           : [(5,),         'est_Shake <identifier> <time> <distance> <violence>'],
'Give'            : [(3,),         'est_Give <identifier> <weapon/entity>'],
'Teleport'        : [(3,5),        'est_Teleport <identifier> <player / x,y,z>'],
'SetAim'          : [(3,4),        'est_SetAim <identifier> <player to aim at> [Value to add to z axis]'],
'Armor'           : [(4,),         'est_Armor <identifier> <operator (+/-/=)> <value>'],
'ArmorAdd'        : [(3,),         'est_ArmorAdd <identifier> <value to add>'],
'Health'          : [(4,),         'est_Health <identifier> <operator (+/-/=)> <value>'],
'Healthadd'       : [(3,),         'est_HealthAdd <identifier> <value to add>'],
'DeleteRagdolls'  : [(1,2),        'est_DeleteRagdolls [identifier]'],
'DropWeapon'      : [(3,),         'est_DropWeapon <identifier> <weapon slot / weapon name>'],
'Cash'            : [(4,),         'est_Cash <identifier> <operator (+/-/=)> <amount>'],
'CashAdd'         : [(3,),         'est_CashAdd <identifier> <amount to add>'],
'Drug'            : [(2,3),        'est_Drug <identifier> [time]'],
'Drunk'           : [(2,3),        'est_Drunk <identifier> [time]'],
'Burn'            : [(3,),         'est_Burn <identifier> <time>'],
'Effect'          : [(18, 10, 19), 'est_Effect <number> <delay> <identifier> <additional parameters> <model/halo>'],
'GetFb'           : [(3,),         'est_GetFB <variable> <player>'],
'GetSg'           : [(3,),         'est_GetSG <variable> <player>'],
'GetAmmo'         : [(4,),         'est_GetAmmo <variable> <player> <weapon slot / weapon name>'],
'GetArmor'        : [(3,),         'est_GetArmor <variable> <player>'],
'GetEyeCoord'     : [(5,),         'est_GetEyeCoord <player> <x variable> <y variable> <z variable>'],
'GetGravity'      : [(3,),         'est_GetGravity <variable> <player>'],
'GetAngleToPoint' : [(8,),         'est_GetAngleToPoint <player> <x> <y> <z> <pitch variable> <yaw variable> <roll variable>'],
'GetPlayerIndex'  : [(3,),         'est_GetPlayerIndex <variable> <player>'],
'GetViewPlayer'   : [(3,),         'est_GetViewPlayer <variable> <player>'],
'GetViewProp'     : [(3,),         'est_GetViewProp <variable> <player>'],
'GetKills'        : [(3,),         'est_GetKills <variable> <player>'],
'GetName'         : [(3,),         'est_GetName <variable> <player>'],
'GetPrimary'      : [(3,),         'est_GetPrimary <variable> <player>'],
'GetSecondary'    : [(3,),         'est_GetSecondary <variable> <player>'],
'GetSteam'        : [(3,),         'est_GetSteam <variable> <player>'],
'GetTeam'         : [(3,),         'est_GetTeam <variable> <player>'],
'GetUserid'       : [(3,),         'est_GetUserid <variable> <player>'],
'GetViewAngle'    : [(5,),         'est_GetViewAngle <player> <pitch variable> <yaw variable> <roll variable>'],
'GetViewCoord'    : [(5,),         'est_GetViewCoord <player> <x variable> <y variable> <z variable>'],
'GetWeaponIndex'  : [(4,),         'est_GetWeaponIndex <variable> <player> <weapon slot / weapon name>'],
'God'             : [(3,),         'est_God <identifier> <on/off>'],
'HasDefuser'      : [(3,),         'est_HasDefuser <variable> <player>'],
'HasHelmet'       : [(3,),         'est_HasHelmet <variable> <player>'],
'HasKevlar'       : [(3,),         'est_HasKevlar <variable> <player>'],
'IsAlpha'         : [(3,),         'est_IsAlpha <variable> <string>'],
'IsAlive'         : [(3,),         'est_IsAlive <variable> <player>'],
'IsBomber'        : [(3,),         'est_IsBomber <variable> <player>'],
'IsNumeric'       : [(3,),         'est_IsNumeric <variable> <string>'],
'IsOnly'          : [(3,),         'est_IsOnly <variable> <test string> <for string>'],
'JetPack'         : [(3,),         'est_Jetpack <identifier> <on/off>'],
'KillAdd'         : [(3,),         'est_KillAdd <identifier> <amount of kills to add>'],
'KillSet'         : [(3,),         'est_KillSet <identifier> <value>'],
'KnifeOnly'       : [(3,),         'est_KnifeOnly <variable> <player>'],
'Name'            : [(3,),         'est_Name <identifier> <new name>'],
'NoClip'          : [(3,),         'est_NoClip <identifier> <on/off>'],
'PhysPush'        : [(5,),         'est_PhysPush <identifier> <x force> <y force> <z force>'],
'PushTo'          : [(6,),         'est_PushTo <identifier> <x coord> <y coord> <z coord> <force>'],
'Remove'          : [(2,),         'est_Remove <entity>'],
'RemoveIdle'      : [(1,2),        'est_RemoveIdle [classname]'],
'Restrict'        : [(3,),         'est_Restrict <identifier> <weapon name>'],
'RestrictAll'     : [(2,),         'est_RestrictAll <identifier>'],
'Unrestrict'      : [(3,),         'est_Unrestrict <identifier> <weapon name>'],
'UnrestrictAll'   : [(2,),         'est_UnrestrictAll <identifier>'],
'Rocket'          : [(2,),         'est_Rocket <identifier>'],
'SetAmmo'         : [(4,),         'est_SetAmmo <identifier> <weapon slot/ weapon name> <value>'],
'SetArmor'        : [(3,),         'est_SetArmor <identifier> <value>'],
'SetCash'         : [(3,),         'est_SetCash <identifier> <value>'],
'SetEntityColor'  : [(6,),         'est_SetEntityColor <entity index> <red> <green> <blue> <alpha>'],
'SetGravity'      : [(3,),         'est_SetGravity <identifier> <value>'],
'SetHealth'       : [(3,),         'est_SetHealth <identifier> <value>'],
'SetModel'        : [(3,),         'est_SetModel <identifier> <model path>'],
'SetPlayerColor'  : [(6,7),        'est_SetPlayerColor <identifier> <red> <green> <blue> <alpha> [color weapons also]'],
'SetViewAngle'    : [(5,),         'est_SetViewAngle <identifier> <pitch> <yaw> <roll>'],
'Slay'            : [(2,),         'est_Slay <identifier>'],
'Speed'           : [(3,),         'est_Speed <identifier> <value>'],
'StrLen'          : [(3,),         'est_StrLen <variable> <string>'],
'StrToUpper'      : [(3,),         'est_StrToUpper <variable> <string>'],
'StrToLower'      : [(3,),         'est_StrToLower <variable> <string>'],
'StripPlayer'     : [(2,3),        'est_StripPlayer <identifier> [strip armor also]'],
'Team'            : [(3,),         'est_Team <identifier> <new team>'],
'TrimDecimal'     : [(5,),         'est_TrimDecimal <variable> <decimal number> <number of points>'],
'Near'            : [(6,),         'est_Near <variable> <filter> <distance> <userid> "<command>"'],
'NearCoord'       : [(10,),        'est_NearCoord <variable> <filter> <start-x> <start-y> <start-z> <x distance> <y distance> <z distance> "<command>"']
}
""""""

if not isEst:
    for command in estCommands:
        trueCommand = 'est_' + command
        if not es.exists('command', trueCommand):
            es.regcmd(trueCommand, 'wcs/estCommand', estCommands[command][1])
            es.regcmd(trueCommand.lower(), 'wcs/estCommand', estCommands[command][1])

def estCommand():
    """ This function makes all the EST commands possible via an ES counterpart. """
    command  = str(es.getargv(0))[4:].lower()
    argCount = es.getargc() 
    #
    for tempCommand in estCommands:
        if command == tempCommand.lower():
            if argCount not in estCommands[tempCommand][0]:
                if command != 'csay':
                    debugMsg(0, 'EST Syntax: %s' % estCommands[tempCommand][1])
                    return
            break
            
    if command == 'spawn':
        """ If the server is an orange box server, then just call the orange box command es.spawnplayer() """
        if not isOb:
            debugMsg(0, 'EST Warning: Sorry est_spawn requires the server to be an orange box server to run this command')
            return
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.spawnplayer(player)
        
    elif command == 'removeweapon':
        """ Just a shortcut to remove the weapon of the given syntax """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            Command(player).RemoveWeapon(es.getargv(2))
            
    elif command == 'randplayer':
        """ Assign the variable to hold a random player from the given identifier """
        es.ServerVar(es.getargv(1)).set( random.choice(returnPlayerlibFilters(es.getargv(2) ) ) )
        
    elif command == 'playplayer':
        """ For all the players in the given identifier, play the corrosponding sound. """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if argCount == 3:
                es.emitsound('player', player, es.getargv(2), 1.0, 1.0)
            elif argCount == 4:
                es.emitsound('player', player, es.getargv(2), es.getargv(3), 1.0)
            else:
                es.emitsound('player', player, es.getargv(2), es.getargv(3), es.getargv(4))
                
    elif command == 'freeze':
        """ Freeze all the players according to the given identifier """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if es.getargv(2) == '1':
                Command(player).Freeze()
            else:
                Command(player).UnFreeze()
                
    elif command == 'fade':
        """ Fade the players screen to another color """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if filter(lambda x: not x.isdigit(), [es.getargv(x) for x in (8, 2, 5, 6, 7) ]):
                """ One of the 'ints' is not an int """
                return
            if not isfloat(es.getargv(4)):
                return
            Command(player).Blind(float(es.getargv(4)), int(es.getargv(8)), int(es.getargv(2)), int(es.getargv(5)), int(es.getargv(6)), int(es.getargv(7) ) )
                
    elif command == 'rounddecimal':
        """ Set the given variable to the number rounded """
        if not es.getargv(3).isdigit() :
            return
        if not isfloat(es.getargv(2)):
            return
        es.ServerVar(es.getargv(1)).set( round(float(es.getargv(2) ), int(es.getargv(3) ) ) )
        
    elif command == 'csay':
        """ Join all the args following the command and the identifier, and send a centertell to them. """
        message = ' '.join(es.getargs().split()[1:])
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.centertell(player, message)
    
    elif command == 'shake':
        """ Shake the identifiers screen """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not isfloat(es.getargv(2)) or not es.getargv(3).isdigit():
                return
            Command(player).Shake(float(es.getargv(2)), int(es.getargv(3)) )
            
    elif command == 'give':
        """ Give all players in the identifier a certain entity """
        entity = es.getargv(2)
        if isOb:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                es.give(player, entity)
        else:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                es.server.queuecmd('es_xgive %s %s' % (player, entity) )
        
    elif command == 'teleport':
        """ Set the position of a player to a new location """
        if argCount == 3:
            arg3   = es.getargv(3)
            player = es.getuserid(arg3)
            if player:
                x,y,z = es.getplayerlocation(player)
            else:
                x, y, z = str(es.getargv(2)).split(',')
        else:        
            x, y, z = [es.getargv(a) for a in (2, 3, 4)]
    
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.server.queuecmd('es_xsetpos %s %s %s %s' % (player, x, y, z) )
               
    elif command == 'setaim':
        """ Set the aim of certin identifier group to a certain player """
        xx, yy, zz = es.getplayerlocation(es.getargv(2))
        if argCount == 4:
            zz += float(es.getargv(3))
        endVector = vecmath.vector((xx, yy, zz))
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            vectorX, vectorY, vectorZ = vecmath.vector(es.getplayerlocation(player)) - endVector
            myViewAngle               = Command(player).GetViewAngles() 
            ourAtan                   = math.degrees(math.atan( float(vectorY) / float(vectorX) ) )
            if float(vectorX) < 0:
                RealAngle = ourAtan + 180
            else:
                if float(vectorY) < 0:
                    RealAngle = ourAtan + 360
                else:
                    RealAngle = ourAtan
            yAngle = RealAngle
            xAngle = 0 - math.degrees( math.atan( vectorZ / (((vectorY ** 2) + vectorX ** 2)) ** 0.5) )
            if isOb:
                es.setang(player, xAngle, yAngle, myViewAngle[2])
            else:
                es.server.queuecmd('es_xsetang %s %s %s %s' % (player, xAngle, yAngle, myViewAngle[2]))
                
    elif command == 'armor':
        """ Set the armor of each player in the identifier to the amount """
        operator = es.getargv(2)
        if not es.getargv(3).isdigit():
            return
        amount   = int(es.getargv(3))
        if operator == '-':
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).ArmorAdd(amount * -1)
        elif operator == '+':
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).ArmorAdd(amount)
        else:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).Armor(amount)
                
    elif command == 'armoradd':
        """ Add an amount to the identifiers current armor """
        if not es.getargv(2).isdigit():
            return
        amount = int(es.getargv(2))
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            Command(player).ArmorAdd(amount)
            
    elif command == 'health':
        """ Set the health of each player in the identifier to the amount """
        operator = es.getargv(2)
        if not es.getargv(3).isdigit():
            return
        amount   = int(es.getargv(3))
        if operator == '-':
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).HealthAdd(amount * -1)
        elif operator == '+':
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).HealthAdd(amount)
        else:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).Health(amount)
                
    elif command == 'healthadd':
        """ Add an amount to the identifiers current health """
        if not es.getargv(2).isdigit():
            return
        amount = int(es.getargv(2))
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            Command(player).HealthAdd(amount)
            
    elif command == 'deleteragdolls':
        """ For all the ragdoll entitys, delete them. If a second arg is given, then only delete the ragdoll owned by that player. """
        if es.getargc() == 2:
            for player in returnPlayerlibFilters(es.getargv(2)):
                if not es.exists('userid', player):
                    continue
                handle = es.getplayerhandle(player)
                for entity in es.createentitylist('cs_ragoll'):
                    if not handle == es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity'):
                        continue
                    if isOb:
                        es.remove(entity)
                    else:
                        es.server.queuecmd('es_xremove %s' % entity)
                    break
        else:
            randPlayer = es.getuserid()
            if not randPlayer:
                return
            if isOb:
                es.fire(randPlayer, "cs_ragdoll", "kill")
            else:
                es.server.queuecmd('es_xfire %s cs_ragdoll kill' % randPlayer)
                
    elif command == 'dropweapon':
        """ Get the true weapon, then force a player to switch to that weapon, then force them to drop the weapon. """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            weapon = returnWeaponNameFromEstSyntax(es.getargv(2), player)
            if weapon is not None:
                if weapon not in ('weapon_knife', 'weapon_c4', 'weapon_hegrenade', 'weapon_smokegrenade', 'weapon_flashbang'):
                    es.sexec(player, 'use', weapon)
                    es.sexec(player, 'drop')
                else:
                    good   = 1
                    handle = es.getplayerhandle(player)
                    for weaponIndex in es.createentitylist(weapon):
                        if es.getindexprop(weaponIndex, 'CBaseEntity.m_hOwnerEntity') <> handle:
                            continue
                        good = 0
                        break
                    if not good:
                        continue
                    playerlibPlayer = playerlib.getPlayer(player) 
                    currentWeapon   = playerlibPlayer['weapon']
                    if currentWeapon == weapon:
                        es.sexec(player, 'lastinv')
                    if isOb:
                        es.give(player, weapon)
                        gamethread.delayed(0.2, es.remove, (playerlibPlayer.get("weaponindex", weapon) ) )
                    else:
                        es.server.queuecmd('es_xgive %s %s' % (player, weapon) )
                        es.delayed(0.2, 'es_xremove %s' % playerlibPlayer.get("weaponindex", weapon) )
                        
    elif command == 'cash':
        """ Set the cash of each player in the identifier to the amount """
        operator = es.getargv(2)
        if not es.getargv(3).isdigit():
            return
        amount   = int(es.getargv(3))
        if operator == '-':
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).TakeCash(amount * -1)
        elif operator == '+':
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).GiveCash(amount)
        else:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).SetCash(amount)
                
    elif command == 'cashadd':
        """ Add an amount to the identifiers current cash """
        if not es.getargv(2).isdigit():
            return
        amount = int(es.getargv(2))
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            Command(player).GiveCash(amount)
            
    elif command == 'drunk':
        """ For each player in the given identifier, endouse them with alcohol """
        if es.getargc() == 2:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).Drunk()
        else:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).Drunk(float(es.getargv(2) ) )
                
    elif command == 'drug':
        """ For each player in the given identifier, drug them up """
        if es.getargc() == 2:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                Command(player).Drug()
        else:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                if not isfloat(es.getargv(2)):
                    return
                Command(player).Drug(float(es.getargv(2) ) )
                
    elif command == 'burn':
        """ For each player in the given identifier, Burn them  """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not isfloat(es.getargv(2)):
                return
            Command(player).Burn(float(es.getargv(2) ) )
            
    elif command == 'effect':
        # est_Effect 3 #a 0 sprites/bluelight1.vmt server_var(wcs_x1) server_var(wcs_y1) server_var(wcs_z1) server_var(wcs_x2) server_var(wcs_y2) server_var(wcs_z2) 3 2 5 215 11 167 255
        # est_effect 7 #a 0 sprites/smoke.vmt server_var(wcs_x1) server_var(wcs_y1) server_var(wcs_z1) 100 10"
        # est_effect 10 #a 0 effects/ar2_altfire1.vmt server_var(wcs_x1) server_var(wcs_y1) server_var(wcs_z1) 950 190 3 150 100 0 155 115 100 200 1
        if es.getargv(1).isdigit():
            return
        effectNumber = int(es.getargv(1))
        if effectNumber in (3, 7, 10):
            if effectNumber == 3:
                if filter(lambda x: not isfloat(x), range(5, 18) + [3]):
                    return
                effect.BeamCustom(es.getargv(2), float(es.getargv(3)), es.getargv(4), float(es.getargv(5)), float(es.getargv(6)), float(es.getargv(7)), float(es.getargv(8)), float(es.getargv(9)), float(es.getargv(10)), float(es.getargv(11)), float(es.getargv(12)), float(es.getargv(13)), float(es.getargv(14)), float(es.getargv(15)), float(es.getargv(16)), float(es.getargv(17) ) )
            elif effectNumber == 7:
                #effect.Smoke()
                userid = es.getuserid()
                if not userid:
                    return
                location = [es.getargv(x) for x in (5, 6, 7)]
                effect._createEntity(userid, 'env_Smokestack', 'smoke%s' % userid, {"basespread" : 400, 
                                                                                  "spreadspeed" : 25, 
                                                                                  "WindSpeed" : 30, 
                                                                                  "initial" : 1, 
                                                                                  "speed" : 100, 
                                                                                  "startsize" : 250, 
                                                                                  "endsize" : 400, 
                                                                                  "rate" : 350, 
                                                                                  "jetlength" : 100,
                                                                                  "twist" : 360,
                                                                                  "SmokeMaterial" : "sprites/smoke",
                                                                                  "angles" : "0 0 0",
                                                                                  "redercolor": "127 127 127"
                                                                                  }, location = location)
            elif effectNumber == 10:
                if filter(lambda x: not isfloat(x), range(5, 19) + [3]):
                    return
                effect.RingCustom(es.getargv(2), float(es.getargv(3) ), es.getargv(4), float(es.getargv(5) ), float(es.getargv(6) ), float(es.getargv(7) ), float(es.getargv(8) ), float(es.getargv(9) ), float(es.getargv(10) ), float(es.getargv(11) ), float(es.getargv(12) ), float(es.getargv(13) ), float(es.getargv(14) ), float(es.getargv(15) ), float(es.getargv(16) ), float(es.getargv(17) ), float(es.getargv(18) ) )
                
    elif command == 'extinguish':
        napalmlist = es.createentitylist('entityflame')
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                return
            handle = es.getplayerhandle(player)
            for flameEntity in napalmlist:
                string = es.getindexprop(flameEntity, 'CEntityFlame.m_hEntAttached')
                if string == handle:
                    es.setindexprop(flameEntity, 'CEntityFlame.m_flLifetime', 0)
                    es.cexec(player, 'r_screenoverlay ""')
                    es.server.queuecmd('es_xfire %s !self DispatchEffect WaterSurfaceExplosion' % player)
                    break
            
    elif command == 'getfb':
        """ Return the amount of flashbangs a player has """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayerprop(player, "CBasePlayer.localdata.m_iAmmo.012"))
        
    elif command == 'gethe':
        """ Return the amount of grenades a player has """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayerprop(player, "CBasePlayer.localdata.m_iAmmo.011"))
        
    elif command == 'getsg':
        """ Return the amount of smoke grenades a player has """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayerprop(player, "CBasePlayer.localdata.m_iAmmo.013"))
    
    elif command == 'getammo':
        """ Return the amount of ammo a player has in the given weapon """
        player = es.getuserid(es.getargv(2))
        if not player:
            return
        weapon = returnWeaponNameFromEstSyntax(es.getargv(3), player)
        if not weapon in (playerlib._primary_weapons + playerlib._secondary_weapons):
            es.ServerVar(es.getargv(1)).set( '0')
            return
        weaponAmmo = 'CBasePlayer.localdata.m_iAmmo.' + playerlib._weapons_ammo[weapon.replace('weapon_','')]
        good   = False
        handle = es.getplayerhandle(player) 
        for weaponEntity in es.createentitylist(weapon):
            if es.getindexprop(weaponEntity, 'CBaseEntity.m_hOwnerEntity') <> handle:
                continue
            good = False
            break
        if good:
            """ Player has the weapon, so we can return the weapon ammo """
            es.ServerVar(es.getargv(1)).set( es.getplayerprop(player, weaponAmmo) )
        else:
            es.ServerVar(es.getargv(1)).set( '0')
        
    elif command == 'getarmor':
        """ Return the amount of armor a player has """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( Command(player)['MaxArmor'])
        
    elif command == 'geteyecoord':
        """ Return the co-ordinates of a players eye """
        player = es.getuserid(es.getargv(1))
        if not player:
            for a in (1, 2, 3):
                es.ServerVar(es.getargv(a)).set( '0')
            return
        x, y, z = es.getplayerlocation(player)
        if es.getplayerprop(player, 'CBasePlayer.localdata.m_Local.m_bDucked') % 2:
            z += 44
        else:
            z += 66
        es.ServerVar(es.getargv(2)).set( x)
        es.ServerVar(es.getargv(3)).set( y)
        es.ServerVar(es.getargv(4)).set( z)
        
    elif command == 'getgravity':
        """ Retrun the current value of a players gravity """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( Command(player)['MinGrav'])
        
    elif command == 'getangletopoint':
        """ Return the angles needed to look at a certain co-ord on the map """
        player = es.getuserid(es.getargv(2))
        if not player:
            for a in (5, 6, 7):
                es.ServerVar(es.getargv(a)).set( '0')
            return
        pitch, yaw, roll = vecmath.viewangles(es.getplayerlocation(player), (es.getargv(2), es.getargv(3), es.getargv(4) ) )
        es.ServerVar(es.getargv(5)).set( pitch)
        es.ServerVar(es.getargv(6)).set( yaw)
        es.ServerVar(es.getargv(7)).set( roll)
        
    elif command == 'getplayerindex':
        """ Return the players index """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(1, playerlib.getPlayer(player).get("index"))
    
    elif command == 'getviewprop':
        """ Return the prop that a player is looking at """
        player = es.getuserid(es.getargv(2))
        if isOb and player:
            es.fire(player, '!picker', 'color', "254 255 255")
        elif player:
            es.server.cmd('es_xfire %s !picker \'color\' "254 255 255"')
        else:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        for index in es.createentitylist():
            if es.getindexprop(index, "CBaseEntity.m_clrRender") == -2:
                es.setindexprop(index, "CBaseEntity.m_clrRender", -1)
                es.ServerVar(es.getargv(1)).set( index)
                return
        es.ServerVar(es.getargv(1)).set( '0')
    
    elif command == 'getviewplayer':
        """ Return the player that another player is looking at """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        if isOb:
            es.fire(player, '!picker', 'color', "254 255 255")
        else:
            es.server.cmd('es_xfire %s !picker \'color\' "254 255 255"')
        for iterPlayer in playerlib.getPlayerList('#all'):
            if int(player) == player:
                continue
            index = iterPlayer['index']
            if es.getindexprop(index, "CBaseEntity.m_clrRender") == -2:
                es.setindexprop(index, "CBaseEntity.m_clrRender", -1)
                es.ServerVar(es.getargv(1)).set( int(iterPlayer))
                return
        es.ServerVar(es.getargv(1)).set( '0')
    
    elif command == 'getkills':
        """ Return the amount of kills a player has """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( playerlib.getPlayer(userid).get("kills") )
        
    elif command == 'getname':
        """ Get the name of a player """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayername(player))
        
    elif command == 'getprimary':
        """ Get the primary weapon a player has """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( playerlib.getPlayer(player).get("primary") )
        
    elif command == 'getsecondary':
        """ Get the secondary weapon a player has """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( playerlib.getPlayer(player).get("secondary") )
    
    elif command == 'getsteam':
        """ Get the steamid of a player """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayersteamid(player) )
    
    elif command == 'getteam':
        """ Get the current team a player is on """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayerteam(player) )
        
    elif command == 'getuserid':
        """ Get the userid of a player. It will accept partial name, steamid, or userid """
        es.ServerVar(es.getargv(1)).set( es.getuserid(es.getargv(2) ) )
        
    elif command == 'getviewangle':
        """ Return the current pitch, yaw and roll of the players view """
        player = es.getuserid(es.getargv(1))
        if not player:
            for var in (2, 3, 4):
                es.ServerVar(es.getargv(var)).set( '0')
            return
        pitch, yaw, roll = Command(player).GetViewAngles()
        es.ServerVar(es.getargv(2)).set( pitch)
        es.ServerVar(es.getargv(3)).set( yaw)
        es.ServerVar(es.getargv(4)).set( roll)
        
    elif command == 'getweaponindex':
        """ Return the weaponindex of a player and a given weapon """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        weapon = returnWeaponNameFromEstSyntax(es.getargv(3), player)
        if weapon is None:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( playerlib.getPlayer(player).get("weaponindex", weapon.replace('weapon_','') ) )
        
    elif command == 'god':
        """ Set a player to god mode """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if es.getargv(2) == '1':
                Command(player).God()
            else:
                Command(player).UnGod()
        
    elif command == 'hasdefuser':
        """ Assign 1/0 to a variable depending on whether or not a player has a defuser """
        if dir != 'cstrike':
            es.ServerVar(es.getargv(1)).set( '0')
            return
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayerprop(player, "CCSPlayer.m_bHasDefuser") )
    
    elif command == 'hashelmet':
        """ Assign 1/0 to a variable depending on whether or not a player has a kevlar helmet """
        if dir != 'cstrike':
            es.ServerVar(es.getargv(1)).set( '0')
            return
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( es.getplayerprop(player, "CCSPlayer.m_bHasHelmet") )
    
    elif command == 'haskevlar':
        """ Assign 1/0 to a variable depending on whether or not a player has a kevlar suit """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        if dir not in ['cstrike', 'hl2mp', 'pvk']:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( int(bool(Command(player)['MaxArmor'] ) ) )
        
    elif command == 'isalpha':
        """ Return 1/0 if a given string is only alpha """
        es.ServerVar(es.getargv(1)).set( int(es.getargv(2).isalpha()) )
        
    elif command == 'isalive':
        """ Return 1/0 if a given player is alive """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( int(not es.getplayerprop(player, 'CBasePlayer.pl.deadflag') ) )
        
    elif command == 'isbomber':
        """ Return 1/0 if a player is currently holding the bomb """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( playerlib.getPlayer(player).get("c4") )
        
    elif command == 'isnumeric':
        """ Return 1/0 if a given string contains only digits """
        es.ServerVar(es.getargv(1)).set( int(es.getargv(2).isdigit()) )
    
    elif command == 'isonly':
        """ Return 1/0 if the given string contains only chars from the given test """
        allowed = list(es.getargv(3))
        if filter(lambda x: x not in allowed, es.getarg(2)):
            es.ServerVar(es.getargv(1)).set( '0')
            return
        es.ServerVar(es.getargv(1)).set( '1')
        
    elif command == 'jetpack':
        """ Gives a player the jetpack movement type """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            playerlib.getPlayer(player).jetpack(es.getargv(2))
            
    elif command == 'killadd':
        """ Add kills to a players score """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.server.queuecmd('score add %s %s' % (player, es.getargv(2) ) )
            
    elif command == 'killset':
        """ Sets a players kills """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.server.queuecmd('score set %s %s' % (player, es.getargv(2) ) )
            
    elif command == 'knifeonly':
        """ Returns 1/0 if the only weapon a player has is a knife """
        player = es.getuserid(es.getargv(2))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        entityList = es.createentitylist()
        handle     = es.getplayerhandle(player)
        for entity in filter(lambda x: entityList[x]['classname'].startswith('weapon_'), entityList):
            if entityList[entity]['classname'] == 'weapon_knife':
                continue
            if es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity') <> handle:
                continue
            es.ServerVar(es.getargv(1)).set( '0')
        es.ServerVar(es.getargv(1)).set( '1')
        
    elif command == 'name':
        """ Assigns a new name to a player """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.sexec(player, 'name', es.getargv(2) )
            
    elif command == 'noclip':
        """ Gives a player a nolip ability """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            playerlib.getPlayer(player).set('noclip', es.getargv(2))
            
    elif command == 'physpush':
        """ Push all the people in the identifier a certain X,Y,Z force """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.setplayerprop(player, 'CBasePlayer.localdata.m_vecBaseVelocity', '%s,%s,%s' % (es.getargv(2), es.getargv(3), es.getargv(4) ) )
            
    elif command == 'pushto':
        """ Push all the players within the identifiers group to a certain point on the map """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not isfloat(es.getargv(5)):
                return
            es.setplayerprop(player, 'CBasePlayer.localdata.m_vecBaseVelocity', str( (vecmath.vector((es.getargv(2), es.getargv(3), es.getargv(4) ) ) - vecmath.vector(es.getplayerlocation(player) ) ).setlength(float(es.getargv(5)) * 1000) ) )
    
    elif command == 'remove':
        """ Remove an entity """
        if isOb:
            es.remove(es.getargv(1))
        else:
            es.server.queuecmd('es_xremove %s' % es.getargv(1))
    
    elif command == 'removeidle':
        """ Remove all entitys which have no ownerEntity """
        if argCount == 3:
            entityList = es.createentitylist(es.getargv(2))
        else:
            entityList = es.createentitylist()
        for entity in entityList:
            if es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity') == -1:
                if isOb:
                    es.remove(entity)
                else:
                    es.server.queuecmd('es_xremove %s' % entity)
    
    elif command == 'restrict':
        """ Restrict a certain weapon type for a group """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            weapon = returnWeaponNameFromEstSyntax(es.getargv(2), player)
            if weapon is None:
                continue
            Command(player).Restrict(weapon[7:])
            
    elif command == 'restrictall':
        """ Restricts all weapons for players """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            for weapon in (playerlib._primary_weapons + playerlib._secondary_weapons + ['knife', 'hegrenade', 'smokegrenade', 'flashbang', 'c4']):
                Command(player).Restrict(weapon)
    
    elif command == 'unrestrict':
        """ un-restricts a weapon type for certain players """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            weapon = returnWeaponNameFromEstSyntax(es.getargv(2), player)
            if weapon is None:
                continue
            Command(player).UnRestrict(weapon[7:])
            
    elif command == 'unrestrictall':
        """ Un-restrict all weapons for certain players """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            for weapon in (playerlib._primary_weapons + playerlib._secondary_weapons + ['knife', 'hegrenade', 'smokegrenade', 'flashbang', 'c4']):
                Command(player).UnRestrict(weapon)
                
    elif command == 'rocket':
        """ Shake the players screen, push them vertically then make them explode... Nice way to see them die. """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.emitsound('player', player, 'weapons/rpg/rocketfire1.wav', '1.0', '0.4')
            Command(player).Shake(3, 25)
            gamethread.delayed(0.5, es.emitsound, ('player', player, 'ambient/fire/ignite.wav', '1.0', '0.4') )
            rocketEffectLoop(player, 3.0)
        
    elif command == 'setammo':
        """ Set the ammo in a players gun to a certain value """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            weapon = returnWeaponNameFromEstSyntax(es.getargv(2), player)
            if weapon is None:
                continue
            es.setplayerprop(player, 'CBasePlayer.localdata.m_iAmmo.%s' % playerlib._weapons_ammo[weapon])
            
    elif command == 'setarmor':
        """ Asssign a new value to a player groups armor """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not es.getargv(2).isdigit():
                return
            Command(player).Armor(int( es.getargv(2) ) )
    
    elif command == 'setcash':
        """ For all the players in a given identifier, reasign the value of their cash """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not es.getargv(2).isdigit():
                return
            Command(player).SetCash(int( es.getargv(2) ) )
            
    elif command == 'setentitycolor':
        """ Make an entity a different color """
        entity = es.getargv(1)
        if entity in map(str, es.createentitylist()):
            if filter(lambda x: not x.isdigit(), [es.getargv(y) for y in range(2, 6)]):
                return
            color = int(es.getargv(2))
            color += int(es.getargv(3)) << 8
            color += int(es.getargv(4)) << 16
            color += int(es.getargv(5)) << 24
            es.setindexprop(entity, 'CBaseEntity.m_clrRender', color)
            
    elif command == 'setgravity':
        """ For all the players in a given identifier, reasign the value of their gravity """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not isfloat(es.getargv(2)):
                return
            Command(player).SetGravity(float(es.getargv(2) ) )
            
    
    elif command == 'sethealth':
        """ For all the players in a given identifier, reasign the value of their health """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not es.getargv(2).isdigit():
                return
            Command(player).Health(int(es.getargv(2) ) )
    
    elif command == 'setmodel':
        """ For all the players in a given identifier, reasign the value of their model """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            playerlib.getPlayer(player).set("model", es.getargv(2) )
            
    elif command == 'setplayercolor':
        """ For all the players in a given identifier, reasign the value of their color """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if filter(lambda x: not x.isdigit(), [es.getargv(y) for y in range(2, 6)]):
                return
            r, g, b, a = map(int, [es.getargv(y) for y in range(2, 6)])
            color = r
            color += g << 8
            color += b << 16
            color += a << 24
            if color >= 2**31: 
                color -= 2**32
            oldRenderMode = es.getplayerprop(player, "CBaseEntity.m_nRenderMode")
            oldRenderFX   = es.getplayerprop(player, "CBaseEntity.m_nRenderFX")
            newRenderMode = oldRenderMode | 1
            newRenderFX   = oldRenderFX | 256
            es.setplayerprop(player, "CBaseEntity.m_nRenderMode", newRenderMode)
            es.setplayerprop(player, "CBaseEntity.m_nRenderFX", newRenderFX)
            es.setplayerprop(player, "CBaseEntity.m_clrRender", color)
            if argCount == 7:
                for entity in es.createentitylist(playerlib.getPlayer(player).get("weapon")):
                    if es.getplayerhandle(player) == es.getindexprop(entity, 'CBaseEntity.m_hOwnerEntity'):
                        oldRenderMode = es.getindexprop(entity, "CBaseEntity.m_nRenderMode")
                        oldRenderFX = es.getindexprop(entity, "CBaseEntity.m_nRenderFX")
                        newRenderMode = oldRenderMode | 1
                        newRenderFX = oldRenderFX | 256
                        es.setindexprop(entity, "CBaseEntity.m_nRenderMode", newRenderMode)
                        es.setindexprop(entity, "CBaseEntity.m_nRenderFX", newRenderFX)
                        es.setindexprop(entity, "CBaseEntity.m_clrRender", color)
                        break
    
    elif command == 'setviewangle':
        """ For all the players in a given identifier, reasign the value of their view angle """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if filter(lambda x: not isfloat(x), [es.getargv(y) for y in range(2, 5)]):
                return
            playerlib.getPlayer(player).set("viewangle", map(float, (es.getargv(2), es.getargv(3), es.getargv(4) ) ) )
        
    elif command == 'slay':
        """ For all the players in a given identifier, damage them with the same amount as their health """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            es.emitsound('player', player, 'ambient/explosions/exp3.wav', '1.0', '0.4')
            es.server.queuecmd('damage %s %s' % (player, es.getplayerprop(player, 'CBasePlayer.m_iHealth') ) )
        
    elif command == 'speed':
        """ For all the players in a given identifier, reasign the value of their speed """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            if not isfloat(es.getargv(2)):
                return
            es.setplayerprop(player, 'CBasePlayer.localdata.m_flLaggedMovementValue', float(es.getargv(2) ) )
            
    elif command == 'strlen':
        """ Return the length of a current string """
        es.ServerVar(es.getargv(1)).set( len(es.getargv(2) ) )
        
    elif command == 'strtoupper':
        """ Convert a string to upper case """
        es.ServerVar(es.getargv(1)).set( es.getargv(2).upper() )
        
    elif command == 'strtolower':
        """ Convert a string to lower case """
        es.ServerVar(es.getargv(1)).set( es.getargv(2).lower() )
        
    elif command == 'stripplayer':
        """ Strip a player of all their weapons """
        if isOb:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                es.fire(player, 'player_weaponstrip', 'kill')
                es.give(player, 'player_weaponstrip')
                es.fire(player, 'player_weaponstrip', 'strip')
        else:
            for player in returnPlayerlibFilters(es.getargv(1)):
                if not es.exists('userid', player):
                    continue
                es.server.cmd('es_xfire %s player_weaponstrip kill' % player)
                es.server.cmd('es_xgive %s player_weaponstrip' % player)
                es.server.cmd('es_xfire %s player_weaponstrip strip' % player)
                
    elif command == 'team':
        """ Change a players current team without killing them... """
        for player in returnPlayerlibFilters(es.getargv(1)):
            if not es.exists('userid', player):
                continue
            pass
        
    elif command == 'trimdecimal':
        """ Trip a decimal number down to X.DP WITHOUT rounding. """
        if not es.getargv(3).isdigit():
            return
        dp = int(es.getargv(3))
        string = es.getargv(2)
        if len(string) - 2 <= dp:
            if string.find('.') == -1:
                string += '.0'
            while len(string) < dp:
                string += '0' 
        else:
            string = string[:dp + 2]
        es.ServerVar(es.getargv(1)).set( string)
        
    elif command == 'near':
        player = es.getuserid(es.getargv(4))
        if not player:
            es.ServerVar(es.getargv(1)).set( '0')
            return
        if not isfloat(es.getargv(3)):
            return
        x, y, z = es.getplayerlocation(player)
        for userid in returnPlayerlibFilters(es.getargv(2)):
            if not es.exists('userid', userid):
                continue
            xx, yy, zz = es.getplayerlocation(userid)
            if ((xx - x) ** 2 + (yy - y) ** 2 + (zz - z) ** 2) ** 0.5 <= float(es.getargv(3)):
                es.ServerVar(es.getargv(1)).set(userid)
                es.server.cmd(es.getargv(5))
    
    elif command == 'nearcoord':
        if filter(lambda x: not isfloat(x), [es.getargv(y) for y in range(3, 9)]):
            return
        for player in returnPlayerlibFilters(es.getargv(2)):
            if not es.exists('userid', player):
                continue
            x, y, z = es.getplayerlocation(player)
            if abs(x - float(es.getargv(3) ) ) <= float(es.getargv(6)) and abs(y - float(es.getargv(4) ) ) <= float(es.getargv(7) ) and abs(z - float(es.getargv(5) ) ) <= float(es.getargv(8) ):
                es.ServerVar(es.getargv(1)).set(player)
                es.server.cmd(es.getargv(9))
            
def isfloat(string):
    """ Return if a string can be converted to a float """
    string = str(string)
    if string.isdigit():
        return True
    if string.count('.') <> 1:
        return False
    string = string.split('.')
    return string[0].isdigit() and string[1].isdigit()
            
def rocketEffectLoop(userid, time):
    """ A command to make some neat effects and push a player vertically... Made by bonbon <3 """
    if time >= 0:
        time -= 0.1
        loc = es.getplayerlocation(userid)
        if time < 2.5:
            effectlib.drawBox(loc, [loc[0] + 10, loc[1] + 10, loc[2]], "materials/sprites/laser.vmt", "materials/sprites/halo01.vmt", 0.2, 20, 20, 255, 0, 0, 255, 10, 0, 0, 0, 0)
            effectlib.drawBox(loc, [loc[0] - 10, loc[1] - 10, loc[2]], "materials/sprites/laser.vmt", "materials/sprites/halo01.vmt", 0.2, 20, 20, 255, 128, 0, 255, 10, 0, 0, 0, 0)
            effectlib.drawBox([loc[0] - 5, loc[1] - 5, loc[2]], [loc[0] + 5, loc[1] + 5, loc[2]], "materials/sprites/laser.vmt", "materials/sprites/halo01.vmt", 0.2, 20, 20, 0, 0, 255, 255, 10, 0, 0, 0, 0)
            if (time * 10) % 2:
                es.setplayerprop(userid, 'CBasePlayer.localdata.m_vecBaseVelocity', '0,0,145')
        gamethread.delayed(0.1, rocketEffectLoop, (userid, time) )
    else:
        es.server.queuecmd('es_give %s env_explosion' % userid)
        es.server.queuecmd('es_xfire %s env_explosion addoutput "iMagnitude 100"' % userid)
        es.server.queuecmd('es_xfire %s env_explosion explode' % userid)
        es.emitsound('player', userid, 'ambient/explosions/exp3.wav', '1.0', '0.4')
        es.server.queuecmd('damage %s %s' % (userid, es.getplayerprop(userid, 'CBasePlayer.m_iHealth') ) )
        
def returnWeaponNameFromEstSyntax(weaponSlotOrName, userid):
    """ Returns the weapon name from either a slot or weapon name. """        
    weaponSlotOrName = str(weaponSlotOrName)
    weapon           = ''
    if weaponSlotOrName.isdigit():
        if weaponSlotOrName in ('1', '2'):
            if weaponSlotOrName == '1':
                weapon = playerlib.getPlayer(userid).get("primary")
            else:
                weapon = playerlib.getPlayer(userid).get("secondary")
            weapon = 'weapon_' + weapon
            if weapon == 'weapon_0':
                return
        elif weaponSlotOrName == '3':
            weapon = 'weapon_knife'
        elif weaponSlotOrName == '4':
            weapon = 'weapon_c4'
    else:
        weapon = weaponSlotOrName
    if not weapon.startswith('weapon_'):
        weapon = 'weapon_' + weapon
    if weapon != 'weapon_' or weapon != 'weapon_0':
        return weapon
    return None

def returnPlayerlibFilters(team, string = False):
    """ 
        Returns a playerlib filter list from a given EST syntax... 
        e.g. #a will return #all and #al will return #all,#alive 
    """
    if team.count(','):
        """ If the filter list contains a , then it's already a playerlib filter """
        return team
    if str(team).isdigit():
        if str(team) == '0':
            return ()
        return (team,)
    userid = es.getuserid(team)
    if userid:
        return (userid,)
    currentTeamFilter = ""
    currentFilter     = "#"
    for teamFilter in team:
        if teamFilter in ('#', '!'):
            currentFilter = teamFilter
        else:
            if teamFilter   == 'c':
                teamFilter   = 'ct'
            elif teamFilter == 'a':
                teamFilter   = 'all'
            elif teamFilter == 'l':
                teamFilter   = 'alive'
            elif teamFilter == 'b':
                teamFilter   = 'bot'
            elif teamFilter == 'u':
                temFilter    = 'un'
            elif teamFilter == 's':
                teamFilter   = 'spec'
            elif teamFilter == 'd':
                teamFilter   = 'dead'
            elif teamFilter == 'h':
                teamFilter   = 'human'
            currentTeamFilter += currentFilter + teamFilter + ","
    if string is not False:
        return currentTeamFilter[:-1]
    return playerlib.getUseridList(currentTeamFilter[:-1])
             
_dict_races_instances = {}
def Race(race):
    """ Method to ensure there's only ever 1 race instance per race. """
    if not _dict_races_instances.has_key(race):
        _dict_races_instances[race] = Race_Race(race)
    return _dict_races_instances[race]

_dict_races = {}
race_list = []
class Race_Race:
    """ A class to handle the races """
    def __init__(self, race):
        """ Called whenever a new race is loaded """
        self.race = race
        if not _dict_races.has_key(race):
            _dict_races[race]= {}
            _dict_races[race]['skills'] = {}
            _dict_races[race]['skills']['skill list'] = []
            _dict_races[race]['itemRestrictions'] = []
        self.author = None
        self.key    = _dict_races[race]
        self.skills = self.key['skills']
        self.registerMinLevel(0)
        
    def registerSkill(self, skillName, skillLevels, skillInterval, skillDescription, requiredLevel=None, requiredSkill=None):
        """ Registers a skill. Add the skillname as a dict, and adds the relevant keys to it. """
        self.skills[skillName] = {}
        self.skills[skillName]['type'] = 'Skill'
        self.skills[skillName]['levels'] = int(skillLevels)
        self.skills[skillName]['interval'] = int(skillInterval)
        self.skills[skillName]['description'] = skillDescription
        if requiredLevel:
            self.skills[skillName]['required level'] = int(requiredLevel)
            if requiredSkill:
                self.skills[skillName]['required skill'] = requiredSkill
        self.skills['skill list'].append(skillName)
        
    def registerMinLevel(self, minLevel):
        """ Register a minimum level to a race so the user has to be over level x to play it. """
        self.key['Min Level'] = minLevel
        gamethread.delayedname(1, 'reload', buildRaceMenu)
        
    def registerTeam(self, Team):
        """ Registers a team restriction so only 1 team can use the race """
        if Team.lower() == 't':
            regTeam = 2
        elif Team.lower() == 'ct':
            regTeam = 3
        elif Team in (2, 3):
            regTeam = Team
        else:
            debugMsg(0,'Team %s is an incorect team for Race %s'%(Team,self.race))
            return None
        self.key['Team'] = regTeam
        gamethread.delayedname(1, 'reload', buildRaceMenu)
        
    def registerUltimate(self, ultiName, ultiRequiredLevel, ultiMaxLevel, ultiLevelInterval, ultiDescription, requiredSkill=None):
        """ Registers the ultimate of the race (+ultimate key) """
        self.skills[ultiName] = {}
        self.skills[ultiName]['type'] = 'Ulti'
        self.skills[ultiName]['required level'] = int(ultiRequiredLevel)
        self.skills[ultiName]['levels'] = int(ultiMaxLevel)
        self.skills[ultiName]['interval'] = int(ultiLevelInterval)
        self.skills[ultiName]['description'] = ultiDescription
        if requiredSkill:
            self.skills[ultiName]['required skill'] = requiredSkill
        self.skills['skill list'].append(ultiName)
        
    def registerSteamid(self, steamIds):
        """ Registers a list of steamID's that are only allowed to use that race """
        self.key['steam allow'] = steamIds
        
    def registerWeaponRestriction(self, type, weapons):
        """ Registers a weapon restriction to the race. """
        if type.lower() == 'allow only':
            self.key['restriction type'] = 'allow only'
            self.key['weapons list'] = weapons
        elif type.lower() == 'block only':
            self.key['restriction type'] = 'block only'
            self.key['weapons list'] = weapons
        
    def registerItemRestriction(self, items):
        if isinstance(items, tuple) or isinstance(items, list):
            for item in items:
                self.registerItemRestriction(item)
        elif isinstance(items, str):
            self.key['itemRestrictions'].append(items)
        else:
            debugMsg(0, 'WCS ERROR: Error doing the command "race.registerItemRestriction(%s)" for race %s' % (items, self.race) )
            
    def registerMaxLevel(self, maxLevel):
        """ Registers a maximum level to the race so it can only be played until level x """
        self.key['max level'] = maxLevel
        
    def registerTeamLimit(self, limit):
        """ Registers a team limit to the race so only x people per team can play the race """
        self.key['teamlimit'] = int(limit)
        
    def registerAuthor(self, authorName):
        self.author = authorName
        
    def returnSkillList(self):
        """ Returns the skill list of the race """
        return self.skills['skill list']
        
    def returnRaceKey(self):
        """ Returns the key of the race """
        return self.key
        
    def has_key(self, skillName):
        """ Returns weather or not a key exists in the dictionary """
        if self.skills.has_key(skillName):
            return 1
        return 0
        
    def loadStrings(self, path=False):
        """ Loads a specific strings file to allow all races to have multi lingual text """
        if not path:
            lang_path = es.getAddonPath('wcs') + '/races/%s/strings.ini' % self.race
            if os.path.isfile(lang_path):
                return langlib.Strings(lang_path)
            else:
                """ Return a lambda function to return a debug string at every tell/msg command which uses the variable """
                debugMsg(0, 'WCS: ERROR - Unable to load /races/%(race)s/strings.ini! Please ensure it is in the ./wcs/race/%(race)s/ directory.' % {'race':self.race})
                return lambda x, y={}, lang="en": "Incorrect language file!" 
        else:
            if os.path.isfile(path):
                return langlib.Strings(path)
            else:
                """ Return a lambda function to return a debug string at every tell/msg command which uses the variable """
                debugMsg(0, 'WCS: ERROR - Unable to load %s! Please ensure you have typed out the correct path' % path)
                return lambda x, y={}, lang="en": "Incorrect language file!"
    
    def config(self):
        """ Returns an instance of the raceConfigs class so a player can do config = race.confg(). """
        return raceConfigs(self.race)
    
class raceConfigs(object):
    """ A class to control all the configuration options for the race. """
    
    def __init__(self, race):
        """ Called when the class is initialized. Set the self options, and create
            the self.text. """
        self.race     = race
        self.racepath = es.getAddonPath('wcs') + '/races/%s' % self.race
        self.config   = self.racepath + '/config.cfg'
        self.options  = []
        self.text     = "// This file is for changing the configuration options for %s\n" % self.race
        self.text    += "// Change these options to your preference.\n\n"
        
    def addComment(self, text=""):
        """ If self.text, add comment lines (//) followed by the text, and append it to self.text """
        if text:  
            self.text += "// %s\n" % text
        else:
            self.text += "\n"
        
    def addVar(self, variable, defaultValue, comment):
        """ Adds a blank line, followed by the comment of the variable. On the next line,
            add the command so it can be easilly changed. Return an instance of the server
            variable in form of a string. """
        self.options.append(variable)
        self.addComment()
        self.addComment(comment)
        self.text += "   %s \"%s\"\n" % (variable, defaultValue)
        return es.ServerVar(variable, defaultValue, comment)
        
    def load(self, queuecmd=True):
        """ Write the new lines to the file then execute it. """
        debugMsg(1, 'Found the config file. Testing to see if a previous config file for race %s exists' % self.race)
        if os.path.isfile(self.config):
            """ If there is already a config file, do NOT overwrite it, instead, append
                the different lines to the end of the file. """
            debugMsg(1, 'Config file already exists. Testing for line difference...')
            config_file_lines         = open(self.config, 'r')
            config_lines              = config_file_lines.readlines()
            config_file_lines.close()
            text_lines                = map(lambda x: x + "\n", self.text.split('\n'))
            config_file               = open(self.config, 'w')
            
            differ = difflib.Differ()
            result = differ.compare(config_lines, text_lines)
            result = ''.join(result)
            lines  = ''
            for line in result.split('\n'):
                if not line.startswith(('-','?')):
                    lines += line[2:] + "\n"
        
            config_file.writelines(lines[:-1])
            config_file.close()
        else:
            """ There is no config file, thus just create one. """
            debugMsg(1, 'Config file doesnt\'t exists. Simply create a new file now.')
            config_file = open(self.config, 'w')
            config_file.writelines(self.text)
            config_file.close()
            debugMsg(3, 'Writing the following line to the config file:\n%s' % self.text)
        if queuecmd:
            """ If queuecmd is True (default), then append the execution to the end of the queue """
            debugMsg(1, 'Executing the config file, appending it to the end of the queue list')
            es.server.queuecmd('es_xmexec ../addons/eventscripts/wcs/races/%s/config.cfg' % self.race)
        else:
            """ Otherwise, execute it instantly. More likely to crash, but it will execute the file straight away. """
            debugMsg(1, 'Executing the config file via cutting in the queue (es.server.cmd)')
            if isOb:
                es.mexec('../addons/eventscripts/wcs/races/%s/config.cfg' % self.race)
            else:
                es.server.cmd('es_xmexec ../addons/eventscripts/wcs/races/%s/config.cfg' % self.race)
        
# Class menu for the admin system
AdminDict = {}
class Admin:
    """ A Class to keep all the admin options in order. """
    def __init__(self):
        """ Called when a new instance is made. """
        self.dict = AdminDict
        
    def registerMenu(self, text, function):
        """ Create a new popup, and add all the options to it. """
        popup = popuplib.easymenu('wcs_wcsadminmenu','adminchoice',AdminSelection)
        popup.settitle('WarCraft Admin')
        self.dict[text] = function
        for a in self.dict:
            popup.addoption(a,a)
            
_dict_items = {}

shopmenu = {
'enhancement':[],
'attack'     :[],
'defense'    :[],
'special'    :[],
'powerup'    :[]
}

item_dict = {}
def Item(item):
    if not item_dict.has_key(item):
        item_dict[item] = ItemManager(item)
    return item_dict[item]
    
class ItemManager:
    """ Class to sort all the items """
    def __init__(self, item):
        self.item = item
        if not _dict_items.has_key(item):
            _dict_items[item]= {}
        self.key = _dict_items[item]
        
    def registerItem(self, menuType, cost, description, addItem = False):
        """ wcs.Item(<Item Name>).registerItem(<menu>,<cost>,<description>) """
        if shopmenu.has_key(menuType):
            shopmenu[menuType].append(self.item)
            self.key['cost']        = cost
            self.key['description'] = description
            self.key['addItem']     = addItem
            builditemmenu()
        else:
            debugMsg(0, 'WCS Error: %s is not a valid menu type for the shopmenu!'%menuType)
            
    def returnItemKey(self):
        return self.key
        
def builditemmenu():
    """ Create a new popup instance, and add all the items to it. """
    for x in shopmenu:
        mymenu = popuplib.easymenu('wcs_%smenu'%x, '_popup_choice', ItemBought)
        myinfo = popuplib.easymenu('wcs_%sinfo'%x, '_popup_choice', ShopInfoSelect)
        mymenu.c_exitformat = '0. Back'
        myinfo.c_exitformat = '0. Back'
        mymenu.submenu(10, 'wcs_shopmenu')
        myinfo.submenu(10, 'wcs_shopinfo')
        for i in shopmenu[x]:
            mymenu.addoption(i, '%s ($%s)'%(i, Item(i).returnItemKey()['cost']))
            myinfo.addoption(i, '%s - %s'%(i, Item(i).returnItemKey()['description']))
            
def ShopInfoSelect(userid, choice, popupid):
    """ Tell the player about the item when they ask for a description """
    es.tell(userid, '#multi', '#green%s #default- #lightgreen%s'%(choice, Item(choice).returnItemKey()['description']))
    
def ItemBought(userid, choice, popupid):
    """ Initialize the event """
    if choice not in Race(GetRace(userid)).returnRaceKey()['itemRestrictions']:
        addItem = Item(choice).returnItemKey()['addItem'] 
        if not addItem or not len(Command(userid)['items']) >= float(es.ServerVar('wcs_maxitems')):
            cost = Item(choice).returnItemKey()['cost']
            if Command(userid).GetCash() >= cost:
                if addItem:
                    Command(userid).AddItem(choice)
                Command(userid).TakeCash(cost)
                es.tell(userid, '#multi', text('shopmenu buy item', {'item' : choice}, playerlib.getPlayer(userid).get("lang") ) )
                es.event('initialize', 'item_bought')
                es.event('setint',     'item_bought', 'userid', userid)
                es.event('setint',     'item_bought', 'cost',   cost)
                es.event('setstring',  'item_bought', 'item',   choice)
                es.event('fire', 'item_bought')
            else:
                es.tell(userid, '#multi', text('shopmenu low cash', {'item' : choice}, playerlib.getPlayer(userid).get("lang") ) )    
        else:
            es.tell(userid, '#multi', text('shopmenu max items', lang = playerlib.getPlayer(userid).get("lang") ) )
    else:
        es.tell(userid, '#multi', text('shopmenu restricted item', {'item' : choice}, playerlib.getPlayer(userid).get("lang") ) )


class gravityManager(object):
    """ Class to manager the tick listener, and to manage the players gravity """
    def __init__(self):
        """ Create 2 self. variables """
        self.gravityList = {}
       
    def addGravityChange(self, userid, amount):
        """ Check if there are already any players in the gravityChange list.
            If there isn't, start the tick listener. Following this, check
            if the userid is in the dictionary, if so, remove them. Then create
            a new instance. """
        userid = str(userid)
        if not len(self.gravityList):
            gamethread.delayedname(0.25, 'gravity_check', self._ticker)
        if self.gravityList.has_key(userid):
            self.removeGravityChange(userid)
        if es.exists('userid', userid):
            self.gravityList[userid] = {'lastairvalue': es.getplayerprop(userid, 'CBasePlayer.m_fFlags') & 1, 'gravity': amount, 'lastmovementvalue': es.getplayerprop(userid, 'CBaseEntity.movetype')}
        else:
            self.gravityList[userid] = {'lastairvalue': 0, 'gravity': amount, 'lastmovementvalue': 2}
        self._resetGravity(userid, amount)
       
    def removeGravityChange(self, userid):
        """ Check if the player is in the dictioanry. If so, reset their gravity to 1
            and delete their instance from the dictionary. If there are no more players
            within the gravityList, remove the tick listener """
        userid = str(userid)
        if self.gravityList.has_key(userid):
            del self.gravityList[userid]
        if isOb:
            es.fire(userid, '!self', 'addouput', "gravity 1.0", 0.1, 1)
        else:
            es.server.queuecmd('es_xfire %s !self addoutput "gravity %s" 0.1 1'%(userid, 1.0))
       
    def deleteGravityList(self):
        """ Loop through all the players, reset their gravity to 1, delete the gravity
            list then unregister the tick listener. """
        for player in self.gravityList:
            _resetGravity(player, 1.0)
        del self.gravityList
        gamethread.cancelDelayed('gravity_check')
       
    def _ticker(self):
        """ Here we loop through all of the players, and check their gravity etc. """
        for player in self.gravityList:
            try:
                if es.exists('userid', player):
                    newaval = es.getplayerprop(player, 'CBasePlayer.m_fFlags') & 1
                    newmval = es.getplayerprop(player, 'CBaseEntity.movetype')
                else:
                    newaval = 0
                    newmval = 2
                if self.gravityList[player]['lastairvalue'] <> newaval:
                    """ Player has jumped """
                    self._resetGravity(player, self.gravityList[player]['gravity'])
                             
                elif self.gravityList[player]['lastmovementvalue'] <> newmval and newmval == 2:
                    """ Player has changed move type and is back to normal (I.E, just came off a ladder) """
                    self._resetGravity(player, self.gravityList[player]['gravity'])
                self.gravityList[player]['lastairvalue']      = newaval
                self.gravityList[player]['lastmovementvalue'] = newmval
            except:
                debugMsg(1, 'ERROR: Error looping the ticker for player %s, looping to next player' % player )
                continue
        gamethread.delayedname(0.25, 'gravity_check', self._ticker)

    def _resetGravity(self, userid, amount):
        """ Change the players gravity to value amount. """
        if isOb:
            es.fire(userid, '!self', 'addoutput', "gravity %s" % amount, 0.1, 1)
        else:
            es.server.queuecmd('es_xfire %s !self addoutput "gravity %s" 0.1 1'%(userid, amount))
       
gravity = gravityManager()

def addGravity(userid, amount):
    """ Add a new player to the gravity list """
    gravity.addGravityChange(userid, amount)
   
def removeGravity(userid):
    """ Remove a player from the gravity list """
    gravity.removeGravityChange(userid)
   
def gravityCommand():
    """ gravity <userid> <amount> """
    if es.exists('userid', es.getargv(1)):
        if float(es.getargv(2)) == 1.0:
            """ Remove the gravity since they are 'resetting' their gravity to normal """
            removeGravity(es.getargv(1))
        else:   
            """ Add a new player to the gravity list, and pass the new value. """
            addGravity(es.getargv(1), float(es.getargv(2) ) )
    else:
        debugMsg(0, "Incorrect userid for gravity : %s" % es.getargv(1) )
if not es.exists('command', 'gravity'):
    es.regcmd('gravity', 'wcs/gravityCommand', 'gravity <userid> <amount>') 

def AdminSelection(userid, choice, popupid):
    """ The admin made a selection, so call the function """
    if AdminDict.has_key(choice):
        function = AdminDict[choice]
        if callable(function):
            function(userid)
            
def SendRank(userid):
    """ Sorted the dict out by level, then #s the index of the user. """
    if es.exists('userid',userid):
        a = sorted(_dict_WCSPlayers,WcsSort)
        steamid = playerlib.uniqueid(userid, True)
        position = a.index(steamid) + 1
        totalranked = len(a)
        _level = _dict_WCSPlayers[steamid]['level']
        _race = GetRace(userid)
        tokens = {}
        tokens['name']        = es.getplayername(userid)
        tokens['position']    = position
        tokens['totalranked'] = totalranked
        tokens['race']        = _race
        tokens['level']       = _level
        for player in es.getUseridList():
            es.tell(player, '#multi', text('ranked place', tokens, playerlib.getPlayer(player).get('lang') ) )
        
def WcsSort(player1, player2):
    """ Return whether the item should be before (-1) or after(1) the other item. """
    if _dict_WCSPlayers[player1]['level'] >  _dict_WCSPlayers[player2]['level']: return -1
    if _dict_WCSPlayers[player1]['level'] == _dict_WCSPlayers[player2]['level']: return 0
    return 1

def _cc_filter(userid, args):
    """ Tests to see if the user tried to buy a restricted item, if so, deny them """
    if args[0].lower() == 'buy' and len(args) > 1:
        weapon  = args[1].lower().replace('weapon_','')
        race    = GetRace(userid)
        racekey = Race(race).returnRaceKey()
        if racekey.has_key('restriction type'):
            if racekey['restriction type'] == 'allow only':
                if weapon not in racekey['weapons list']:
                    es.tell(userid,'#multi',text('weapon restricted',{'race':race},playerlib.getPlayer(userid).get('lang')))
                    debugMsg(1, 'Denied %s access to buy weapon %s' % (es.getplayername(userid), weapon ) )
                    return False
            elif racekey['restriction type'] == 'block only':
                if weapon in racekey['weapons list']:
                    es.tell(userid,'#multi',text('weapon restricted',{'race':race},playerlib.getPlayer(userid).get('lang')))
                    debugMsg(1, 'Denied %s access to buy weapon %s' % (es.getplayername(userid), weapon ) )
                    return False
        if weapon in Command(userid)['Restricted']:
            es.tell(userid,'#multi',text('weapon restricted',{'race':race},playerlib.getPlayer(userid).get('lang')))
            debugMsg(1, 'Denied %s access to buy weapon %s' % (es.getplayername(userid), weapon ) )
            return False
    return True
es.addons.registerClientCommandFilter(_cc_filter)

def debugMsg(level, text, addToFile=True, writeTime=True):
    """ This method prints text to the console, and if addToFile is true, it will
        open a log file and append the log and time to it. """
    if level <= int(es.ServerVar('wcs_debug')):
        if isOb:
            tempText = text
            while len(tempText) > 200:
                index    = tempText[:200].rfind(' ')
                es.dbgmsg(0, tempText[:index])
                tempText = tempText[index:]
            es.dbgmsg(0, tempText)
        else:
            print text
        if addToFile:
            strfile = es.getAddonPath('wcs') + '/debuglog.txt'
            if not os.path.isfile(strfile):
                myfile = open(strfile, 'w')
            else:
                myfile = open(strfile, 'a')
            if writeTime:
                myfile.writelines(time.strftime('%A %m %Y - %H:%M:%S') + " - " + text + "\n")
            else:
                myfile.writelines(text + "\n")
            myfile.close()
            
def loadPopupFiles(popupFile):
    """ Load all the popups from the file. Allows for multi-lingual popup support """
    debugMsg(1, '\n***************************************\nLoading Popup: %s' % popupFile, writeTime = False)
    currentLine  = ""
    language     = popupFile.split('_')[-1].split('.')[0]
    if language == 'en' and dir == 'hl2mp':
        language = 'default'
    debugMsg(1, 'The popup language is: %s' % language, writeTime = False)
    languageFile = open(popupFile, 'r')
    debugMsg(2, 'Language file: %s' % languageFile, writeTime = False)
    popupDict[language] = {}
    debugMsg(2, 'Created the language file in popupDict', writeTime = False)
    trueLines = filter(lambda x: bool(x.replace(' ','')) and not x.startswith('#'), languageFile)
    debugMsg(1, 'The number of lines in popup file (%s) without comments or spaces are: %s\n' % (language, len(trueLines) ), writeTime = False)
    for line in trueLines:
        debugMsg(3, 'Adding line Without Being Stripped: %s' % repr(line), writeTime = False)
        line = line.strip()
        debugMsg(3, 'Adding line After Being Stripped: %s' % repr(line), writeTime = False)
        test = re.compile('[[][a-zA-Z0-9 ]*[]]').search(line)
        debugMsg(3, 'Is the line a popup title? %s' % test, writeTime = False)
        if test:
            line        = line.replace('[','').replace(']','')
            debugMsg(3, 'The popup title is: %s' % line, writeTime = False)
            currentLine = line
            popupDict[language][line] = []
        else:
            debugMsg(3, 'Adding line to language %s with the popup name %s' % (language, currentLine), writeTime = False)
            if popupDict.has_key(language) and currentLine in popupDict[language]:
                popupDict[language][currentLine].append(line + '\n')
                debugMsg(3, 'The line has finished and been appended to the current popup in memory', writeTime = False)
        debugMsg(3, '', writeTime = False)
    languageFile.close()
    debugMsg(1, 'Finished loading the popups.\n***************************************\n')
popupDict = {}

def loadPopup(popup, tokens={}, lang="en"):
    """ Returns the popup string, with all the tokens replaced """
    debugMsg(2, '\nInside the loadPopup Function where we are getting the popup %s for language %s' % (popup, lang) )
    if not popupDict.has_key(lang):
        debugMsg(2, 'The popups do not contain language %s, thus reverting to English' % lang)
        lang = "en"
    if not popupDict[lang].has_key(popup):
        debugMsg(2, 'Popup %s does not exist in language %s'% (popup, lang) )
        return ""
    lineList = popupDict[lang][popup]
    lineStr  = ""
    debugMsg(3, 'Starting the popup Build....')
    for line in lineList:
        debugMsg(3, 'Testing line %s' % line.replace('\n',''))
        if line[0].isdigit() and str(line[0]) != '0':
            debugMsg(3, 'The line is a selectable line but has not \'->\' at the start and does not start with 0.')
            line = "->" + line
        if tokens and line.count('$'):
            """ If there are tokens to be substituted, and there is at least 1 $ on the line, substitute it. """
            debugMsg(3, 'Line contains something to be substituted')
            if line.count('$blankline'):
                lineStr += " \n"
                line = line.replace('$blankline','')
            s = Template(line)
            s = s.substitute(tokens)
            lineStr += str(s)
            debugMsg(3, 'Adding line %s to popup %s' % (s.replace('\n',''), popup) )
        else:
            lineStr += line
            debugMsg(3, 'Adding line %s to popup %s' % (line.replace('\n',''), popup) )
    debugMsg(2, 'Finished the popup - the popup is as follows:\n%s\n' % lineStr)
    return lineStr
    
def returnAllLanguages(popup, tokens={}):
    """ This just returns all the languages of that popup
        in a nice dictionary so we can just use:
        popup_instance.addline(returnAllLanguages('popup', tokens) ) """
    debugMsg(2, 'Returning All the language for popup %s' % popup)
    languageDict = {}
    for language in popupDict:
        debugMsg(2, 'Atempting to find the language: %s' % language)
        if popupDict[language].has_key(popup):
            debugMsg(2, 'Popup %s found in language %s, adding to the dictionary now.' % (popup, language) )
            languageDict[language] = loadPopup(popup, tokens, language)
    debugMsg(2, 'The language dictionary being returned is as follows:\n    %s' % languageDict, writeTime=False)
    return languageDict
    
def wrapDictionaryItems(items, value, splitter = "-"):
    """ Wraps it up so you can loop through a dictionary,
        and add all the items of that dictionary to a string,
        compared with the value[item] split via a splitter """
    tempStr = ""
    for item in items:
        tempStr += "%s %s %s\n" % (item, splitter, value[item])
    return tempStr

def addline(popupInstance, lines):
    """ Make it so it adds individual lines to the popup instance rather than 1 huge string """
    if dir == 'hl2mp':
        tempLines = []
        for language in lines:
            lines[language] = lines[language].split('\n')
        index = 0
        while index < len(lines[list(lines)[0]]):
            tempLines.append({})
            for language in lines:
                tempLines[index][language] = lines[language][index]
            index += 1
        for line in tempLines:
            popupInstance.addline(line)
    else:
        popupInstance.addline(lines)

def wcs_levelup(ev):
    buildRaceMenu(ev['userid'])

def runKeygroupRace(userid, race, skillType, ultimate = False):
    """ Run a skill from a keygroup race. """
    if race in keygroupraces:
        skillsCfg  = str(keygroupraces[race]['race']['skillcfg']).split('|')
        skillCount = 1
        for skillCfg in skillsCfg:
            if skillCfg == skillType:
                try:
                    es.ServerVar('wcs_dice').set(random.randint(1,100) )
                    if ultimate is not False:
                        es.ServerVar('wcs_userid').set(userid)
                        
                    skillTypeTitle = skillType.replace('_',' ').title()
                    debugMsg(1, '\n---------------------\nRunning keygroup race %s event %s' % (race,  skillTypeTitle) )
                    
                    skillName     = str(keygroupraces[race]['race']['skillnames']).split('|')[skillCount-1]
                    skillLevel    = GetLevel(userid, race, skillName)
                    
                    debugMsg(1, 'Skill %s, Level: %s' % (skillName, skillLevel) )
                    
                    skillSetting  = str(keygroupraces[race]['race']['skill%s_setting' % skillCount]).split('|')[skillLevel -1]
                    skillCommand  = keygroupraces[race]['race']['skill%s_cmd' % skillCount]
                    effectCommand = None
                    
                    if 'skill%s_sfx' % skillCount in keygroupraces[race]['race'] and keygroupraces[race]['race']['skill%s_sfx'%skillCount] not in ('0', 0):
                        effectCommand = keygroupraces[race]['race']['skill%s_sfx'%skillCount]
                        
                    if isOb:
                        if race in dictAlias:
                            for alias in dictAlias[race]:
                                if alias in skillSetting:
                                    skillSetting = skillSetting.replace(alias, "%s_%s" % (alias, race) )
                                if alias in skillCommand:
                                    skillCommand = skillCommand.replace(alias, "%s_%s" % (alias, race) )
                                if effectCommand and alias in skillCommand:
                                    effectCommand = effectCommand.replace(alias, "%s_%s" % (alias, race) )
                                    
                    debugMsg(2, '--------------------\n%s Setting: %s' % (skillTypeTitle, skillSetting), writeTime = False)
                    debugMsg(2, '%s Command: %s' % (skillTypeTitle, skillCommand), writeTime = False )
                    if effectCommand:
                        debugMsg(2, '%s Effect: %s' % (skillTypeTitle, effectCommand), writeTime = False)
                    debugMsg(2, '--------------------', writeTime = False)
                    
                    if isOb:
                        for command in skillSetting.split(';'):
                            es.server.queuecmd(command)
                        for command in skillCommand.split(';'):
                            es.server.queuecmd(command)
                        if effectCommand:
                            for command in effectCommand.split(';'):
                                es.server.queuecmd(command)
                    else:                                    
                        es.server.queuecmd(skillSetting)
                        es.server.queuecmd(skillCommand)
                        if effectCommand:
                            es.server.queuecmd(effectCommand)
                    
                    if ultimate is not False:
                        if 'ultimate_cooldown' in keygroupraces[race]['race']:
                            cooldown = str(keygroupraces[race]['race']['ultimate_cooldown']).split('|')
                            if len(cooldown) > 1:
                                cooldown = cooldown[skillLevel - 1]
                                debugMsg(2, 'Assigning cooldown to skill %s for %s seconds' % (skillName, cooldown) )
                                Command(userid).SetCoolDown(skillName, cooldown)
                            else:
                                debugMsg(2, 'Assigning cooldown to skill %s for %s seconds' % (skillName, cooldown[0]) )
                                Command(userid).SetCoolDown(skillName, cooldown[0])
                    debugMsg(1, 'Keygrouprace skill has finished\n---------------------\n')
                except IndexError:
                    debugMsg(0, 'Keygroup Race %s\'s skill number %s is broken due to incorrect number of levels' % (race, skillCount) )
            skillCount += 1
