print "Loading mod: autoaim_indicator v2016-10-05 (http://forum.worldoftanks.eu/index.php?/topic/441413-)"
"""
AutoAim indicator+snapping
by Krzysztof_Chodak aka Kodak
"""
import BigWorld, ResMgr, GUI, json, os, time, VehicleGunRotator, Math, CommandMapping, math, inspect, Vehicle
from debug_utils import LOG_NOTE, LOG_ERROR
from gui.app_loader import g_appLoader
from gui.app_loader.settings import GUI_GLOBAL_SPACE_ID as _SPACE_ID
from PlayerEvents import g_playerEvents
from constants import ARENA_PERIOD, ARENA_BONUS_TYPE, AIMING_MODE
from gui import g_guiResetters, g_repeatKeyHandlers, GUI_SETTINGS, SystemMessages
from AvatarInputHandler.control_modes import ArcadeControlMode, StrategicControlMode
from collections import OrderedDict
from gui.battle_control import g_sessionProvider
from gui.battle_control.battle_constants import GUN_RELOADING_VALUE_TYPE

config = {}
config_error = None
old_autoAim = None
old_onAutoAimVehicleLost = None
indicator = None
myEventsAttached = False
toggleKey = 0
toggleStateOn = True
enemies_alive = {}
allies_alive = {}
bw_player = None
playerVehicle = None
cw_fow_mode = None
aa_delay_cb = 0
texts = {}
d = False
ammoCtrl = None
clipSize = 0
last_shortcut_used = None
devices_to_repair_with_T = {}
LARGEREPAIRKIT = 1531
SMALLREPAIRKIT = 1275
last_timeLeft = -1
cmdMap = None
last_command = None
last_key = None
mods_log = None
key_CMD_CM_FREE_CAMERA = None
old_shoot = None
last_enemy_killed_id = None
last_enemy_killed_time = 0

def MYLOGLIVE(message, permanent_log = True, make_red = True):
    from messenger import MessengerEntry
    if message=="":
        return
    if permanent_log:
        LOG_NOTE(message)
    if make_red:
        message = '<font color="#FF0000">' + message + '</font>'
    MessengerEntry.g_instance.gui.addClientMessage(message)

def MYLOGLIVE_GARAGE(message, permanent_log = True, make_red = True):
    if message=="":
        return
    if permanent_log:
        MYLOG(message)
    msg_type = SystemMessages.SM_TYPE.Information
    if make_red:
        message = '<font color="#FF0000">' + message + '</font>'
        msg_type = SystemMessages.SM_TYPE.Warning
    try:
        SystemMessages.pushMessage(message, type=msg_type)
    except:
        pass

def MYLOG(msg, *args):
    if d:
        import datetime
        output = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
        if args:
            output = ' '.join(map(str, [output, msg, args]))
        else:
            output = ' '.join(map(str, [output, msg]))
        mods_log.write(output + '\n')
    LOG_NOTE(msg, *args)

def PT2STR(obj):
    return "x=%f, y=%f, z=%f" % (obj.x, obj.y, obj.z)

def MYPPRINT(obj, name = None):
    import inspect, pprint
    if isinstance(obj, dict) or isinstance(obj, list):
        pprint.pprint(obj)
    elif isinstance(obj, Math.Vector3):
        if name is None:
            print PT2STR(obj)
        else:
            print "%s: %s" % (name, PT2STR(obj))
    elif hasattr(obj, '__call__'):
        pprint.pprint(inspect.getargspec(obj))
    else:
        pprint.pprint(inspect.getmembers(obj))

def _LOG_EXECUTING_TIME(startTime, methodName, deltaTime = 0.1):
    finishTime = time.time()
    if finishTime - startTime > deltaTime:
        LOG_ERROR('Method "%s" takes %s%s' % (methodName, "too much time " if deltaTime > 0 else "", finishTime - startTime))

def myPe_onArenaPeriodChange(period = ARENA_PERIOD.BATTLE, *args):
    global old_autoAim
    global old_onAutoAimVehicleLost
    global indicator
    global myEventsAttached
    global bw_player
    global playerVehicle
    global cw_fow_mode
    global ammoCtrl
    global clipSize
    global last_timeLeft
    global key_CMD_CM_FREE_CAMERA
    global old_shoot
    #if not g_appLoader.getSpaceID() is _SPACE_ID.BATTLE:
    #    return
    bw_player = BigWorld.player()
    if period is ARENA_PERIOD.BATTLE:
        if g_appLoader.getDefBattleApp() is None:
            if (d): MYLOG("g_appLoader.getDefBattleApp() is None. waiting")
            BigWorld.callback(1, myPe_onArenaPeriodChange)
            return
        arena = bw_player.arena
        vehicles = arena.vehicles
        if bw_player.isVehicleAlive:
            playerVehicleID = bw_player.playerVehicleID
            playerVehicle = BigWorld.entity(playerVehicleID)
            if (d): MYLOG("arena.bonusType = %d" % arena.bonusType)
            cw_fow_mode = arena.bonusType in [
                ARENA_BONUS_TYPE.CLAN,
                ARENA_BONUS_TYPE.EVENT_BATTLES,
                ARENA_BONUS_TYPE.GLOBAL_MAP,
                ARENA_BONUS_TYPE.FALLOUT_CLASSIC,
                ARENA_BONUS_TYPE.FALLOUT_MULTITEAM
            ]
            for vehicleID, desc in vehicles.items():
                if desc['isAlive']==True:
                    if bw_player.team is desc['team']:
                        if not vehicleID is playerVehicleID:
                            allies_alive[vehicleID] = True
                    else:
                        enemies_alive[vehicleID] = True
            if d: MYLOG("enemies_alive (%d): %s" % (len(enemies_alive), str(enemies_alive.keys())))
            if indicator is None:
                if config.get("enable_panel", True):
                    indicator = TextLabel(config.get('autoaim_indicator_panel', {}))
                    onChangeScreenResolution()
                new_autoAim(None, True)
            if not myEventsAttached:
                old_autoAim = bw_player.autoAim
                bw_player.autoAim = new_autoAim
                old_onAutoAimVehicleLost = bw_player.onAutoAimVehicleLost
                bw_player.onAutoAimVehicleLost = new_onAutoAimVehicleLost
                arena.onVehicleKilled += myOnVehicleKilled
                bw_player.onVehicleEnterWorld += myOnVehicleEnterWorld
                old_shoot = bw_player.shoot
                bw_player.shoot = new_shoot
                myEventsAttached = True
            ammoCtrl = g_sessionProvider.shared.ammo
            if config["addon-auto_announce_reload"]["clip_reload"]:
                clipSize = ammoCtrl._AmmoController__gunSettings.clip.size
            else:
                clipSize = 1
            last_timeLeft = -1
            ammoCtrl.onGunReloadTimeSet += onGunReloadTimeSet
        else:
            cleanUp()
        key_CMD_CM_FREE_CAMERA = CommandMapping.g_instance.get('CMD_CM_FREE_CAMERA')
    elif period is ARENA_PERIOD.AFTERBATTLE:
        cleanUp()

def cleanUp():
    global old_autoAim
    global old_onAutoAimVehicleLost
    global indicator
    global myEventsAttached
    global playerVehicle
    global old_shoot
    if myEventsAttached:
        bw_player.autoAim = old_autoAim
        old_autoAim = None
        bw_player.onAutoAimVehicleLost = old_onAutoAimVehicleLost
        old_onAutoAimVehicleLost = None
        if bw_player.arena:
            bw_player.arena.onVehicleKilled -= myOnVehicleKilled
        bw_player.onVehicleEnterWorld -= myOnVehicleEnterWorld
        bw_player.shoot = old_shoot
        old_shoot = None
        myEventsAttached = False
    if not indicator is None:
        GUI.delRoot(indicator.window)
        indicator = None
    enemies_alive.clear()
    allies_alive.clear()
    playerVehicle = None
    texts.clear()

def new_CommandMapping_isFired(self, command, key):
    global cmdMap, last_command, last_key
    cmdMap, last_command, last_key = self, command, key
    return old_CommandMapping_isFired(self, command, key)
    
old_CommandMapping_isFired = CommandMapping.CommandMapping.isFired
CommandMapping.CommandMapping.isFired = new_CommandMapping_isFired

def new_autoAim(target, init = False):
    global aa_delay_cb
    startTime = time.time()
    if (d): MYLOG("new_autoAim(%s, %s)" % (str(type(target)), str(init)))
    prevAutoAimVehicleID = 0
    if not init:
        prevAutoAimVehicleID = bw_player._PlayerAvatar__autoAimVehID
        old_autoAim(target)
    autoAimVehicleID = bw_player._PlayerAvatar__autoAimVehID
    enabled = autoAimVehicleID != 0
    if enabled:
        if indicator and config.get("use_target_as_text", True):
            indicator.setText(texts.setdefault(autoAimVehicleID, \
                target.typeDescriptor.type.shortUserString[0:config.get("max_characters", 15)-1])) #BigWorld.entity(autoAimVehicleID)
    if indicator:
        indicator.setVisible(enabled)
    if not init and (prevAutoAimVehicleID==0 or config.get("snap_continously", False)) and not enabled and config.get("snap_to_nearest", True):
        if isinstance(bw_player.inputHandler.ctrl, StrategicControlMode):
            if (d): MYLOG("StrategicControlMode used")
            return            
            if (d): MYLOG("disable autoaim used")
        if config.get("no_snap_on_autoaim_off_E", True) and last_command is CommandMapping.CMD_CM_LOCK_TARGET_OFF:
            return
        snappingDelay = config.get("snappingDelay", 0.2)
        if BigWorld.isKeyDown(key_CMD_CM_FREE_CAMERA) and snappingDelay > 0:
            if (d): MYLOG("delaying %.2fs (key=%d)" % (snappingDelay, key_CMD_CM_FREE_CAMERA))
            if aa_delay_cb:
                BigWorld.cancelCallback(aa_delay_cb)
            aa_delay_cb = BigWorld.callback(snappingDelay, lambda: trySnapping(key_CMD_CM_FREE_CAMERA))
        else:
            BigWorld.callback(0, trySnapping)
    _LOG_EXECUTING_TIME(startTime, 'new_autoAim')

def trySnapping(key = 0):
    global aa_delay_cb
    startTime = time.time()
    aa_delay_cb = 0
    isKeyDown = False
    if key:
        isKeyDown = BigWorld.isKeyDown(key)
    if not isKeyDown:
        if (d): MYLOG("snapping")
        new_target = findTarget(enemies_alive)
        if new_target:
            new_autoAim(new_target)
    else:
        if (d): MYLOG("key still pressed - no snapping")
    _LOG_EXECUTING_TIME(startTime, 'trySnapping')

def findTarget(vehicles_alive):
    if isinstance(bw_player.inputHandler.ctrl, ArcadeControlMode):
        desiredShotPoint = bw_player.inputHandler.ctrl.camera.aimingSystem.getThirdPersonShotPoint()
    else:
        desiredShotPoint = bw_player.inputHandler.getDesiredShotPoint()
        if desiredShotPoint is None:
            if (d): MYLOG("No desiredShotPoint available - trying alternative")
            desiredShotPoint = bw_player.gunRotator.markerInfo[0]
    if desiredShotPoint is None:
        MYLOG("No desiredShotPoint available")
        return None
    else:
        new_target = None
        distance_to_target = math.radians(config.get("snapping_angle_degrees", 7.5))
        new_target_m = None
        distance_to_target_m = int(config.get("useDistanceBelowM", 0))            
        #http://stackoverflow.com/questions/4143256/finding-the-angles-for-the-x-y-and-z-axis-in-3d-opengl-c
        camera = BigWorld.camera().position
        v1norm = normalize(desiredShotPoint - camera)
        for vehicleID in vehicles_alive.keys():
            vehicle = BigWorld.entity(vehicleID)
            if not vehicle is None:
                v2norm = normalize(vehicle.position - camera)
                distance = math.acos(v1norm.x * v2norm.x + v1norm.y * v2norm.y + v1norm.z * v2norm.z)
                if distance < 0:
                    distance = -distance
                if distance > math.pi:
                    distance = 2 * math.pi - distance
                if distance < distance_to_target:
                    new_target = vehicle
                    distance_to_target = distance
                if distance_to_target_m:
                    try:
                        position = playerVehicle.position
                    except BigWorld.EntityIsDestroyedException:
                        return None
                    else:
                        distance = position.flatDistTo(vehicle.position)
                        if distance < distance_to_target_m:
                            new_target_m = vehicle
                            distance_to_target_m = distance
        if new_target is None and not new_target_m is None:
            if (d): MYLOG("new target acquired at %f meters" % distance_to_target_m)
            new_target = new_target_m
        elif not new_target is None:
            if (d): MYLOG("new target acquired at %f degrees" % math.degrees(distance_to_target))
        return new_target
                
def normalize(v):
    return v / math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)

def new_onAutoAimVehicleLost():
    old_onAutoAimVehicleLost()
    if indicator:
        indicator.setVisible(False)
    
def myOnVehicleKilled(vehicleID, *args):
    global last_enemy_killed_id
    global last_enemy_killed_time
    if vehicleID == playerVehicle.id:
        if not bw_player.arena.bonusType in [
                ARENA_BONUS_TYPE.EVENT_BATTLES,
                ARENA_BONUS_TYPE.FALLOUT_CLASSIC,
                ARENA_BONUS_TYPE.FALLOUT_MULTITEAM
            ]:
            cleanUp()
    else:
        try:
            del enemies_alive[vehicleID]
            last_enemy_killed_id = vehicleID
            last_enemy_killed_time = time.time()
        except KeyError:
            try:
                del allies_alive[vehicleID]
            except KeyError:
                pass

def myOnVehicleEnterWorld(vehicle):
    vehicleID = vehicle.id
    if cw_fow_mode and vehicle.isAlive() and bw_player.team is not vehicle.publicInfo['team']: #bw_player.arena.vehicles[vehicleID]['team']:
        enemies_alive[vehicleID] = True
        
# borrowed from https://github.com/macrosoft/wothp/blob/master/src/totalhp.py
class TextLabel(object):
    label = None
    shadow = None
    window = None
    color = '\cFFFFFFFF;'
    visible = True
    x = 0
    y = 0
    hcentered = False
    vcentered = False
    mainCaliberValue = 0

    def __init__(self, config):
        if config.get('color', False):
            self.color = '\c' + config.get('color')[1:] + 'FF;'
        self.visible = config.get('visible', True)
        self.x  = config.get('x', 0)
        self.y  = config.get('y', 0)
        self.hcentered  = config.get('hcentered', False)
        self.vcentered  = config.get('vcentered', False)
        background = os.path.join('scripts', 'client', 'gui', 'mods', config.get('background')) \
            if config.get('background', '') else ''
        self.window = GUI.Window(background)
        self.window.materialFX = "BLEND"
        self.window.verticalAnchor = "TOP"
        self.window.horizontalAnchor = "LEFT"
        self.window.horizontalPositionMode = 'PIXEL'
        self.window.verticalPositionMode = 'PIXEL'
        self.window.heightMode = 'PIXEL'
        self.window.widthMode = 'PIXEL'
        self.window.width = config.get('width', 186)
        self.window.height = config.get('height', 32)
        self.autoSize = True
        GUI.addRoot(self.window)
        font = config.get('font', 'default_medium.font')
        self.shadow = GUI.Text('')
        self.installItem(self.shadow, font)
        self.label = GUI.Text('')
        self.installItem(self.label, font)
        self.setText(config.get('text', ''))
        self.setVisible(self.visible)

    def installItem(self, item, font):
        item.font = font
        self.window.addChild(item)
        item.verticalAnchor = "CENTER"
        item.horizontalAnchor = "CENTER"
        item.horizontalPositionMode = 'PIXEL'
        item.verticalPositionMode = 'PIXEL'
        item.position = (self.window.width/2, self.window.height/2, 1)
        item.colourFormatting = True

    def setVisible(self, flag):
        flag = flag and self.visible
        self.window.visible = flag
        self.shadow.visible = flag
        self.label.visible = flag

    def setText(self, text, color = None):
        shadowText = text.replace('\c60FF00FF;','')
        self.shadow.text = '\c000000FF;' + shadowText
        color = '\c' + color + 'FF;' if color else self.color
        self.label.text = color + text

def onChangeScreenResolution():
    if indicator:
        sr = GUI.screenResolution()
        for panel in [indicator]:
            if panel is None:
                continue
            x = sr[0]/2 - panel.window.width /2 + panel.x if panel.hcentered else panel.x
            y = sr[1]/2 - panel.window.height/2 + panel.y if panel.vcentered else panel.y
            panel.window.position = (x, y, 1)

def myHandleRepeatKeyEvent(event):
    global toggleStateOn
    if GUI_SETTINGS.minimapSize:
        if event.repeatCount == 1:
            if (d): MYLOG("myHandleRepeatKeyEvent %d" % event.key)
            if event.key == toggleKey:
                if toggleStateOn:
                    toggleStateOn = False
                    g_playerEvents.onArenaPeriodChange -= myPe_onArenaPeriodChange
                    cleanUp()
                    MYLOGLIVE(config.get("toggledOffMsg", ""), make_red=False)
                else:
                    toggleStateOn = True
                    g_playerEvents.onArenaPeriodChange += myPe_onArenaPeriodChange
                    if not g_appLoader.getDefBattleApp() is None:
                        myPe_onArenaPeriodChange()
                    MYLOGLIVE(config.get("toggledOnMsg", ""), make_red=False)
                config["toggleStateOn"] = toggleStateOn
                with open(conf_file, 'w') as data_file:
                    try:
                        json.dump(config, data_file, sort_keys=True, indent=4, separators=(',', ': '))
                    except:
                        print "Error while saving %s: %s" % (conf_file, sys.exc_info()[0])

conf_file = './res_mods/mod_autoaim_indicator.json'
if not os.path.isfile(conf_file):
    conf_file = ResMgr.openSection('../paths.xml')['Paths'].values()[0:2][0].asString + '/scripts/client/gui/mods/mod_autoaim_indicator.json'
#print "config file: " + conf_file
if os.path.isfile(conf_file):
    with open(conf_file) as data_file:
        try:
            config = json.load(data_file)
            
            config.setdefault("addon-auto_announce_reload", {"enabled": False, "clip_reload": False, "reload_longer_than": 0})
            if config["addon-auto_announce_reload"].get("enabled", True):
                config["addon-auto_announce_reload"].setdefault("clip_reload", False)
                config["addon-auto_announce_reload"].setdefault("reload_longer_than", 0)
            else:
                config["addon-auto_announce_reload"]["clip_reload"] = False
                config["addon-auto_announce_reload"]["reload_longer_than"] = 0
            
            config.setdefault("addon-repair_with_T", {})
            if config["addon-repair_with_T"].get("enabled", True):
                data_file.seek(0)
                config_ordered = json.load(data_file, object_pairs_hook=OrderedDict)
                devices_to_repair_with_T = config_ordered.get("addon-repair_with_T", {}).get("devices", {})
        except:
            import sys
            print "Error while loading %s: %s" % (conf_file, sys.exc_info()[0])
            config_error = "autoaim_indicator mod: configuration file corrupted - running on default values"
else:
    config_error = "autoaim_indicator mod: configuration file missing - running on default values"
    
toggleKey = config.get("toggleKeyCode", 0)
d = config.get("debug", False)
if d:
    mods_log = open('mod_autoaim_indicator.log', 'a+')

if toggleKey > 0:
    if (d): MYLOG("g_repeatKeyHandlers.add(myHandleRepeatKeyEvent)")
    g_repeatKeyHandlers.add(myHandleRepeatKeyEvent)
    toggleStateOn = config.get("toggleStateOn", True)
if toggleStateOn:
    g_playerEvents.onArenaPeriodChange += myPe_onArenaPeriodChange
    g_guiResetters.add(onChangeScreenResolution)

def myOnAccountBecomePlayer(*args):
    if config_error:
        MYLOGLIVE_GARAGE(config_error)

def myOnAvatarBecomeNonPlayer(*args):
    cleanUp()

g_playerEvents.onAccountBecomePlayer += myOnAccountBecomePlayer
g_playerEvents.onAvatarBecomeNonPlayer += myOnAvatarBecomeNonPlayer

config.setdefault("attack_snapping", True)
config.setdefault("follow_me_snapping", True)

if devices_to_repair_with_T:
    from gui.battle_control import g_sessionProvider
    from gui.battle_control.battle_constants import VEHICLE_DEVICE_IN_COMPLEX_ITEM, DEVICE_STATE_AS_DAMAGE
    from constants import VEHICLE_SETTING

def checkForRepairs():
    other_devices = config["addon-repair_with_T"].get("other_forcing_large_kit", {})
    to_repair = []
    other_found = False
    for deviceName, stateName in bw_player.deviceStates.iteritems():
        if stateName in DEVICE_STATE_AS_DAMAGE:
            if (d): MYLOG("%s is %s" % (deviceName, stateName))
            repairable_states = devices_to_repair_with_T.get(deviceName, [])
            if repairable_states and stateName in repairable_states:
                to_repair.append(deviceName)
                continue
            repairable_states = other_devices.get(deviceName, [])
            if repairable_states and stateName in repairable_states:
                other_found = True
    if to_repair:
        equipmentsCtrl = g_sessionProvider.shared.equipments
        if "leftTrack" in to_repair and "rightTrack" in to_repair:
            to_repair.remove("rightTrack")
        if (len(to_repair) > 1 or (to_repair and other_found)) and equipmentsCtrl.canActivate(LARGEREPAIRKIT)[0] and \
            config["addon-repair_with_T"].get("use_large_kit_when_two_damaged", True):
            if (d): MYLOG("Using large kit for %s (other found = %s)" % (", ".join(to_repair), other_found))
            bw_player.base.vehicle_changeSetting(VEHICLE_SETTING.ACTIVATE_EQUIPMENT,
                                                 equipmentsCtrl.getActivationCode(LARGEREPAIRKIT, None, bw_player))
            return True
        else:
            deviceName = None
            for deviceName in devices_to_repair_with_T.keys():
                if deviceName in to_repair:
                    break
            res = equipmentsCtrl.canActivate(SMALLREPAIRKIT, deviceName)
            if (d):
                MYLOG("canActivate SMALLREPAIRKIT for %s? %s" % (deviceName, res[0]))
                #MYPPRINT(res[1])
            if res[0]:
                if (d): MYLOG("Using small kit for %s" % deviceName)
                bw_player.base.vehicle_changeSetting(VEHICLE_SETTING.ACTIVATE_EQUIPMENT,
                                                     equipmentsCtrl.getActivationCode(SMALLREPAIRKIT, deviceName, bw_player))
                return True
            res = equipmentsCtrl.canActivate(LARGEREPAIRKIT)
            if (d):
                MYLOG("canActivate LARGEREPAIRKIT? %s" % res[0])
                #MYPPRINT(res[1])
            if res[0]:
                if (d): MYLOG("Using large kit for %s" % deviceName)
                bw_player.base.vehicle_changeSetting(VEHICLE_SETTING.ACTIVATE_EQUIPMENT,
                                                     equipmentsCtrl.getActivationCode(LARGEREPAIRKIT, None, bw_player))
                return True
    return False

#from gui.Scaleform.daapi.view.battle.legacy.RadialMenu import RadialMenu
#
# def RadialMenu__getMappedCommand(self, shortcut):
#     global last_shortcut_used
#     if (d):
#         MYLOG("RadialMenu__getMappedCommand(%s)" % shortcut)
#     last_shortcut_used = shortcut
#     return old_RadialMenu__getMappedCommand(self, shortcut)
# 
# old_RadialMenu__getMappedCommand = RadialMenu._RadialMenu__getMappedCommand
# RadialMenu._RadialMenu__getMappedCommand = RadialMenu__getMappedCommand
# 
# def RadialMenu__isTargetCorrect(self, *args):
#     if (d):
#         MYLOG("RadialMenu__isTargetCorrect%s last_shortcut_used=%s" % (str(args), last_shortcut_used))
#     if bw_player:
#         if last_shortcut_used=="attack" and devices_to_repair_with_T and checkForRepairs()==True:
#             return False
#         if self._RadialMenu__currentTarget is None:
#             t = findTarget(enemies_alive)
#             if t is None and last_shortcut_used=="attack" and config["follow_me_snapping"]:
#                 if (d):
#                     MYLOG("snapping allies")
#                 t = findTarget(allies_alive)
#             if not t is None:
#                 self._RadialMenu__currentTarget = t
#     return old_RadialMenu__isTargetCorrect(self, *args)
# 
# old_RadialMenu__isTargetCorrect = RadialMenu._RadialMenu__isTargetCorrect
# RadialMenu._RadialMenu__isTargetCorrect = RadialMenu__isTargetCorrect

from gui.battle_control.controllers.chat_cmd_ctrl import ChatCommandsController, KB_MAPPING, CHAT_COMMANDS, DEFAULT_CUT, TARGET_TRANSLATION_MAPPING

def ChatCommandsController_handleShortcutChatCommand(self, key):
    cmdMap = CommandMapping.g_instance
    player = BigWorld.player()
    target = BigWorld.target()
    for chatCmd, keyboardCmd in KB_MAPPING.iteritems():
        if cmdMap.isFired(keyboardCmd, key):
            if chatCmd==CHAT_COMMANDS.ATTACK:
                if devices_to_repair_with_T and checkForRepairs()==True:
                    return
                if target is None and config["attack_snapping"]:
                    target = findTarget(enemies_alive)
                    if target is None and config["follow_me_snapping"]:
                        if (d):
                            MYLOG("snapping allies")
                        target = findTarget(allies_alive)
            crosshairType = self._ChatCommandsController__getCrosshairType(player, target)
            if crosshairType != DEFAULT_CUT and chatCmd in TARGET_TRANSLATION_MAPPING and crosshairType in TARGET_TRANSLATION_MAPPING[chatCmd]:
                self.handleChatCommand(TARGET_TRANSLATION_MAPPING[chatCmd][crosshairType], target.id)
            else:
                self.handleChatCommand(chatCmd)

if devices_to_repair_with_T or config["attack_snapping"] or config["follow_me_snapping"]:
    ChatCommandsController.handleShortcutChatCommand = ChatCommandsController_handleShortcutChatCommand
    
def onGunReloadTimeSet(currShellCD, state, *args):
    global last_timeLeft
    if state.getValueType() == GUN_RELOADING_VALUE_TYPE.TIME:
        timeLeft = state.getTimeLeft()
        baseTime = state.getBaseValue()
        if timeLeft > 0:
            totalShots, shotsInClip = ammoCtrl.getCurrentShells()
            if d:
                MYLOG("onGunReloadTimeSet(timeLeft=%.2f, totalShots=%d, shotsInClip=%d, clipSize=%d" % (timeLeft, totalShots, shotsInClip, clipSize))
                #MYPPRINT(baseTime)
            if (config["addon-auto_announce_reload"]["clip_reload"] and clipSize > 1 and shotsInClip==0) or (timeLeft >= config["addon-auto_announce_reload"]["reload_longer_than"] and config["addon-auto_announce_reload"]["reload_longer_than"] > 0):
                if last_timeLeft < timeLeft:
                    if last_timeLeft != -1:
                        BigWorld.callback(0.1, lambda: g_sessionProvider.shared.chatCommands.sendReloadingCommand())
                    last_timeLeft = timeLeft
        else:
            last_timeLeft = 0

def new_shoot(isRepeat = False):
    if isRepeat == False and bw_player._PlayerAvatar__autoAimVehID==0:
        target = BigWorld.target()
        if target and isinstance(target, Vehicle.Vehicle):
            if not target.isAlive() and target.id == last_enemy_killed_id and time.time() - last_enemy_killed_time < 1.5 and config.get("addon-dead_shot_blocker", False):
                if d: MYLOG("Saving a dead-shot (direct)")
                bw_player.soundNotifications.play('target_unlocked')
                return
            if allies_alive.has_key(target.id) and config.get("addon-ally_shot_blocker", False) and not bw_player.arena.vehicles[target.id]["isTeamKiller"]:
                if d: MYLOG("Blocking an ally-shot")
                return
        elif time.time() - last_enemy_killed_time < 1.5 and config.get("addon-dead_shot_blocker", False) and findTarget({last_enemy_killed_id: True}) and findTarget(enemies_alive) is None:
            if d: MYLOG("Saving a dead-shot (proximity)")
            bw_player.soundNotifications.play('target_unlocked')
            return
    old_shoot(isRepeat)

def new_CommandMapping_isFired_plus(self, command, key):
    global cmdMap, last_command, last_key
    cmdMap, last_command, last_key = self, command, key
    return old_CommandMapping_isFired(self, command, key)

if config.get("no_snap_on_autoaim_off_E", True):
    CommandMapping.CommandMapping.isFired = new_CommandMapping_isFired_plus
