Пример #1
0
 def OnGraphSwitched(self, event):
     view = self.getView()
     GraphSettings.getInstance().set('selectedGraph', view.internalName)
     self.clearCache(reason=GraphCacheCleanupReason.graphSwitched)
     self.ctrlPanel.updateControls()
     self.draw()
     event.Skip()
Пример #2
0
 def _prepareApplicationMap(self, miscParams, src, tgt):
     tgtSpeed = miscParams['tgtSpeed']
     tgtSigRadius = tgt.getSigRadius()
     if GraphSettings.getInstance().get('applyProjected'):
         webMods, tpMods = self.graph._projectedCache.getProjModData(src)
         webDrones, tpDrones = self.graph._projectedCache.getProjDroneData(src)
         webFighters, tpFighters = self.graph._projectedCache.getProjFighterData(src)
         tgtSpeed = getWebbedSpeed(
             src=src,
             tgt=tgt,
             currentUnwebbedSpeed=tgtSpeed,
             webMods=webMods,
             webDrones=webDrones,
             webFighters=webFighters,
             distance=miscParams['distance'])
         tgtSigRadius = tgtSigRadius * getTpMult(
             src=src,
             tgt=tgt,
             tgtSpeed=tgtSpeed,
             tpMods=tpMods,
             tpDrones=tpDrones,
             tpFighters=tpFighters,
             distance=miscParams['distance'])
     # Get all data we need for all times into maps/caches
     applicationMap = getApplicationPerKey(
         src=src,
         tgt=tgt,
         atkSpeed=miscParams['atkSpeed'],
         atkAngle=miscParams['atkAngle'],
         distance=miscParams['distance'],
         tgtSpeed=tgtSpeed,
         tgtAngle=miscParams['tgtAngle'],
         tgtSigRadius=tgtSigRadius)
     return applicationMap
Пример #3
0
 def _getCommonData(self, miscParams, src, tgt):
     tgtSpeed = miscParams['tgtSpeed']
     tgtSigMult = 1
     if GraphSettings.getInstance().get('applyProjected'):
         webMods, tpMods = self.graph._projectedCache.getProjModData(src)
         webDrones, tpDrones = self.graph._projectedCache.getProjDroneData(src)
         webFighters, tpFighters = self.graph._projectedCache.getProjFighterData(src)
         tgtSpeed = getWebbedSpeed(
             src=src,
             tgt=tgt,
             currentUnwebbedSpeed=tgtSpeed,
             webMods=webMods,
             webDrones=webDrones,
             webFighters=webFighters,
             distance=miscParams['distance'])
         tgtSigMult = getTpMult(
             src=src,
             tgt=tgt,
             tgtSpeed=tgtSpeed,
             tpMods=tpMods,
             tpDrones=tpDrones,
             tpFighters=tpFighters,
             distance=miscParams['distance'])
     # Prepare time cache here because we need to do it only once,
     # and this function is called once per point info fetch
     self._prepareTimeCache(src=src, maxTime=miscParams['time'])
     return {
         'tgtSpeed': tgtSpeed,
         'tgtSigMult': tgtSigMult,
         'dmgMap': self._getDamagePerKey(src=src, time=miscParams['time']),
         'tgtResists': tgt.getResists()}
Пример #4
0
 def _getCommonData(self, miscParams, src, tgt):
     # Prepare time cache here because we need to do it only once,
     # and this function is called once per point info fetch
     self._prepareTimeCache(src=src, maxTime=miscParams['time'])
     return {
         'applyProjected': GraphSettings.getInstance().get('applyProjected'),
         'dmgMap': self._getDamagePerKey(src=src, time=miscParams['time']),
         'tgtResists': tgt.getResists()}
Пример #5
0
def getSigRadiusMult(src, tgt, tgtSpeed, srcScramRange, tgtScrammables, tpMods,
                     tpDrones, tpFighters, distance):
    # Can blow non-immune ships and target profiles
    if tgt.isFit and tgt.item.ship.getModifiedItemAttr(
            'disallowOffensiveModifiers'):
        return 1
    inLockRange = checkLockRange(src=src, distance=distance)
    inDroneRange = checkDroneControlRange(src=src, distance=distance)
    initSig = tgt.getSigRadius()
    # No scrams or distance is longer than longest scram - nullify scrammables list
    if not inLockRange or srcScramRange is None or (distance is not None and
                                                    distance > srcScramRange):
        tgtScrammables = ()
    # TPing modules
    appliedMultipliers = {}
    if inLockRange:
        for tpData in tpMods:
            appliedBoost = tpData.boost * calculateRangeFactor(
                srcOptimalRange=tpData.optimal,
                srcFalloffRange=tpData.falloff,
                distance=distance)
            if appliedBoost:
                appliedMultipliers.setdefault(tpData.stackingGroup, []).append(
                    (1 + appliedBoost / 100, tpData.resAttrID))
    # TPing drones
    mobileTps = []
    if inLockRange:
        mobileTps.extend(tpFighters)
    if inLockRange and inDroneRange:
        mobileTps.extend(tpDrones)
    droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
    atkRadius = src.getRadius()
    for mtpData in mobileTps:
        # Faster than target or set to follow it - apply full TP
        if (droneOpt == GraphDpsDroneMode.auto and mtpData.speed >= tgtSpeed
            ) or droneOpt == GraphDpsDroneMode.followTarget:
            appliedMtpBoost = mtpData.boost
        # Otherwise project from the center of the ship
        else:
            if distance is None:
                rangeFactorDistance = None
            else:
                rangeFactorDistance = distance + atkRadius - mtpData.radius
            appliedMtpBoost = mtpData.boost * calculateRangeFactor(
                srcOptimalRange=mtpData.optimal,
                srcFalloffRange=mtpData.falloff,
                distance=rangeFactorDistance)
        appliedMultipliers.setdefault(mtpData.stackingGroup, []).append(
            (1 + appliedMtpBoost / 100, mtpData.resAttrID))
    modifiedSig = tgt.getSigRadius(extraMultipliers=appliedMultipliers,
                                   ignoreAfflictors=tgtScrammables)
    if modifiedSig == math.inf and initSig == math.inf:
        return 1
    mult = modifiedSig / initSig
    # Ensure consistent results - round off a little to avoid float errors
    return floatUnerr(mult)
Пример #6
0
 def display(self, callingWindow, srcContext, mainItem, selection):
     if srcContext != 'graphTgtList':
         return False
     if GraphSettings.getInstance().get('ignoreResists'):
         return False
     if not isinstance(mainItem, TargetWrapper) or not mainItem.isFit:
         return False
     self.callingWindow = callingWindow
     self.selection = selection
     return True
Пример #7
0
def getDroneMult(drone, src, tgt, atkSpeed, atkAngle, distance, tgtSpeed, tgtAngle, tgtSigRadius):
    if (
        distance is not None and (
            (not GraphSettings.getInstance().get('ignoreDCR') and distance > src.item.extraAttributes['droneControlRange']) or
            (not GraphSettings.getInstance().get('ignoreLockRange') and distance > src.item.maxTargetRange))
    ):
        return 0
    droneSpeed = drone.getModifiedItemAttr('maxVelocity')
    # Hard to simulate drone behavior, so assume chance to hit is 1 for mobile drones
    # which catch up with target
    droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
    if (
        droneSpeed > 1 and (
            (droneOpt == GraphDpsDroneMode.auto and droneSpeed >= tgtSpeed) or
            droneOpt == GraphDpsDroneMode.followTarget)
    ):
        cth = 1
    # Otherwise put the drone into center of the ship, move it at its max speed or ship's speed
    # (whichever is lower) towards direction of attacking ship and see how well it projects
    else:
        droneRadius = drone.getModifiedItemAttr('radius')
        if distance is None:
            cthDistance = None
        else:
            # As distance is ship surface to ship surface, we adjust it according
            # to attacker ship's radiuses to have drone surface to ship surface distance
            cthDistance = distance + src.getRadius() - droneRadius
        cth = _calcTurretChanceToHit(
            atkSpeed=min(atkSpeed, droneSpeed),
            atkAngle=atkAngle,
            atkRadius=droneRadius,
            atkOptimalRange=drone.maxRange or 0,
            atkFalloffRange=drone.falloff or 0,
            atkTracking=drone.getModifiedItemAttr('trackingSpeed'),
            atkOptimalSigRadius=drone.getModifiedItemAttr('optimalSigRadius'),
            distance=cthDistance,
            tgtSpeed=tgtSpeed,
            tgtAngle=tgtAngle,
            tgtRadius=tgt.getRadius(),
            tgtSigRadius=tgtSigRadius)
    mult = _calcTurretMult(cth)
    return mult
Пример #8
0
def applyDamage(dmgMap, applicationMap, tgtResists):
    total = DmgTypes(em=0, thermal=0, kinetic=0, explosive=0)
    for key, dmg in dmgMap.items():
        total += dmg * applicationMap.get(key, 0)
    if not GraphSettings.getInstance().get('ignoreResists'):
        emRes, thermRes, kinRes, exploRes = tgtResists
        total = DmgTypes(em=total.em * (1 - emRes),
                         thermal=total.thermal * (1 - thermRes),
                         kinetic=total.kinetic * (1 - kinRes),
                         explosive=total.explosive * (1 - exploRes))
    return total
Пример #9
0
def getFighterAbilityMult(fighter, ability, src, distance, tgtSpeed,
                          tgtSigRadius):
    fighterSpeed = fighter.getModifiedItemAttr('maxVelocity')
    attrPrefix = ability.attrPrefix
    # It's bomb attack
    if attrPrefix == 'fighterAbilityLaunchBomb':
        # Just assume we can land bomb anywhere
        return _calcBombFactor(
            atkEr=fighter.getModifiedChargeAttr('aoeCloudSize'),
            tgtSigRadius=tgtSigRadius)
    droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
    # It's regular missile-based attack
    if (droneOpt == GraphDpsDroneMode.auto and fighterSpeed >= tgtSpeed
        ) or droneOpt == GraphDpsDroneMode.followTarget:
        rangeFactor = 1
    # Same as with drones, if fighters are slower - put them to center of
    # the ship and see how they apply
    else:
        if distance is None:
            rangeFactorDistance = None
        else:
            rangeFactorDistance = distance + src.getRadius(
            ) - fighter.getModifiedItemAttr('radius')
        rangeFactor = _calcRangeFactor(
            atkOptimalRange=fighter.getModifiedItemAttr(
                '{}RangeOptimal'.format(attrPrefix))
            or fighter.getModifiedItemAttr('{}Range'.format(attrPrefix)),
            atkFalloffRange=fighter.getModifiedItemAttr(
                '{}RangeFalloff'.format(attrPrefix)),
            distance=rangeFactorDistance)
    drf = fighter.getModifiedItemAttr('{}ReductionFactor'.format(attrPrefix),
                                      None)
    if drf is None:
        drf = fighter.getModifiedItemAttr(
            '{}DamageReductionFactor'.format(attrPrefix))
    drs = fighter.getModifiedItemAttr(
        '{}ReductionSensitivity'.format(attrPrefix), None)
    if drs is None:
        drs = fighter.getModifiedItemAttr(
            '{}DamageReductionSensitivity'.format(attrPrefix))
    missileFactor = _calcMissileFactor(
        atkEr=fighter.getModifiedItemAttr(
            '{}ExplosionRadius'.format(attrPrefix)),
        atkEv=fighter.getModifiedItemAttr(
            '{}ExplosionVelocity'.format(attrPrefix)),
        atkDrf=_calcAggregatedDrf(reductionFactor=drf,
                                  reductionSensitivity=drs),
        tgtSpeed=tgtSpeed,
        tgtSigRadius=tgtSigRadius)
    mult = rangeFactor * missileFactor
    return mult
Пример #10
0
 def yDefs(self):
     ignoreResists = GraphSettings.getInstance().get('ignoreResists')
     return [
         YDef(handle='dps',
              unit=None,
              label='DPS' if ignoreResists else 'Effective DPS'),
         YDef(handle='volley',
              unit=None,
              label='Volley' if ignoreResists else 'Effective volley'),
         YDef(handle='damage',
              unit=None,
              label='Damage inflicted'
              if ignoreResists else 'Effective damage inflicted')
     ]
Пример #11
0
def getTpMult(src, tgt, tgtSpeed, tpMods, tpDrones, tpFighters, distance):
    # Can blow non-immune ships and target profiles
    if tgt.isFit and tgt.item.ship.getModifiedItemAttr(
            'disallowOffensiveModifiers'):
        return 1
    untpedSig = tgt.getSigRadius()
    # Modules
    appliedMultipliers = {}
    for tpData in tpMods:
        appliedBoost = tpData.boost * calculateRangeFactor(
            srcOptimalRange=tpData.optimal,
            srcFalloffRange=tpData.falloff,
            distance=distance)
        if appliedBoost:
            appliedMultipliers.setdefault(tpData.stackingGroup, []).append(
                (1 + appliedBoost / 100, tpData.resAttrID))
    # Drones and fighters
    mobileTps = []
    mobileTps.extend(tpFighters)
    # Drones have range limit
    if distance is None or distance <= src.item.extraAttributes[
            'droneControlRange']:
        mobileTps.extend(tpDrones)
    droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
    atkRadius = src.getRadius()
    for mtpData in mobileTps:
        # Faster than target or set to follow it - apply full TP
        if (droneOpt == GraphDpsDroneMode.auto and mtpData.speed >= tgtSpeed
            ) or droneOpt == GraphDpsDroneMode.followTarget:
            appliedMtpBoost = mtpData.boost
        # Otherwise project from the center of the ship
        else:
            if distance is None:
                rangeFactorDistance = None
            else:
                rangeFactorDistance = distance + atkRadius - mtpData.radius
            appliedMtpBoost = mtpData.boost * calculateRangeFactor(
                srcOptimalRange=mtpData.optimal,
                srcFalloffRange=mtpData.falloff,
                distance=rangeFactorDistance)
        appliedMultipliers.setdefault(mtpData.stackingGroup, []).append(
            (1 + appliedMtpBoost / 100, mtpData.resAttrID))
    tpedSig = tgt.getSigRadius(extraMultipliers=appliedMultipliers)
    if tpedSig == math.inf and untpedSig == math.inf:
        return 1
    mult = tpedSig / untpedSig
    # Ensure consistent results - round off a little to avoid float errors
    return floatUnerr(mult)
Пример #12
0
def getTackledSpeed(src, tgt, currentUntackledSpeed, srcScramRange,
                    tgtScrammables, webMods, webDrones, webFighters, distance):
    # Can slow down non-immune ships and target profiles
    if tgt.isFit and tgt.item.ship.getModifiedItemAttr(
            'disallowOffensiveModifiers'):
        return currentUntackledSpeed
    maxUntackledSpeed = tgt.getMaxVelocity()
    # What's immobile cannot be slowed
    if maxUntackledSpeed == 0:
        return maxUntackledSpeed
    inLockRange = checkLockRange(src=src, distance=distance)
    inDroneRange = checkDroneControlRange(src=src, distance=distance)
    speedRatio = currentUntackledSpeed / maxUntackledSpeed
    # No scrams or distance is longer than longest scram - nullify scrammables list
    if not inLockRange or srcScramRange is None or (distance is not None and
                                                    distance > srcScramRange):
        tgtScrammables = ()
    appliedMultipliers = {}
    # Modules first, they are always applied the same way
    if inLockRange:
        for wData in webMods:
            appliedBoost = wData.boost * calculateRangeFactor(
                srcOptimalRange=wData.optimal,
                srcFalloffRange=wData.falloff,
                distance=distance)
            if appliedBoost:
                appliedMultipliers.setdefault(wData.stackingGroup, []).append(
                    (1 + appliedBoost / 100, wData.resAttrID))
    maxTackledSpeed = tgt.getMaxVelocity(extraMultipliers=appliedMultipliers,
                                         ignoreAfflictors=tgtScrammables)
    currentTackledSpeed = maxTackledSpeed * speedRatio
    # Drones and fighters
    mobileWebs = []
    if inLockRange:
        mobileWebs.extend(webFighters)
    if inLockRange and inDroneRange:
        mobileWebs.extend(webDrones)
    atkRadius = src.getRadius()
    # As mobile webs either follow the target or stick to the attacking ship,
    # if target is within mobile web optimal - it can be applied unconditionally
    longEnoughMws = [
        mw for mw in mobileWebs
        if distance is None or distance <= mw.optimal - atkRadius + mw.radius
    ]
    if longEnoughMws:
        for mwData in longEnoughMws:
            appliedMultipliers.setdefault(mwData.stackingGroup, []).append(
                (1 + mwData.boost / 100, mwData.resAttrID))
            mobileWebs.remove(mwData)
        maxTackledSpeed = tgt.getMaxVelocity(
            extraMultipliers=appliedMultipliers,
            ignoreAfflictors=tgtScrammables)
        currentTackledSpeed = maxTackledSpeed * speedRatio
    # Apply remaining webs, from fastest to slowest
    droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
    while mobileWebs:
        # Process in batches unified by speed to save up resources
        fastestMwSpeed = max(mobileWebs, key=lambda mw: mw.speed).speed
        fastestMws = [mw for mw in mobileWebs if mw.speed == fastestMwSpeed]
        for mwData in fastestMws:
            # Faster than target or set to follow it - apply full slowdown
            if (droneOpt == GraphDpsDroneMode.auto
                    and mwData.speed >= currentTackledSpeed
                ) or droneOpt == GraphDpsDroneMode.followTarget:
                appliedMwBoost = mwData.boost
            # Otherwise project from the center of the ship
            else:
                if distance is None:
                    rangeFactorDistance = None
                else:
                    rangeFactorDistance = distance + atkRadius - mwData.radius
                appliedMwBoost = mwData.boost * calculateRangeFactor(
                    srcOptimalRange=mwData.optimal,
                    srcFalloffRange=mwData.falloff,
                    distance=rangeFactorDistance)
            appliedMultipliers.setdefault(mwData.stackingGroup, []).append(
                (1 + appliedMwBoost / 100, mwData.resAttrID))
            mobileWebs.remove(mwData)
        maxTackledSpeed = tgt.getMaxVelocity(
            extraMultipliers=appliedMultipliers,
            ignoreAfflictors=tgtScrammables)
        currentTackledSpeed = maxTackledSpeed * speedRatio
    # Ensure consistent results - round off a little to avoid float errors
    return floatUnerr(currentTackledSpeed)
Пример #13
0
def checkDroneControlRange(src, distance):
    if distance is None:
        return True
    if GraphSettings.getInstance().get('ignoreDCR'):
        return True
    return distance <= src.item.extraAttributes['droneControlRange']
Пример #14
0
def checkLockRange(src, distance):
    if distance is None:
        return True
    if GraphSettings.getInstance().get('ignoreLockRange'):
        return True
    return distance <= src.item.maxTargetRange
Пример #15
0
 def tgtExtraCols(self):
     cols = []
     if not GraphSettings.getInstance().get('ignoreResists'):
         cols.append('Target Resists')
     cols.extend(('Speed', 'SigRadius', 'Radius'))
     return cols
Пример #16
0
 def __init__(self):
     self.mainFrame = gui.mainFrame.MainFrame.getInstance()
     self.settings = GraphSettings.getInstance()
Пример #17
0
def getWebbedSpeed(src, tgt, currentUnwebbedSpeed, webMods, webDrones,
                   webFighters, distance):
    # Can slow down non-immune ships and target profiles
    if tgt.isFit and tgt.item.ship.getModifiedItemAttr(
            'disallowOffensiveModifiers'):
        return currentUnwebbedSpeed
    maxUnwebbedSpeed = tgt.getMaxVelocity()
    try:
        speedRatio = currentUnwebbedSpeed / maxUnwebbedSpeed
    except ZeroDivisionError:
        currentWebbedSpeed = 0
    else:
        appliedMultipliers = {}
        # Modules first, they are applied always the same way
        for wData in webMods:
            appliedBoost = wData.boost * _calcRangeFactor(
                atkOptimalRange=wData.optimal,
                atkFalloffRange=wData.falloff,
                distance=distance)
            if appliedBoost:
                appliedMultipliers.setdefault(wData.stackingGroup, []).append(
                    (1 + appliedBoost / 100, wData.resAttrID))
        maxWebbedSpeed = tgt.getMaxVelocity(
            extraMultipliers=appliedMultipliers)
        currentWebbedSpeed = maxWebbedSpeed * speedRatio
        # Drones and fighters
        mobileWebs = []
        mobileWebs.extend(webFighters)
        # Drones have range limit
        if distance is None or distance <= src.item.extraAttributes[
                'droneControlRange']:
            mobileWebs.extend(webDrones)
        atkRadius = src.getRadius()
        # As mobile webs either follow the target or stick to the attacking ship,
        # if target is within mobile web optimal - it can be applied unconditionally
        longEnoughMws = [
            mw for mw in mobileWebs
            if distance is None or distance <= mw.optimal - atkRadius +
            mw.radius
        ]
        if longEnoughMws:
            for mwData in longEnoughMws:
                appliedMultipliers.setdefault(mwData.stackingGroup, []).append(
                    (1 + mwData.boost / 100, mwData.resAttrID))
                mobileWebs.remove(mwData)
            maxWebbedSpeed = tgt.getMaxVelocity(
                extraMultipliers=appliedMultipliers)
            currentWebbedSpeed = maxWebbedSpeed * speedRatio
        # Apply remaining webs, from fastest to slowest
        droneOpt = GraphSettings.getInstance().get('mobileDroneMode')
        while mobileWebs:
            # Process in batches unified by speed to save up resources
            fastestMwSpeed = max(mobileWebs, key=lambda mw: mw.speed).speed
            fastestMws = [
                mw for mw in mobileWebs if mw.speed == fastestMwSpeed
            ]
            for mwData in fastestMws:
                # Faster than target or set to follow it - apply full slowdown
                if (droneOpt == GraphDpsDroneMode.auto
                        and mwData.speed >= currentWebbedSpeed
                    ) or droneOpt == GraphDpsDroneMode.followTarget:
                    appliedMwBoost = mwData.boost
                # Otherwise project from the center of the ship
                else:
                    if distance is None:
                        rangeFactorDistance = None
                    else:
                        rangeFactorDistance = distance + atkRadius - mwData.radius
                    appliedMwBoost = mwData.boost * _calcRangeFactor(
                        atkOptimalRange=mwData.optimal,
                        atkFalloffRange=mwData.falloff,
                        distance=rangeFactorDistance)
                appliedMultipliers.setdefault(mwData.stackingGroup, []).append(
                    (1 + appliedMwBoost / 100, mwData.resAttrID))
                mobileWebs.remove(mwData)
            maxWebbedSpeed = tgt.getMaxVelocity(
                extraMultipliers=appliedMultipliers)
            currentWebbedSpeed = maxWebbedSpeed * speedRatio
    # Ensure consistent results - round off a little to avoid float errors
    return floatUnerr(currentWebbedSpeed)