예제 #1
0
    def getSubMenu(self, context, selection, rootMenu, i, pitem):
        m = wx.Menu()
        if "wxMSW" in wx.PlatformInfo:
            bindmenu = rootMenu
        else:
            bindmenu = m

        isNotDefault = self.mod.spoolType is not None and self.mod.spoolAmount is not None
        cycleDefault = self.mod.getSpoolData(spoolOptions=SpoolOptions(SpoolType.SCALE, eos.config.settings['globalDefaultSpoolupPercentage'], True))[0]
        cycleCurrent = self.mod.getSpoolData(spoolOptions=SpoolOptions(SpoolType.SCALE, eos.config.settings['globalDefaultSpoolupPercentage'], False))[0]
        cycleMin = self.mod.getSpoolData(spoolOptions=SpoolOptions(SpoolType.SCALE, 0, True))[0]
        cycleMax = self.mod.getSpoolData(spoolOptions=SpoolOptions(SpoolType.SCALE, 1, True))[0]

        for cycle in range(cycleMin, cycleMax + 1):
            menuId = ContextMenu.nextID()

            # Show default only for current value and when not overriden
            if not isNotDefault and cycle == cycleDefault:
                text = "{} (default)".format(cycle)
            else:
                text = "{}".format(cycle)

            item = wx.MenuItem(m, menuId, text, kind=wx.ITEM_CHECK)
            bindmenu.Bind(wx.EVT_MENU, self.handleSpoolChange, item)
            m.Append(item)
            item.Check(isNotDefault and cycle == cycleCurrent)
            self.cycleMap[menuId] = cycle

        self.resetId = ContextMenu.nextID()
        item = wx.MenuItem(m, self.resetId, "Reset")
        bindmenu.Bind(wx.EVT_MENU, self.handleSpoolChange, item)
        m.Append(item)

        return m
예제 #2
0
    def refreshPanel(self, fit):
        # If we did anything intresting, we'd update our labels to reflect the new fit's stats here
        if fit is not None and fit.targetProfile is not None:
            self.stEff.Show()
        else:
            self.stEff.Hide()

        def dpsToolTip(preSpool, fullSpool, prec, lowest, highest):
            if roundToPrec(preSpool, prec) == roundToPrec(fullSpool, prec):
                return ""
            else:
                return "Spool up: {}-{}".format(
                    formatAmount(preSpool, prec, lowest, highest),
                    formatAmount(fullSpool, prec, lowest, highest))

        defaultSpoolValue = eos.config.settings['globalDefaultSpoolupPercentage']
        stats = (
            (
                "labelFullDpsWeapon",
                lambda: fit.getWeaponDps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, defaultSpoolValue, False)).total,
                lambda: fit.getWeaponDps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).total,
                lambda: fit.getWeaponDps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).total,
                3, 0, 0, "{}{} DPS"),
            (
                "labelFullDpsDrone",
                lambda: fit.getDroneDps().total,
                lambda: fit.getDroneDps().total,
                lambda: fit.getDroneDps().total,
                3, 0, 0, "{}{} DPS"),
            (
                "labelFullVolleyTotal",
                lambda: fit.getTotalVolley(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, defaultSpoolValue, False)).total,
                lambda: fit.getTotalVolley(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).total,
                lambda: fit.getTotalVolley(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).total,
                3, 0, 0, "{}{}"),
            (
                "labelFullDpsTotal",
                lambda: fit.getTotalDps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, defaultSpoolValue, False)).total,
                lambda: fit.getTotalDps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).total,
                lambda: fit.getTotalDps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).total,
                3, 0, 0, "{}{}"))

        counter = 0
        for labelName, val, preSpoolVal, fullSpoolVal, prec, lowest, highest, valueFormat in stats:
            label = getattr(self, labelName)
            val = val() if fit is not None else 0
            preSpoolVal = preSpoolVal() if fit is not None else 0
            fullSpoolVal = fullSpoolVal() if fit is not None else 0
            if self._cachedValues[counter] != val:
                tooltipText = dpsToolTip(preSpoolVal, fullSpoolVal, prec, lowest, highest)
                label.SetLabel(valueFormat.format(
                    formatAmount(val, prec, lowest, highest),
                    "\u02e2" if tooltipText else ""))
                label.SetToolTip(wx.ToolTip(tooltipText))
                self._cachedValues[counter] = val
            counter += 1

        self.panel.Layout()
        self.headerPanel.Layout()
예제 #3
0
    def getYForX(self, fit, extraData, distance):
        tgtSpeed = extraData['speed']
        tgtSigRad = extraData['signatureRadius'] if extraData['signatureRadius'] is not None else inf
        angle = extraData['angle']
        tgtSigRadMods = []
        tgtSpeedMods = []
        total = 0
        distance = distance * 1000

        for mod in fit.modules:
            if not mod.isEmpty and mod.state >= FittingModuleState.ACTIVE:
                if "remoteTargetPaintFalloff" in mod.item.effects or "structureModuleEffectTargetPainter" in mod.item.effects:
                    tgtSigRadMods.append(
                        1 + (mod.getModifiedItemAttr("signatureRadiusBonus") / 100)
                        * self.calculateModuleMultiplier(mod, distance))
                if "remoteWebifierFalloff" in mod.item.effects or "structureModuleEffectStasisWebifier" in mod.item.effects:
                    if distance <= mod.getModifiedItemAttr("maxRange"):
                        tgtSpeedMods.append(1 + (mod.getModifiedItemAttr("speedFactor") / 100))
                    elif mod.getModifiedItemAttr("falloffEffectiveness") > 0:
                        # I am affected by falloff
                        tgtSpeedMods.append(
                            1 + (mod.getModifiedItemAttr("speedFactor") / 100) *
                            self.calculateModuleMultiplier(mod, distance))

        tgtSpeed = self.penalizeModChain(tgtSpeed, tgtSpeedMods)
        tgtSigRad = self.penalizeModChain(tgtSigRad, tgtSigRadMods)
        attRad = fit.ship.getModifiedItemAttr('radius', 0)
        defaultSpoolValue = eos.config.settings['globalDefaultSpoolupPercentage']

        for mod in fit.modules:
            dps = mod.getDps(targetResists=fit.targetResists, spoolOptions=SpoolOptions(SpoolType.SCALE, defaultSpoolValue, False)).total
            if mod.hardpoint == FittingHardpoint.TURRET:
                if mod.state >= FittingModuleState.ACTIVE:
                    total += dps * self.calculateTurretMultiplier(fit, mod, distance, angle, tgtSpeed, tgtSigRad)

            elif mod.hardpoint == FittingHardpoint.MISSILE:
                if mod.state >= FittingModuleState.ACTIVE and mod.maxRange is not None and (mod.maxRange - attRad) >= distance:
                    total += dps * self.calculateMissileMultiplier(mod, tgtSpeed, tgtSigRad)

        if distance <= fit.extraAttributes['droneControlRange']:
            for drone in fit.drones:
                multiplier = 1 if drone.getModifiedItemAttr('maxVelocity') > 1 else self.calculateTurretMultiplier(
                    fit, drone, distance, angle, tgtSpeed, tgtSigRad)
                dps = drone.getDps(targetResists=fit.targetResists).total
                total += dps * multiplier

        # this is janky as f**k
        for fighter in fit.fighters:
            if not fighter.active:
                continue
            fighterDpsMap = fighter.getDpsPerEffect(targetResists=fit.targetResists)
            for ability in fighter.abilities:
                if ability.dealsDamage and ability.active:
                    if ability.effectID not in fighterDpsMap:
                        continue
                    multiplier = self.calculateFighterMissileMultiplier(tgtSpeed, tgtSigRad, ability)
                    dps = fighterDpsMap[ability.effectID].total
                    total += dps * multiplier

        return total
def handler(fit, container, context, **kwargs):
    if "projected" in context:
        repAmountBase = container.getModifiedItemAttr("armorDamageAmount")
        cycleTime = container.getModifiedItemAttr("duration") / 1000.0
        repSpoolMax = container.getModifiedItemAttr("repairMultiplierBonusMax")
        repSpoolPerCycle = container.getModifiedItemAttr(
            "repairMultiplierBonusPerCycle")
        # TODO: fetch spoolup option
        defaultSpoolValue = 1
        spoolType, spoolAmount = resolveSpoolOptions(
            SpoolOptions(SpoolType.SCALE, defaultSpoolValue, False), container)
        rps = repAmountBase * (
            1 + calculateSpoolup(repSpoolMax, repSpoolPerCycle, cycleTime,
                                 spoolType, spoolAmount)[0]) / cycleTime
        rpsPreSpool = repAmountBase * (
            1 + calculateSpoolup(repSpoolMax, repSpoolPerCycle, cycleTime,
                                 SpoolType.SCALE, 0)[0]) / cycleTime
        rpsFullSpool = repAmountBase * (
            1 + calculateSpoolup(repSpoolMax, repSpoolPerCycle, cycleTime,
                                 SpoolType.SCALE, 1)[0]) / cycleTime
        fit.extraAttributes.increase("armorRepair", rps, **kwargs)
        fit.extraAttributes.increase("armorRepairPreSpool", rpsPreSpool,
                                     **kwargs)
        fit.extraAttributes.increase("armorRepairFullSpool", rpsFullSpool,
                                     **kwargs)
예제 #5
0
 def _getRepsPerKey(self, src, ancReload, time):
     # Use data from time cache if time was not specified
     if time is not None:
         return self._getTimeCacheDataPoint(src=src,
                                            ancReload=ancReload,
                                            time=time)
     # Compose map ourselves using current fit settings if time is not specified
     rpsMap = {}
     defaultSpoolValue = eos.config.settings[
         'globalDefaultSpoolupPercentage']
     for mod in src.item.activeModulesIter():
         if not mod.isRemoteRepping():
             continue
         isAncShield = 'shipModuleAncillaryRemoteShieldBooster' in mod.item.effects
         isAncArmor = 'shipModuleAncillaryRemoteArmorRepairer' in mod.item.effects
         rpsMap[mod] = mod.getRemoteReps(
             spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE,
                                       defaultSpoolValue, False),
             reloadOverride=ancReload if
             (isAncShield or isAncArmor) else None)
     for drone in src.item.activeDronesIter():
         if not drone.isRemoteRepping():
             continue
         rpsMap[drone] = drone.getRemoteReps()
     return rpsMap
예제 #6
0
파일: getter.py 프로젝트: megari/Pyfa
 def _getDamagePerKey(self, src, time):
     # Use data from time cache if time was not specified
     if time is not None:
         return self._getTimeCacheDataPoint(src=src, time=time)
     # Compose map ourselves using current fit settings if time is not specified
     volleyMap = {}
     defaultSpoolValue = eos.config.settings['globalDefaultSpoolupPercentage']
     for mod in src.item.activeModulesIter():
         if not mod.isDealingDamage():
             continue
         volleyMap[mod] = mod.getVolley(spoolOptions=SpoolOptions(SpoolType.SCALE, defaultSpoolValue, False))
     for drone in src.item.activeDronesIter():
         if not drone.isDealingDamage():
             continue
         volleyMap[drone] = drone.getVolley()
     for fighter in src.item.activeFightersIter():
         if not fighter.isDealingDamage():
             continue
         for effectID, effectVolley in fighter.getVolleyPerEffect().items():
             volleyMap[(fighter, effectID)] = effectVolley
     return volleyMap
예제 #7
0
# You should have received a copy of the GNU General Public License
# along with pyfa.  If not, see <http://www.gnu.org/licenses/>.
# ===============================================================================

# noinspection PyPackageRequirements
import wx
from gui.statsView import StatsView
from gui.utils.numberFormatter import formatAmount, roundToPrec
from eos.utils.spoolSupport import SpoolType, SpoolOptions
import eos.config


stats = [
    (
        "labelRemoteCapacitor", "Capacitor:", "{}{} GJ/s", "capacitorInfo", "Capacitor restored",
        lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, spool, False)).get("Capacitor", 0),
        lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, 0, True)).get("Capacitor", 0),
        lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, 1, True)).get("Capacitor", 0),
        3, 0, 0),
    (
        "labelRemoteShield", "Shield:", "{}{} HP/s", "shieldActive", "Shield restored",
        lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, spool, False)).get("Shield", 0),
        lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, 0, True)).get("Shield", 0),
        lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, 1, True)).get("Shield", 0),
        3, 0, 0),
    (
        "labelRemoteArmor", "Armor:", "{}{} HP/s", "armorActive", "Armor restored",
        lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, spool, False)).get("Armor", 0),
        lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, 0, True)).get("Armor", 0),
        lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SCALE, 1, True)).get("Armor", 0),
        3, 0, 0),
예제 #8
0
    def getSubMenu(self, callingWindow, context, mainItem, rootMenu, i, pitem):
        m = wx.Menu()
        if "wxMSW" in wx.PlatformInfo:
            bindmenu = rootMenu
        else:
            bindmenu = m

        isNotDefault = self.mod.spoolType is not None and self.mod.spoolAmount is not None
        cycleDefault = self.mod.getSpoolData(spoolOptions=SpoolOptions(
            SpoolType.SPOOL_SCALE,
            eos.config.settings['globalDefaultSpoolupPercentage'], True))[0]
        cycleCurrent = self.mod.getSpoolData(spoolOptions=SpoolOptions(
            SpoolType.SPOOL_SCALE,
            eos.config.settings['globalDefaultSpoolupPercentage'], False))[0]
        cycleMin = self.mod.getSpoolData(
            spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True))[0]
        cycleMax = self.mod.getSpoolData(
            spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True))[0]
        cycleTotalMin = min(cycleDefault, cycleCurrent, cycleMin)
        cycleTotalMax = max(cycleDefault, cycleCurrent, cycleMax)

        def findCycles(val1, val2):
            # Try to compose list of 21 steps max (0-20)
            maxSteps = 20
            valDiff = val2 - val1
            valScale = valDiff / maxSteps
            minStep = math.ceil(round(valScale, 9))
            maxStep = math.floor(round(valDiff / 4, 9))
            # Check steps from smallest to highest and see if we can go from min value
            # to max value using those
            for currentStep in range(minStep, maxStep + 1):
                if valDiff % currentStep == 0:
                    return set(range(val1, val2 + currentStep, currentStep))
            # Otherwise just split range in halves and go both ends using min values
            else:
                cycles = set()
                while val2 >= val1:
                    cycles.add(val1)
                    cycles.add(val2)
                    val1 += minStep
                    val2 -= minStep
                return cycles

        self.cycleMap = {}
        cyclesToShow = findCycles(cycleMin, cycleMax)
        for cycle in range(cycleTotalMin, cycleTotalMax + 1):
            menuId = ContextMenuSingle.nextID()

            # Show default only for current value and when not overriden
            if not isNotDefault and cycle == cycleDefault:
                text = "{} (default)".format(cycle)
            # Always show current selection and stuff which we decided to show via the cycles function
            elif cycle == cycleCurrent or cycle in cyclesToShow:
                text = "{}".format(cycle)
            # Ignore the rest to not have very long menu
            else:
                continue

            item = wx.MenuItem(m, menuId, text, kind=wx.ITEM_CHECK)
            bindmenu.Bind(wx.EVT_MENU, self.handleSpoolChange, item)
            m.Append(item)
            item.Check(isNotDefault and cycle == cycleCurrent)
            self.cycleMap[menuId] = cycle

        self.resetId = ContextMenuSingle.nextID()
        item = wx.MenuItem(m, self.resetId, "Reset")
        bindmenu.Bind(wx.EVT_MENU, self.handleSpoolChange, item)
        m.Append(item)

        return m
예제 #9
0
    def __generateCache(self, fit, maxTime):
        cache = self._cache[fit.ID] = {}

        def addDmg(addedTime, addedDmg):
            if addedDmg == 0:
                return
            if addedTime not in cache:
                prevTime = max((t for t in cache if t < addedTime),
                               default=None)
                if prevTime is None:
                    cache[addedTime] = 0
                else:
                    cache[addedTime] = cache[prevTime]
            for time in (t for t in cache if t >= addedTime):
                cache[time] += addedDmg

        # We'll handle calculations in milliseconds
        maxTime = maxTime * 1000
        for mod in fit.modules:
            if not mod.isDealingDamage():
                continue
            cycleParams = mod.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            nonstopCycles = 0
            for cycleTime, inactiveTime in cycleParams.iterCycles():
                volleyParams = mod.getVolleyParameters(
                    spoolOptions=SpoolOptions(SpoolType.CYCLES, nonstopCycles,
                                              True))
                for volleyTime, volley in volleyParams.items():
                    addDmg(currentTime + volleyTime, volley.total)
                if inactiveTime == 0:
                    nonstopCycles += 1
                else:
                    nonstopCycles = 0
                if currentTime > maxTime:
                    break
                currentTime += cycleTime + inactiveTime
        for drone in fit.drones:
            if not drone.isDealingDamage():
                continue
            cycleParams = drone.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            volleyParams = drone.getVolleyParameters()
            for cycleTime, inactiveTime in cycleParams.iterCycles():
                for volleyTime, volley in volleyParams.items():
                    addDmg(currentTime + volleyTime, volley.total)
                if currentTime > maxTime:
                    break
                currentTime += cycleTime + inactiveTime
        for fighter in fit.fighters:
            if not fighter.isDealingDamage():
                continue
            cycleParams = fighter.getCycleParametersPerEffectOptimizedDps(
                reloadOverride=True)
            if cycleParams is None:
                continue
            volleyParams = fighter.getVolleyParametersPerEffect()
            for effectID, abilityCycleParams in cycleParams.items():
                if effectID not in volleyParams:
                    continue
                currentTime = 0
                abilityVolleyParams = volleyParams[effectID]
                for cycleTime, inactiveTime in abilityCycleParams.iterCycles():
                    for volleyTime, volley in abilityVolleyParams.items():
                        addDmg(currentTime + volleyTime, volley.total)
                    if currentTime > maxTime:
                        break
                    currentTime += cycleTime + inactiveTime
예제 #10
0
    def exportEfs(fit, typeNotFitFlag):
        sFit = Fit.getInstance()
        includeShipTypeData = typeNotFitFlag > 0
        if includeShipTypeData:
            fitName = fit.name
        else:
            fitName = fit.ship.name + ": " + fit.name
        pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name)
        fitModAttr = fit.ship.getModifiedItemAttr
        propData = EfsPort.getPropData(fit, sFit)
        mwdPropSpeed = fit.maxSpeed
        if includeShipTypeData:
            mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, sFit)
        projections = EfsPort.getOutgoingProjectionData(fit)
        modInfo = EfsPort.getModuleInfo(fit)
        moduleNames = modInfo["moduleNames"]
        modTypeIDs = modInfo["modTypeIDs"]
        weaponSystems = EfsPort.getWeaponSystemData(fit)

        turretSlots = fitModAttr("turretSlotsLeft") if fitModAttr(
            "turretSlotsLeft") is not None else 0
        launcherSlots = fitModAttr("launcherSlotsLeft") if fitModAttr(
            "launcherSlotsLeft") is not None else 0
        droneBandwidth = fitModAttr("droneBandwidth") if fitModAttr(
            "droneBandwidth") is not None else 0
        weaponBonusMultipliers = EfsPort.getWeaponBonusMultipliers(fit)
        effectiveTurretSlots = round(
            turretSlots * weaponBonusMultipliers["turret"], 2)
        effectiveLauncherSlots = round(
            launcherSlots * weaponBonusMultipliers["launcher"], 2)
        effectiveDroneBandwidth = round(
            droneBandwidth * weaponBonusMultipliers["droneBandwidth"], 2)
        # Assume a T2 siege module for dreads
        if fit.ship.item.group.name == "Dreadnought":
            effectiveTurretSlots *= 9.4
            effectiveLauncherSlots *= 15
        hullResonance = {
            "exp": fitModAttr("explosiveDamageResonance"),
            "kin": fitModAttr("kineticDamageResonance"),
            "therm": fitModAttr("thermalDamageResonance"),
            "em": fitModAttr("emDamageResonance")
        }
        armorResonance = {
            "exp": fitModAttr("armorExplosiveDamageResonance"),
            "kin": fitModAttr("armorKineticDamageResonance"),
            "therm": fitModAttr("armorThermalDamageResonance"),
            "em": fitModAttr("armorEmDamageResonance")
        }
        shieldResonance = {
            "exp": fitModAttr("shieldExplosiveDamageResonance"),
            "kin": fitModAttr("shieldKineticDamageResonance"),
            "therm": fitModAttr("shieldThermalDamageResonance"),
            "em": fitModAttr("shieldEmDamageResonance")
        }
        resonance = {
            "hull": hullResonance,
            "armor": armorResonance,
            "shield": shieldResonance
        }
        shipSize = EfsPort.getShipSize(fit.ship.item.groupID)
        # TODO: fetch spoolup option
        defaultSpoolValue = 1
        spoolOptions = SpoolOptions(SpoolType.SCALE, defaultSpoolValue, False)
        try:
            dataDict = {
                "name": fitName,
                "ehp": fit.ehp,
                "droneDPS": fit.getDroneDps().total,
                "droneVolley": fit.getDroneVolley().total,
                "hp": fit.hp,
                "maxTargets": fit.maxTargets,
                "maxSpeed": fit.maxSpeed,
                "weaponVolley":
                fit.getWeaponVolley(spoolOptions=spoolOptions).total,
                "totalVolley":
                fit.getTotalVolley(spoolOptions=spoolOptions).total,
                "maxTargetRange": fit.maxTargetRange,
                "scanStrength": fit.scanStrength,
                "weaponDPS": fit.getWeaponDps(spoolOptions=spoolOptions).total,
                "alignTime": fit.alignTime,
                "signatureRadius": fitModAttr("signatureRadius"),
                "weapons": weaponSystems,
                "scanRes": fitModAttr("scanResolution"),
                "capUsed": fit.capUsed,
                "capRecharge": fit.capRecharge,
                "rigSlots": fitModAttr("rigSlots"),
                "lowSlots": fitModAttr("lowSlots"),
                "midSlots": fitModAttr("medSlots"),
                "highSlots": fitModAttr("hiSlots"),
                "turretSlots": fitModAttr("turretSlotsLeft"),
                "launcherSlots": fitModAttr("launcherSlotsLeft"),
                "powerOutput": fitModAttr("powerOutput"),
                "cpuOutput": fitModAttr("cpuOutput"),
                "rigSize": fitModAttr("rigSize"),
                "effectiveTurrets": effectiveTurretSlots,
                "effectiveLaunchers": effectiveLauncherSlots,
                "effectiveDroneBandwidth": effectiveDroneBandwidth,
                "resonance": resonance,
                "typeID": fit.shipID,
                "groupID": fit.ship.item.groupID,
                "shipSize": shipSize,
                "droneControlRange": fitModAttr("droneControlRange"),
                "mass": fitModAttr("mass"),
                "unpropedSpeed": propData["unpropedSpeed"],
                "unpropedSig": propData["unpropedSig"],
                "usingMWD": propData["usingMWD"],
                "mwdPropSpeed": mwdPropSpeed,
                "projections": projections,
                "modTypeIDs": modTypeIDs,
                "moduleNames": moduleNames,
                "pyfaVersion": pyfaVersion,
                "efsExportVersion": EfsPort.version
            }
        except TypeError:
            pyfalog.error("Error parsing fit:" + str(fit))
            pyfalog.error(TypeError)
            dataDict = {"name": fitName + "Fit could not be correctly parsed"}
        export = json.dumps(dataDict, skipkeys=True)
        return export
예제 #11
0
파일: misc.py 프로젝트: zzwpower/Pyfa
    def __getData(self, stuff):
        item = stuff.item
        if item is None:
            return "", None
        itemGroup = item.group.name
        itemCategory = item.category.name

        if itemGroup == "Ship Modifiers":
            return "", None
        elif itemGroup == "Booster":
            stuff.getModifiedItemAttr("boosterDuration")
            text = "{0} min".format(
                formatAmount(
                    stuff.getModifiedItemAttr("boosterDuration") / 1000 / 60,
                    3, 0, 3))
            return text, "Booster Duration"
        elif itemGroup in ("Super Weapon", "Structure Doomsday Weapon"):
            volleyParams = stuff.getVolleyParameters(ignoreState=True)
            dmg = sum(dt.total for dt in volleyParams.values())
            duration = (max(volleyParams) - min(volleyParams)) / 1000
            if dmg <= 0:
                text = ""
                tooltip = ""
            elif duration > 0:
                text = "{} over {}s".format(formatAmount(dmg, 3, 0, 6),
                                            formatAmount((duration), 0, 0, 0))
                tooltip = "Raw damage done over time"
            else:
                text = "{} dmg".format(formatAmount(dmg, 3, 0, 6))
                tooltip = "Raw damage done"
            return text, tooltip

            pass
        elif itemGroup in ("Energy Weapon", "Hybrid Weapon",
                           "Projectile Weapon", "Combat Drone",
                           "Fighter Drone"):
            trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed")
            optimalSig = stuff.getModifiedItemAttr("optimalSigRadius")
            if not trackingSpeed or not optimalSig:
                return "", None
            normalizedTracking = trackingSpeed * 40000 / optimalSig
            text = "{0}".format(formatAmount(normalizedTracking, 3, 0, 3))
            tooltip = "Tracking speed"
            return text, tooltip
        elif itemGroup == "Precursor Weapon":
            info = []
            trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed")
            if trackingSpeed:
                text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3))
                tooltip = "tracking speed"
                info.append((text, tooltip))

            defaultSpoolValue = eos.config.settings[
                'globalDefaultSpoolupPercentage']
            spoolTime = stuff.getSpoolData(spoolOptions=SpoolOptions(
                SpoolType.SPOOL_SCALE, defaultSpoolValue, False))[1]
            if spoolTime:
                text = "{0}s".format(formatAmount(spoolTime, 3, 0, 3))
                tooltip = "spool up time"
                info.append((text, tooltip))
            if not info:
                return "", None
            text = ' | '.join(i[0] for i in info)
            tooltip = ' and '.join(i[1] for i in info).capitalize()
            return text, tooltip
        elif itemGroup == "Vorton Projector":
            cloudSize = stuff.getModifiedItemAttr("aoeCloudSize")
            aoeVelocity = stuff.getModifiedItemAttr("aoeVelocity")
            if not cloudSize or not aoeVelocity:
                return "", None
            text = "{0}{1} | {2}{3}".format(formatAmount(cloudSize, 3, 0,
                                                         3), "m",
                                            formatAmount(aoeVelocity, 3, 0, 3),
                                            "m/s")
            tooltip = "Explosion radius and explosion velocity"
            return text, tooltip
        elif itemCategory == "Subsystem":
            slots = ("hi", "med", "low")
            info = []
            for slot in slots:
                n = int(stuff.getModifiedItemAttr("%sSlotModifier" % slot))
                if n > 0:
                    info.append("{0}{1}".format(n, slot[0].upper()))
            return "+ " + ", ".join(info), "Slot Modifiers"
        elif (itemGroup
              in ("Energy Neutralizer", "Structure Energy Neutralizer") or
              (itemGroup in ("Structure Burst Projector", "Burst Projectors")
               and "doomsdayAOENeut" in item.effects)):
            neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount")
            cycleParams = stuff.getCycleParameters()
            if cycleParams is None:
                return "", None
            cycleTime = cycleParams.averageTime
            if not neutAmount or not cycleTime:
                return "", None
            capPerSec = float(-neutAmount) * 1000 / cycleTime
            text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
            tooltip = "Energy neutralization per second"
            return text, tooltip
        elif itemGroup == "Energy Nosferatu":
            neutAmount = stuff.getModifiedItemAttr("powerTransferAmount")
            cycleParams = stuff.getCycleParameters()
            if cycleParams is None:
                return "", None
            cycleTime = cycleParams.averageTime
            if not neutAmount or not cycleTime:
                return "", None
            capPerSec = float(-neutAmount) * 1000 / cycleTime
            text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
            tooltip = "Energy neutralization per second"
            return text, tooltip
        elif itemGroup == "Salvager":
            chance = stuff.getModifiedItemAttr("accessDifficultyBonus")
            if not chance:
                return "", None
            text = "{0}%".format(formatAmount(chance, 3, 0, 3))
            tooltip = "Item retrieval chance"
            return text, tooltip
        elif itemGroup == "Data Miners":
            strength = stuff.getModifiedItemAttr("virusStrength")
            coherence = stuff.getModifiedItemAttr("virusCoherence")
            if not strength or not coherence:
                return "", None
            text = "{0} | {1}".format(formatAmount(strength, 3, 0, 3),
                                      formatAmount(coherence, 3, 0, 3))
            tooltip = "Virus strength and coherence"
            return text, tooltip
        elif itemGroup in ("Warp Scrambler", "Warp Core Stabilizer",
                           "Structure Warp Scrambler"):
            scramStr = stuff.getModifiedItemAttr("warpScrambleStrength")
            if not scramStr:
                return "", None
            text = "{0}".format(
                formatAmount(-scramStr, 3, 0, 3, forceSign=True))
            tooltip = "Warp core strength modification"
            return text, tooltip
        elif (itemGroup in ("Stasis Web", "Stasis Webifying Drone",
                            "Structure Stasis Webifier") or
              (itemGroup in ("Structure Burst Projector", "Burst Projectors")
               and "doomsdayAOEWeb" in item.effects)):
            speedFactor = stuff.getModifiedItemAttr("speedFactor")
            if not speedFactor:
                return "", None
            text = "{0}%".format(formatAmount(speedFactor, 3, 0, 3))
            tooltip = "Speed reduction"
            return text, tooltip
        elif (itemGroup == "Target Painter"
              or (itemGroup == "Structure Disruption Battery"
                  and "structureModuleEffectTargetPainter" in item.effects) or
              (itemGroup in ("Structure Burst Projector", "Burst Projectors")
               and "doomsdayAOEPaint" in item.effects)):
            sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus")
            if not sigRadBonus:
                return "", None
            text = "{0}%".format(
                formatAmount(sigRadBonus, 3, 0, 3, forceSign=True))
            tooltip = "Signature radius increase"
            return text, tooltip
        elif (itemGroup == "Sensor Dampener" or
              (itemGroup == "Structure Disruption Battery"
               and "structureModuleEffectRemoteSensorDampener" in item.effects)
              or
              (itemGroup in ("Structure Burst Projector", "Burst Projectors")
               and "doomsdayAOEDamp" in item.effects)):
            lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus")
            scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus")
            if lockRangeBonus is None or scanResBonus is None:
                return "", None
            display = 0
            for bonus in (lockRangeBonus, scanResBonus):
                if abs(bonus) > abs(display):
                    display = bonus
            if not display:
                return "", None
            text = "{0}%".format(formatAmount(display, 3, 0, 3,
                                              forceSign=True))
            ttEntries = []
            if display == lockRangeBonus:
                ttEntries.append("lock range")
            if display == scanResBonus:
                ttEntries.append("scan resolution")
            tooltip = "{0} dampening".format(
                formatList(ttEntries)).capitalize()
            return text, tooltip
        elif (itemGroup in ("Weapon Disruptor", "Structure Disruption Battery")
              or
              (itemGroup in ("Structure Burst Projector", "Burst Projectors")
               and "doomsdayAOETrack" in item.effects)):
            # Weapon disruption now covers both tracking and guidance (missile) disruptors
            # First get the attributes for tracking disruptors
            optimalRangeBonus = stuff.getModifiedItemAttr("maxRangeBonus")
            falloffRangeBonus = stuff.getModifiedItemAttr("falloffBonus")
            trackingSpeedBonus = stuff.getModifiedItemAttr(
                "trackingSpeedBonus")

            trackingDisruptorAttributes = {
                "optimal range": optimalRangeBonus,
                "falloff range": falloffRangeBonus,
                "tracking speed": trackingSpeedBonus
            }

            isTrackingDisruptor = any([
                x is not None and x != 0
                for x in list(trackingDisruptorAttributes.values())
            ])

            # Then get the attributes for guidance disruptors
            explosionVelocityBonus = stuff.getModifiedItemAttr(
                "aoeVelocityBonus")
            explosionRadiusBonus = stuff.getModifiedItemAttr(
                "aoeCloudSizeBonus")

            flightTimeBonus = stuff.getModifiedItemAttr("explosionDelayBonus")
            missileVelocityBonus = stuff.getModifiedItemAttr(
                "missileVelocityBonus")

            guidanceDisruptorAttributes = {
                "explosion velocity": explosionVelocityBonus,
                "explosion radius": explosionRadiusBonus,
                "flight time": flightTimeBonus,
                "missile velocity": missileVelocityBonus
            }

            isGuidanceDisruptor = any([
                x is not None and x != 0
                for x in list(guidanceDisruptorAttributes.values())
            ])

            if not isTrackingDisruptor and not isGuidanceDisruptor:
                return "", None

            texts = []
            ttSegments = []

            for status, attributes in ((isTrackingDisruptor,
                                        trackingDisruptorAttributes),
                                       (isGuidanceDisruptor,
                                        guidanceDisruptorAttributes)):
                if not status:
                    continue
                display = max(list(attributes.values()), key=lambda x: abs(x))
                texts.append("{0}%".format(
                    formatAmount(display, 3, 0, 3, forceSign=True)))
                ttEntries = []
                for attributeName, attributeValue in list(attributes.items()):
                    if abs(attributeValue) == abs(display):
                        ttEntries.append(attributeName)
                ttSegments.append("{0} disruption".format(
                    formatList(ttEntries)).capitalize())
            return ' | '.join(texts), '\n'.join(ttSegments)
        elif itemGroup in ("Gyrostabilizer", "Magnetic Field Stabilizer",
                           "Heat Sink", "Ballistic Control system",
                           "Structure Weapon Upgrade",
                           "Entropic Radiation Sink",
                           "Vorton Projector Upgrade"):
            attrMap = {
                "Gyrostabilizer":
                ("damageMultiplier", "speedMultiplier", "Projectile weapon"),
                "Magnetic Field Stabilizer":
                ("damageMultiplier", "speedMultiplier", "Hybrid weapon"),
                "Heat Sink": ("damageMultiplier", "speedMultiplier",
                              "Energy weapon"),
                "Ballistic Control system": ("missileDamageMultiplierBonus",
                                             "speedMultiplier", "Missile"),
                "Structure Weapon Upgrade": ("missileDamageMultiplierBonus",
                                             "speedMultiplier", "Missile"),
                "Entropic Radiation Sink":
                ("damageMultiplier", "speedMultiplier", "Precursor weapon"),
                "Vorton Projector Upgrade":
                ("damageMultiplier", "speedMultiplier", "Vorton projector")
            }
            dmgAttr, rofAttr, weaponName = attrMap[itemGroup]
            dmg = stuff.getModifiedItemAttr(dmgAttr)
            rof = stuff.getModifiedItemAttr(rofAttr)
            if not dmg or not rof:
                return "", None
            texts = []
            tooltips = []
            cumulative = (dmg / rof - 1) * 100
            texts.append("{}%".format(
                formatAmount(cumulative, 3, 0, 3, forceSign=True)))
            tooltips.append("{} DPS boost".format(weaponName))
            droneDmg = stuff.getModifiedItemAttr("droneDamageBonus")
            if droneDmg:
                texts.append("{}%".format(
                    formatAmount(droneDmg, 3, 0, 3, forceSign=True)))
                tooltips.append("drone DPS boost".format(weaponName))
            return ' | '.join(texts), ' and '.join(tooltips)
        elif itemGroup == "Drone Damage Modules":
            dmg = stuff.getModifiedItemAttr("droneDamageBonus")
            if not dmg:
                return
            text = "{}%".format(formatAmount(dmg, 3, 0, 3, forceSign=True))
            tooltip = "Drone DPS boost"
            return text, tooltip
        elif (itemGroup in ("ECM", "Burst Jammer", "Structure ECM Battery") or
              (itemGroup in ("Structure Burst Projector", "Burst Projectors")
               and "doomsdayAOEECM" in item.effects)):
            grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus")
            ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus")
            radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus")
            magnet = stuff.getModifiedItemAttr(
                "scanMagnetometricStrengthBonus")
            displayMax = max(grav, ladar, radar, magnet)
            displayMin = min(grav, ladar, radar, magnet)
            if grav is None or ladar is None or radar is None or magnet is None or displayMax is None:
                return "", None

            if displayMax == displayMin or displayMin is None:
                text = "{0}".format(formatAmount(displayMax, 3, 0, 3), )
            else:
                text = "{0} | {1}".format(
                    formatAmount(displayMax, 3, 0, 3),
                    formatAmount(displayMin, 3, 0, 3),
                )
            tooltip = "ECM Jammer Strength:\n{0} Gravimetric | {1} Ladar | {2} Magnetometric | {3} Radar".format(
                formatAmount(grav, 3, 0, 3),
                formatAmount(ladar, 3, 0, 3),
                formatAmount(magnet, 3, 0, 3),
                formatAmount(radar, 3, 0, 3),
            )
            return text, tooltip
        elif itemGroup in ("Remote Sensor Booster", "Sensor Booster",
                           "Signal Amplifier", "Structure Signal Amplifier"):
            textLines = []
            tooltipLines = []
            scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus")
            if scanResBonus:
                textLines.append("{}%".format(
                    formatAmount(scanResBonus, 3, 0, 3)))
                tooltipLines.append("{}% scan resolution".format(
                    formatAmount(scanResBonus, 3, 0, 3)))
            lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus")
            if lockRangeBonus:
                textLines.append("{}%".format(
                    formatAmount(lockRangeBonus, 3, 0, 3)))
                tooltipLines.append("{}% lock range".format(
                    formatAmount(lockRangeBonus, 3, 0, 3)))
            gravBonus = stuff.getModifiedItemAttr(
                "scanGravimetricStrengthPercent")
            if gravBonus:
                textLines.append("{}%".format(formatAmount(gravBonus, 3, 0,
                                                           3)))
                tooltipLines.append("{}% sensor strength".format(
                    formatAmount(gravBonus, 3, 0, 3)))
            if not textLines:
                return "", None
            text = " | ".join(textLines)
            tooltip = "Applied bonuses:\n{}".format(" | ".join(tooltipLines))
            return text, tooltip
        elif itemGroup in ("Projected ECCM", "ECCM", "Sensor Backup Array"):
            grav = stuff.getModifiedItemAttr("scanGravimetricStrengthPercent")
            ladar = stuff.getModifiedItemAttr("scanLadarStrengthPercent")
            radar = stuff.getModifiedItemAttr("scanRadarStrengthPercent")
            magnet = stuff.getModifiedItemAttr(
                "scanMagnetometricStrengthPercent")
            if grav is None or ladar is None or radar is None or magnet is None:
                return "", None
            display = max(grav, ladar, radar, magnet)
            if not display:
                return "", None
            text = "{0}%".format(formatAmount(display, 3, 0, 3,
                                              forceSign=True))
            ttEntries = []
            if display == grav:
                ttEntries.append("gravimetric")
            if display == ladar:
                ttEntries.append("ladar")
            if display == magnet:
                ttEntries.append("magnetometric")
            if display == radar:
                ttEntries.append("radar")
            plu = "" if len(ttEntries) == 1 else "s"
            tooltip = "{0} strength{1} bonus".format(formatList(ttEntries),
                                                     plu).capitalize()
            return text, tooltip
        elif itemGroup == "Cloaking Device":
            recalibration = stuff.getModifiedItemAttr("cloakingTargetingDelay")
            if recalibration is None:
                return "", None
            text = "{0}s".format(
                formatAmount(float(recalibration) / 1000, 3, 0, 3))
            tooltip = "Sensor recalibration time"
            return text, tooltip
        elif itemGroup == "Remote Armor Repairer":
            rps = stuff.getRemoteReps(ignoreState=True).armor
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Armor repaired per second"
            return text, tooltip
        elif itemGroup == "Mutadaptive Remote Armor Repairer":
            defaultSpoolValue = eos.config.settings[
                'globalDefaultSpoolupPercentage']
            spoolOptDefault = SpoolOptions(SpoolType.SPOOL_SCALE,
                                           defaultSpoolValue, False)
            spoolOptPre = SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)
            spoolOptFull = SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)
            rps = stuff.getRemoteReps(spoolOptions=spoolOptDefault,
                                      ignoreState=True).armor
            rpsPre = stuff.getRemoteReps(spoolOptions=spoolOptPre,
                                         ignoreState=True).armor
            rpsFull = stuff.getRemoteReps(spoolOptions=spoolOptFull,
                                          ignoreState=True).armor
            if not rps:
                return "", None
            text = []
            tooltip = []
            text.append("{}/s".format(
                formatAmount(rps, 3, 0, 3, forceSign=True)))
            tooltip.append("Armor repaired per second")
            spoolTime = stuff.getSpoolData(spoolOptDefault)[1]
            if spoolTime:
                text.append("{}s".format(formatAmount(spoolTime, 3, 0, 3)))
                tooltip.append("spool up time")
            text = " | ".join(text)
            tooltip = " and ".join(tooltip)
            spoolTimePre = stuff.getSpoolData(spoolOptPre)[1]
            spoolTimeFull = stuff.getSpoolData(spoolOptFull)[1]
            if spoolTimePre != spoolTimeFull:
                tooltip = "{}\nSpool up: {}-{} over {}s".format(
                    tooltip, formatAmount(rpsPre, 3, 0, 3),
                    formatAmount(rpsFull, 3, 0, 3),
                    formatAmount(spoolTimeFull - spoolTimePre, 3, 0, 3))
            return text, tooltip
        elif itemGroup == "Remote Shield Booster":
            rps = stuff.getRemoteReps(ignoreState=True).shield
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Shield transferred per second"
            return text, tooltip
        elif itemGroup == "Remote Capacitor Transmitter":
            rps = stuff.getRemoteReps(ignoreState=True).capacitor
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Energy transferred per second"
            return text, tooltip
        elif itemGroup == "Remote Hull Repairer":
            rps = stuff.getRemoteReps(ignoreState=True).hull
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Structure repaired per second"
            return text, tooltip
        elif itemGroup == "Gang Coordinator":
            command = stuff.getModifiedItemAttr(
                "commandBonus") or stuff.getModifiedItemAttr(
                    "commandBonusHidden")
            if not command:
                return "", None
            text = "{0}%".format(formatAmount(command, 3, 0, 3,
                                              forceSign=True))
            tooltip = "Gang bonus strength"
            return text, tooltip
        elif itemGroup == "Electronic Warfare Drone":
            sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus")
            lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus")
            scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus")
            falloffRangeBonus = stuff.getModifiedItemAttr("falloffBonus")
            optimalRangeBonus = stuff.getModifiedItemAttr("maxRangeBonus")
            trackingSpeedBonus = stuff.getModifiedItemAttr(
                "trackingSpeedBonus")
            grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus")
            ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus")
            radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus")
            magnet = stuff.getModifiedItemAttr(
                "scanMagnetometricStrengthBonus")
            if sigRadBonus:
                text = "{0}%".format(
                    formatAmount(sigRadBonus, 3, 0, 3, forceSign=True))
                tooltip = "Signature radius increase"
                return text, tooltip
            if lockRangeBonus or scanResBonus:
                display = 0
                for bonus in (lockRangeBonus, scanResBonus):
                    if abs(bonus) > abs(display):
                        display = bonus
                if not display:
                    return "", None
                text = "{0}%".format(
                    formatAmount(display, 3, 0, 3, forceSign=True))
                ttEntries = []
                if display == lockRangeBonus:
                    ttEntries.append("lock range")
                if display == scanResBonus:
                    ttEntries.append("scan resolution")
                tooltip = "{0} dampening".format(
                    formatList(ttEntries)).capitalize()
                return text, tooltip
            if falloffRangeBonus or optimalRangeBonus or trackingSpeedBonus:
                display = 0
                for bonus in (falloffRangeBonus, optimalRangeBonus,
                              trackingSpeedBonus):
                    if abs(bonus) > abs(display):
                        display = bonus
                if not display:
                    return "", None
                text = "{0}%".format(formatAmount(display, 3, 0, 3),
                                     forceSign=True)
                ttEntries = []
                if display == optimalRangeBonus:
                    ttEntries.append("optimal range")
                if display == falloffRangeBonus:
                    ttEntries.append("falloff range")
                if display == trackingSpeedBonus:
                    ttEntries.append("tracking speed")
                tooltip = "{0} disruption".format(
                    formatList(ttEntries)).capitalize()
                return text, tooltip
            if grav is not None and ladar is not None and radar is not None and magnet is not None:
                display = max(grav, ladar, radar, magnet)
                if not display:
                    return "", None
                text = "{0}".format(formatAmount(display, 3, 0, 3))
                ttEntries = []
                if display == grav:
                    ttEntries.append("gravimetric")
                if display == ladar:
                    ttEntries.append("ladar")
                if display == magnet:
                    ttEntries.append("magnetometric")
                if display == radar:
                    ttEntries.append("radar")
                plu = "" if len(ttEntries) == 1 else "s"
                tooltip = "{0} strength{1}".format(formatList(ttEntries),
                                                   plu).capitalize()
                return text, tooltip
            else:
                return "", None
        elif itemGroup == "Fighter Bomber":
            optimalSig = stuff.getModifiedItemAttr("optimalSigRadius")
            if not optimalSig:
                return "", None
            text = "{0}m".format(formatAmount(optimalSig, 3, 0, 3))
            tooltip = "Optimal signature radius"
            return text, tooltip
        elif itemGroup in ("Frequency Mining Laser", "Strip Miner",
                           "Mining Laser", "Gas Cloud Harvester",
                           "Mining Drone"):
            miningAmount = stuff.getModifiedItemAttr(
                "specialtyMiningAmount") or stuff.getModifiedItemAttr(
                    "miningAmount")
            cycleTime = getattr(stuff, 'cycleTime',
                                stuff.getModifiedItemAttr("duration"))
            if not miningAmount or not cycleTime:
                return "", None
            minePerSec = (float(miningAmount) * 1000 / cycleTime)
            text = "{0} m3/s".format(formatAmount(minePerSec, 3, 0, 3))
            tooltip = "Mining Yield per second ({0} per hour)".format(
                formatAmount(minePerSec * 3600, 3, 0, 3))
            return text, tooltip
        elif itemGroup == "Logistic Drone":
            rpsData = stuff.getRemoteReps(ignoreState=True)
            rrType = None
            rps = None
            if rpsData.shield:
                rps = rpsData.shield
                rrType = 'Shield'
            elif rpsData.armor:
                rps = rpsData.armor
                rrType = 'Armor'
            elif rpsData.hull:
                rps = rpsData.hull
                rrType = 'Hull'
            if not rrType or not rps:
                return "", None
            text = "{}/s".format(formatAmount(rps, 3, 0, 3))
            tooltip = "{} HP repaired per second\n{} HP/s per drone".format(
                rrType, formatAmount(rps / stuff.amount, 3, 0, 3))
            return text, tooltip
        elif itemGroup == "Energy Neutralizer Drone":
            neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount")
            cycleTime = stuff.getModifiedItemAttr("energyNeutralizerDuration")
            if not neutAmount or not cycleTime:
                return "", None
            capPerSec = float(-neutAmount) * 1000 / cycleTime
            text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
            tooltip = "Energy neutralization per second"
            return text, tooltip
        elif itemGroup in ("Micro Jump Drive", "Micro Jump Field Generators"):
            cycleTime = stuff.getModifiedItemAttr("duration") / 1000
            text = "{0}s".format(formatAmount(cycleTime, 3, 0, 3))
            tooltip = "Spoolup time"
            return text, tooltip
        elif itemGroup in ("Siege Module", "Cynosural Field Generator"):
            amt = stuff.getModifiedItemAttr("consumptionQuantity")
            if amt:
                typeID = stuff.getModifiedItemAttr("consumptionType")
                item = Market.getInstance().getItem(typeID)
                text = "{0} units".format(formatAmount(amt, 3, 0, 3))
                return text, item.name
            else:
                return "", None
        elif itemGroup in (
                "Ancillary Armor Repairer",
                "Ancillary Shield Booster",
                "Capacitor Booster",
                "Ancillary Remote Armor Repairer",
                "Ancillary Remote Shield Booster",
        ):
            if "Armor" in itemGroup or "Shield" in itemGroup:
                boosted_attribute = "HP"
                reload_time = stuff.getModifiedItemAttr("reloadTime", 0) / 1000
            elif "Capacitor" in itemGroup:
                boosted_attribute = "Cap"
                reload_time = 10
            else:
                boosted_attribute = ""
                reload_time = 0

            cycles = max(stuff.numShots, 0)
            cycleTime = max(stuff.rawCycleTime, 0)

            # Get HP or boosted amount
            stuff_hp = max(stuff.hpBeforeReload, 0)
            armor_hp = stuff.getModifiedItemAttr("armorDamageAmount", 0)
            capacitor_hp = stuff.getModifiedChargeAttr("capacitorBonus", 0)
            shield_hp = stuff.getModifiedItemAttr("shieldBonus", 0)
            hp = max(stuff_hp, armor_hp * cycles, capacitor_hp * cycles,
                     shield_hp * cycles, 0)

            nonChargedMap = {
                "Ancillary Remote Armor Repairer":
                ("armor", "Armor repaired per second"),
                "Ancillary Remote Shield Booster":
                ("shield", "Shield transferred per second")
            }
            if not cycles and itemGroup in nonChargedMap:
                rps = stuff.getRemoteReps(ignoreState=True)
                rps = getattr(rps, nonChargedMap[itemGroup][0])
                if not rps:
                    return "", None
                text = "{0}/s".format(
                    formatAmount(rps, 3, 0, 3, forceSign=True))
                tooltip = nonChargedMap[itemGroup][1]
                return text, tooltip

            if not hp or not cycleTime or not cycles:
                return "", None

            fit = Fit.getInstance().getFit(self.fittingView.getActiveFit())
            ehpTotal = fit.ehp
            hpTotal = fit.hp
            try:
                useEhp = self.mainFrame.statsPane.nameViewMap[
                    "resistancesViewFull"].showEffective
            except KeyError:
                useEhp = False
            tooltip = "{0} restored over duration using charges (plus reload)".format(
                boosted_attribute)

            if useEhp and boosted_attribute == "HP" and "Remote" not in itemGroup:
                if "Ancillary Armor Repairer" in itemGroup:
                    hpRatio = ehpTotal["armor"] / hpTotal["armor"]
                else:
                    hpRatio = ehpTotal["shield"] / hpTotal["shield"]
                tooltip = "E{0}".format(tooltip)
            else:
                hpRatio = 1

            if "Ancillary" in itemGroup and "Armor" in itemGroup:
                hpRatio *= stuff.getModifiedItemAttr(
                    "chargedArmorDamageMultiplier", 1)

            ehp = hp * hpRatio

            duration = cycles * cycleTime / 1000
            for number_of_cycles in {5, 10, 25}:
                tooltip = "{0}\n{1} charges lasts {2} seconds ({3} cycles)".format(
                    tooltip, formatAmount(number_of_cycles * cycles, 3, 0, 3),
                    formatAmount((duration + reload_time) * number_of_cycles,
                                 3, 0, 3),
                    formatAmount(number_of_cycles, 3, 0, 3))
            text = "{0} / {1}s (+{2}s)".format(
                formatAmount(ehp, 3, 0, 9), formatAmount(duration, 3, 0, 3),
                formatAmount(reload_time, 3, 0, 3))

            return text, tooltip
        elif itemGroup == "Armor Resistance Shift Hardener":
            itemArmorResistanceShiftHardenerEM = (
                1 - stuff.getModifiedItemAttr("armorEmDamageResonance")) * 100
            itemArmorResistanceShiftHardenerTherm = (
                1 -
                stuff.getModifiedItemAttr("armorThermalDamageResonance")) * 100
            itemArmorResistanceShiftHardenerKin = (
                1 -
                stuff.getModifiedItemAttr("armorKineticDamageResonance")) * 100
            itemArmorResistanceShiftHardenerExp = (
                1 - stuff.getModifiedItemAttr("armorExplosiveDamageResonance")
            ) * 100

            text = "{0}% | {1}% | {2}% | {3}%".format(
                formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3),
            )
            tooltip = "Resistances Shifted to Damage Profile:\n{0}% EM | {1}% Therm | {2}% Kin | {3}% Exp".format(
                formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3),
            )
            return text, tooltip
        elif itemGroup in ("Cargo Scanner", "Ship Scanner", "Survey Scanner"):
            duration = stuff.getModifiedItemAttr("duration")
            if not duration:
                return "", None
            text = "{}s".format(formatAmount(duration / 1000, 3, 0, 0))
            tooltip = "Scan duration"
            return text, tooltip
        elif stuff.charge is not None:
            chargeGroup = stuff.charge.group.name
            if chargeGroup.endswith("Rocket") or chargeGroup.endswith(
                    "Missile") or chargeGroup.endswith("Torpedo"):
                cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize")
                aoeVelocity = stuff.getModifiedChargeAttr("aoeVelocity")
                if not cloudSize or not aoeVelocity:
                    return "", None
                text = "{0}{1} | {2}{3}".format(
                    formatAmount(cloudSize, 3, 0, 3), "m",
                    formatAmount(aoeVelocity, 3, 0, 3), "m/s")
                tooltip = "Explosion radius and explosion velocity"
                return text, tooltip
            elif chargeGroup in ("Bomb", "Structure Guided Bomb"):
                cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize")
                if not cloudSize:
                    return "", None
                text = "{0}{1}".format(formatAmount(cloudSize, 3, 0, 3), "m")
                tooltip = "Explosion radius"
                return text, tooltip
            elif chargeGroup in ("Scanner Probe", ):
                scanStr = stuff.getModifiedChargeAttr("baseSensorStrength")
                baseRange = stuff.getModifiedChargeAttr("baseScanRange")
                if not scanStr or not baseRange:
                    return "", None
                text = "{}".format(formatAmount(scanStr, 4, 0, 3))
                tooltip = "Scan strength at {} AU scan range".format(
                    formatAmount(baseRange, 3, 0, 0))
                return text, tooltip
            else:
                return "", None
        else:
            return "", None
예제 #12
0
    def _generateInternalForm(self, src, ancReload, maxTime):
        if self._isTimeCacheValid(src=src, ancReload=ancReload, maxTime=maxTime):
            return
        fitCache = self._data.setdefault(src.item.ID, {})[ancReload] = {'maxTime': maxTime}
        intCacheRps = fitCache['internalRps'] = {}
        intCacheRepAmount = fitCache['internalRepAmount'] = {}

        def addRps(rrKey, addedTimeStart, addedTimeFinish, addedRepAmounts):
            if not addedRepAmounts:
                return
            repAmountSum = sum(addedRepAmounts, RRTypes(0, 0, 0, 0))
            if repAmountSum.shield > 0 or repAmountSum.armor > 0 or repAmountSum.hull > 0:
                addedRps = repAmountSum / (addedTimeFinish - addedTimeStart)
                rrCacheRps = intCacheRps.setdefault(rrKey, [])
                rrCacheRps.append((addedTimeStart, addedTimeFinish, addedRps))

        def addRepAmount(rrKey, addedTime, addedRepAmount):
            if addedRepAmount.shield > 0 or addedRepAmount.armor > 0 or addedRepAmount.hull > 0:
                intCacheRepAmount.setdefault(rrKey, {})[addedTime] = addedRepAmount

        # Modules
        for mod in src.item.activeModulesIter():
            if not mod.isRemoteRepping():
                continue
            isAncShield = 'shipModuleAncillaryRemoteShieldBooster' in mod.item.effects
            isAncArmor = 'shipModuleAncillaryRemoteArmorRepairer' in mod.item.effects
            if isAncShield or isAncArmor:
                cycleParams = mod.getCycleParameters(reloadOverride=ancReload)
            else:
                cycleParams = mod.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            nonstopCycles = 0
            cyclesWithoutReload = 0
            cyclesUntilReload = mod.numShots
            for cycleTimeMs, inactiveTimeMs, isInactivityReload in cycleParams.iterCycles():
                cyclesWithoutReload += 1
                cycleRepAmounts = []
                repAmountParams = mod.getRepAmountParameters(spoolOptions=SpoolOptions(SpoolType.CYCLES, nonstopCycles, True))
                for repTimeMs, repAmount in repAmountParams.items():
                    # Loaded ancillary armor rep can keep running at less efficiency if we decide to not reload
                    if isAncArmor and mod.charge and not ancReload and cyclesWithoutReload > cyclesUntilReload:
                        repAmount = repAmount / mod.getModifiedItemAttr('chargedArmorDamageMultiplier', 1)
                    cycleRepAmounts.append(repAmount)
                    addRepAmount(mod, currentTime + repTimeMs / 1000, repAmount)
                addRps(mod, currentTime, currentTime + cycleTimeMs / 1000, cycleRepAmounts)
                if inactiveTimeMs > 0:
                    nonstopCycles = 0
                else:
                    nonstopCycles += 1
                if isInactivityReload:
                    cyclesWithoutReload = 0
                if currentTime > maxTime:
                    break
                currentTime += cycleTimeMs / 1000 + inactiveTimeMs / 1000
        # Drones
        for drone in src.item.activeDronesIter():
            if not drone.isRemoteRepping():
                continue
            cycleParams = drone.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            repAmountParams = drone.getRepAmountParameters()
            for cycleTimeMs, inactiveTimeMs, isInactivityReload in cycleParams.iterCycles():
                cycleRepAmounts = []
                for repTimeMs, repAmount in repAmountParams.items():
                    cycleRepAmounts.append(repAmount)
                    addRepAmount(drone, currentTime + repTimeMs / 1000, repAmount)
                addRps(drone, currentTime, currentTime + cycleTimeMs / 1000, cycleRepAmounts)
                if currentTime > maxTime:
                    break
                currentTime += cycleTimeMs / 1000 + inactiveTimeMs / 1000
예제 #13
0
    def _generateInternalForm(self, src, maxTime):
        if self._isTimeCacheValid(src=src, maxTime=maxTime):
            return
        fitCache = self._data[src.item.ID] = {'maxTime': maxTime}
        intCacheDpsVolley = fitCache['internalDpsVolley'] = {}
        intCacheDmg = fitCache['internalDmg'] = {}

        def addDpsVolley(ddKey, addedTimeStart, addedTimeFinish, addedVolleys):
            if not addedVolleys:
                return
            volleySum = sum(addedVolleys, DmgTypes(0, 0, 0, 0))
            if volleySum.total > 0:
                addedDps = volleySum / (addedTimeFinish - addedTimeStart)
                # We can take "just best" volley, no matter target resistances, because all
                # known items have the same damage type ratio throughout their cycle - and
                # applying resistances doesn't change final outcome
                bestVolley = max(addedVolleys, key=lambda v: v.total)
                ddCacheDps = intCacheDpsVolley.setdefault(ddKey, [])
                ddCacheDps.append(
                    (addedTimeStart, addedTimeFinish, addedDps, bestVolley))

        def addDmg(ddKey, addedTime, addedDmg):
            if addedDmg.total == 0:
                return
            intCacheDmg.setdefault(ddKey, {})[addedTime] = addedDmg

        # Modules
        for mod in src.item.activeModulesIter():
            if not mod.isDealingDamage():
                continue
            cycleParams = mod.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            nonstopCycles = 0
            for cycleTimeMs, inactiveTimeMs, isInactivityReload in cycleParams.iterCycles(
            ):
                cycleVolleys = []
                volleyParams = mod.getVolleyParameters(
                    spoolOptions=SpoolOptions(SpoolType.CYCLES, nonstopCycles,
                                              True))
                for volleyTimeMs, volley in volleyParams.items():
                    cycleVolleys.append(volley)
                    addDmg(mod, currentTime + volleyTimeMs / 1000, volley)
                addDpsVolley(mod, currentTime,
                             currentTime + cycleTimeMs / 1000, cycleVolleys)
                if inactiveTimeMs > 0:
                    nonstopCycles = 0
                else:
                    nonstopCycles += 1
                if currentTime > maxTime:
                    break
                currentTime += cycleTimeMs / 1000 + inactiveTimeMs / 1000
        # Drones
        for drone in src.item.activeDronesIter():
            if not drone.isDealingDamage():
                continue
            cycleParams = drone.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            volleyParams = drone.getVolleyParameters()
            for cycleTimeMs, inactiveTimeMs, isInactivityReload in cycleParams.iterCycles(
            ):
                cycleVolleys = []
                for volleyTimeMs, volley in volleyParams.items():
                    cycleVolleys.append(volley)
                    addDmg(drone, currentTime + volleyTimeMs / 1000, volley)
                addDpsVolley(drone, currentTime,
                             currentTime + cycleTimeMs / 1000, cycleVolleys)
                if currentTime > maxTime:
                    break
                currentTime += cycleTimeMs / 1000 + inactiveTimeMs / 1000
        # Fighters
        for fighter in src.item.activeFightersIter():
            if not fighter.isDealingDamage():
                continue
            cycleParams = fighter.getCycleParametersPerEffectOptimizedDps(
                reloadOverride=True)
            if cycleParams is None:
                continue
            volleyParams = fighter.getVolleyParametersPerEffect()
            for effectID, abilityCycleParams in cycleParams.items():
                if effectID not in volleyParams:
                    continue
                currentTime = 0
                abilityVolleyParams = volleyParams[effectID]
                for cycleTimeMs, inactiveTimeMs, isInactivityReload in abilityCycleParams.iterCycles(
                ):
                    cycleVolleys = []
                    for volleyTimeMs, volley in abilityVolleyParams.items():
                        cycleVolleys.append(volley)
                        addDmg((fighter, effectID),
                               currentTime + volleyTimeMs / 1000, volley)
                    addDpsVolley((fighter, effectID), currentTime,
                                 currentTime + cycleTimeMs / 1000,
                                 cycleVolleys)
                    if currentTime > maxTime:
                        break
                    currentTime += cycleTimeMs / 1000 + inactiveTimeMs / 1000
예제 #14
0
    def exportEfs(fit, typeNotFitFlag, callback):
        sFit = Fit.getInstance()
        includeShipTypeData = typeNotFitFlag > 0
        if includeShipTypeData:
            fitName = fit.name
        else:
            fitName = fit.ship.name + ": " + fit.name
        pyfalog.info("Creating Eve Fleet Simulator data for: " + fit.name)
        fitModAttr = fit.ship.getModifiedItemAttr
        propData = EfsPort.getPropData(fit, sFit)
        mwdPropSpeed = fit.maxSpeed
        if includeShipTypeData:
            mwdPropSpeed = EfsPort.getT2MwdSpeed(fit, sFit)
        projections = EfsPort.getOutgoingProjectionData(fit)
        modInfo = EfsPort.getModuleInfo(fit)
        moduleNames = modInfo["moduleNames"]
        modTypeIDs = modInfo["modTypeIDs"]
        weaponSystems = EfsPort.getWeaponSystemData(fit)

        turretSlots = fitModAttr("turretSlotsLeft") if fitModAttr(
            "turretSlotsLeft") is not None else 0
        launcherSlots = fitModAttr("launcherSlotsLeft") if fitModAttr(
            "launcherSlotsLeft") is not None else 0
        droneBandwidth = fitModAttr("droneBandwidth") if fitModAttr(
            "droneBandwidth") is not None else 0
        weaponBonusMultipliers = EfsPort.getWeaponBonusMultipliers(fit)
        effectiveTurretSlots = round(
            turretSlots * weaponBonusMultipliers["turret"], 2)
        effectiveLauncherSlots = round(
            launcherSlots * weaponBonusMultipliers["launcher"], 2)
        effectiveDroneBandwidth = round(
            droneBandwidth * weaponBonusMultipliers["droneBandwidth"], 2)
        # Assume a T2 siege module for dreads
        if fit.ship.item.group.name == "Dreadnought":
            effectiveTurretSlots *= 9.4
            effectiveLauncherSlots *= 15
        hullResonance = {
            "exp": fitModAttr("explosiveDamageResonance"),
            "kin": fitModAttr("kineticDamageResonance"),
            "therm": fitModAttr("thermalDamageResonance"),
            "em": fitModAttr("emDamageResonance")
        }
        armorResonance = {
            "exp": fitModAttr("armorExplosiveDamageResonance"),
            "kin": fitModAttr("armorKineticDamageResonance"),
            "therm": fitModAttr("armorThermalDamageResonance"),
            "em": fitModAttr("armorEmDamageResonance")
        }
        shieldResonance = {
            "exp": fitModAttr("shieldExplosiveDamageResonance"),
            "kin": fitModAttr("shieldKineticDamageResonance"),
            "therm": fitModAttr("shieldThermalDamageResonance"),
            "em": fitModAttr("shieldEmDamageResonance")
        }
        resonance = {
            "hull": hullResonance,
            "armor": armorResonance,
            "shield": shieldResonance
        }
        shipSize = EfsPort.getShipSize(fit.ship.item.groupID)
        # Export at maximum spool for consistency, spoolup data is exported anyway.
        defaultSpoolValue = 1
        spoolOptions = SpoolOptions(SpoolType.SPOOL_SCALE, defaultSpoolValue,
                                    True)

        cargoIDs = []
        for cargo in fit.cargo:
            cargoIDs.append(cargo.itemID)

        repairs = EfsPort.getRepairData(fit, sFit)

        def roundNumbers(data, digits):
            if isinstance(data, str):
                return
            if isinstance(data, dict):
                for key in data:
                    if isinstance(data[key], Number):
                        data[key] = round(data[key], digits)
                    else:
                        roundNumbers(data[key], digits)
            if isinstance(data, list) or isinstance(data, tuple):
                for val in data:
                    roundNumbers(val, digits)
            if isinstance(data, Number):
                rounded = round(data, digits)
                if data != rounded:
                    pyfalog.error(
                        "Error rounding numbers for EFS export, export may be inconsistent."
                        "This suggests the format has been broken somewhere.")
            return

        try:
            dataDict = {
                "name": fitName,
                "ehp": fit.ehp,
                "droneDPS": fit.getDroneDps().total,
                "droneVolley": fit.getDroneVolley().total,
                "hp": fit.hp,
                "maxTargets": fit.maxTargets,
                "maxSpeed": fit.maxSpeed,
                "weaponVolley":
                fit.getWeaponVolley(spoolOptions=spoolOptions).total,
                "totalVolley":
                fit.getTotalVolley(spoolOptions=spoolOptions).total,
                "maxTargetRange": fit.maxTargetRange,
                "scanStrength": fit.scanStrength,
                "weaponDPS": fit.getWeaponDps(spoolOptions=spoolOptions).total,
                "alignTime": fit.alignTime,
                "signatureRadius": fitModAttr("signatureRadius"),
                "weapons": weaponSystems,
                "scanRes": fitModAttr("scanResolution"),
                "capUsed": fit.capUsed,
                "capRecharge": fit.capRecharge,
                "capacitorCapacity": fitModAttr("capacitorCapacity"),
                "rechargeRate": fitModAttr("rechargeRate"),
                "rigSlots": fitModAttr("rigSlots"),
                "lowSlots": fitModAttr("lowSlots"),
                "midSlots": fitModAttr("medSlots"),
                "highSlots": fitModAttr("hiSlots"),
                "turretSlots": fitModAttr("turretSlotsLeft"),
                "launcherSlots": fitModAttr("launcherSlotsLeft"),
                "powerOutput": fitModAttr("powerOutput"),
                "cpuOutput": fitModAttr("cpuOutput"),
                "rigSize": fitModAttr("rigSize"),
                "effectiveTurrets": effectiveTurretSlots,
                "effectiveLaunchers": effectiveLauncherSlots,
                "effectiveDroneBandwidth": effectiveDroneBandwidth,
                "resonance": resonance,
                "typeID": fit.shipID,
                "groupID": fit.ship.item.groupID,
                "shipSize": shipSize,
                "droneControlRange": fitModAttr("droneControlRange"),
                "mass": fitModAttr("mass"),
                "unpropedSpeed": propData["unpropedSpeed"],
                "unpropedSig": propData["unpropedSig"],
                "usingMWD": propData["usingMWD"],
                "mwdPropSpeed": mwdPropSpeed,
                "projections": projections,
                "repairs": repairs,
                "modTypeIDs": modTypeIDs,
                "moduleNames": moduleNames,
                "cargoItemIDs": cargoIDs,
                "pyfaVersion": pyfaVersion,
                "efsExportVersion": EfsPort.version
            }
            # Recursively round any numbers in dicts to 6 decimal places.
            # This prevents meaningless rounding errors from changing the output whenever pyfa changes.
            roundNumbers(dataDict, 6)
        except TypeError as e:
            pyfalog.error("Error parsing fit:" + str(fit))
            pyfalog.error(e)
            dataDict = {"name": fitName + "Fit could not be correctly parsed"}
        export = json.dumps(dataDict, skipkeys=True)

        if callback:
            callback(export)
        else:
            return export
예제 #15
0
파일: shipstats.py 프로젝트: molbal/Pyfa
def exportAsJson(fit, callback):
    import json
    ehp = [fit.ehp[tank]
           for tank in tankTypes] if fit.ehp is not None else [0, 0, 0]
    ehp.append(sum(ehp))
    resists = {
        tankType: [
            1 - fit.ship.getModifiedItemAttr(s)
            for s in resonanceNames[tankType]
        ]
        for tankType in tankTypes
    }

    selfRep = [
        fit.effectiveTank[tankType + "Repair"] for tankType in tankTypes
    ]
    sustainRep = [
        fit.effectiveSustainableTank[tankType + "Repair"]
        for tankType in tankTypes
    ]
    remoteRepObj = fit.getRemoteReps()
    remoteRep = [remoteRepObj.shield, remoteRepObj.armor, remoteRepObj.hull]
    shieldRegen = [fit.effectiveSustainableTank["passiveShield"], 0, 0]

    cpuUsed = fit.cpuUsed
    pgUsed = fit.pgUsed
    calibrationUsed = fit.calibrationUsed
    droneBandwidthUsed = fit.droneBandwidthUsed
    droneBayUsed = fit.droneBayUsed
    activeDrones = fit.activeDrones
    warpSpeed = fit.warpSpeed
    from eos.utils.spoolSupport import SpoolOptions
    data = {
        "offense": {
            "totalDps":
            round(
                fit.getTotalDps(spoolOptions=SpoolOptions(0, 1, True)).total,
                2),
            "weaponDps":
            round(
                fit.getWeaponDps(spoolOptions=SpoolOptions(0, 1, True)).total,
                2),
            "droneDps":
            round(fit.getDroneDps().total, 2),
            "totalVolley":
            round(fit.getTotalVolley().total, 2)
        },
        "defense": {
            "ehp": {
                "total": ehp[3],
                "shield": ehp[0],
                "armor": ehp[1],
                "hull": ehp[2]
            },
            "resists": {
                "shield": {
                    "em": round(resists["shield"][0], 4),
                    "therm": round(resists["shield"][1], 4),
                    "kin": round(resists["shield"][2], 4),
                    "exp": round(resists["shield"][3], 4)
                },
                "armor": {
                    "em": round(resists["armor"][0], 4),
                    "therm": round(resists["armor"][1], 4),
                    "kin": round(resists["armor"][2], 4),
                    "exp": round(resists["armor"][3], 4)
                },
                "hull": {
                    "em": round(resists["hull"][0], 4),
                    "therm": round(resists["hull"][1], 4),
                    "kin": round(resists["hull"][2], 4),
                    "exp": round(resists["hull"][3], 4)
                }
            },
            "reps": {
                "burst": {
                    "shieldRegen":
                    round(shieldRegen[0], 2),
                    "shieldBoost":
                    round(selfRep[0], 2),
                    "armor":
                    round(selfRep[1], 2),
                    "hull":
                    round(selfRep[2], 2),
                    "total":
                    round(
                        shieldRegen[0] + selfRep[0] + selfRep[1] + selfRep[2],
                        2)
                },
                "sustained": {
                    "shieldRegen":
                    round(shieldRegen[0], 2),
                    "shieldBoost":
                    round(sustainRep[0], 2),
                    "armor":
                    round(sustainRep[1], 2),
                    "hull":
                    round(sustainRep[2], 2),
                    "total":
                    round(
                        shieldRegen[0] + sustainRep[0] + sustainRep[1] +
                        sustainRep[2], 2)
                }
            }
        },
        "misc": {
            "ship": {
                "id": fit.ship.item.ID,
                "name": fit.ship.item.name,
                "cpuMax": round(fit.ship.getModifiedItemAttr("cpuOutput"), 2),
                "powerMax": round(fit.ship.getModifiedItemAttr("powerOutput"),
                                  2),
                "cpuUsed": cpuUsed,
                "pgUsed": pgUsed,
                "calibrationUsed": calibrationUsed,
                "warpSpeed": warpSpeed
                # "cpuUsage": round(fit.cpuUsed(), 2)
                # "all": fit.ship.itemModifiedAttributes.
            },
            "drones": {
                "activeDrones": activeDrones,
                "droneBayTotal": fit.ship.getModifiedItemAttr("droneCapacity"),
                "droneBandwidthUsed": droneBandwidthUsed,
                "droneBayUsed": droneBayUsed,
            },
            "maxSpeed": round(fit.maxSpeed, 2),
            "signature": round(fit.ship.getModifiedItemAttr("signatureRadius"),
                               2),
            "capacitor": {
                "capacity":
                round(fit.ship.getModifiedItemAttr("capacitorCapacity"), 2),
                "stable":
                fit.capStable,
                "stableAt":
                round(fit.capState, 2) if fit.capStable else None,
                "lastsSeconds":
                round(fit.capState, 2) if not fit.capStable else None
            },
            "targeting": {
                "range": fit.maxTargetRange,
                "resolution": fit.ship.getModifiedItemAttr("scanResolution"),
                "strength": fit.scanStrength
            }
        }
    }
    from eos.const import SpoolType
    return json.dumps(data)
예제 #16
0
    def __getData(self, stuff):
        item = stuff.item
        if item is None:
            return "", None
        itemGroup = item.group.name
        itemCategory = item.category.name

        if itemGroup == "Ship Modifiers":
            return "", None
        elif itemGroup == "Booster":
            stuff.getModifiedItemAttr("boosterDuration")
            text = "{0} min".format(
                formatAmount(
                    stuff.getModifiedItemAttr("boosterDuration") / 1000 / 60,
                    3, 0, 3))
            return text, "Booster Duration"
        elif itemGroup in ("Super Weapon", "Structure Doomsday Weapon"):
            doomsday_duration = stuff.getModifiedItemAttr(
                "doomsdayDamageDuration", 1)
            doomsday_dottime = stuff.getModifiedItemAttr(
                "doomsdayDamageCycleTime", 1)
            func = stuff.getModifiedItemAttr

            volley = sum(
                map(lambda attr: (func("%sDamage" % attr) or 0),
                    ("em", "thermal", "kinetic", "explosive")))
            volley *= stuff.getModifiedItemAttr("damageMultiplier") or 1

            if volley <= 0:
                text = ""
                tooltip = ""
            elif max(doomsday_duration / doomsday_dottime, 1) > 1:
                text = "{} over {}s".format(
                    formatAmount(
                        volley * (doomsday_duration / doomsday_dottime), 3, 0,
                        6), formatAmount((doomsday_duration / 1000), 0, 0, 0))
                tooltip = "Raw damage done over time"
            else:
                text = "{0} dmg".format(
                    formatAmount(
                        volley * (doomsday_duration / doomsday_dottime), 3, 0,
                        3))
                tooltip = "Raw damage done"
            return text, tooltip

            pass
        elif itemGroup in ("Energy Weapon", "Hybrid Weapon",
                           "Projectile Weapon", "Combat Drone",
                           "Fighter Drone"):
            trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed")
            if not trackingSpeed:
                return "", None
            text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3))
            tooltip = "Tracking speed"
            return text, tooltip
        elif itemGroup == "Precursor Weapon":
            info = []
            trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed")
            if trackingSpeed:
                text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3))
                tooltip = "tracking speed"
                info.append((text, tooltip))
            # TODO: fetch spoolup option
            defaultSpoolValue = 1
            spoolTime = stuff.getSpoolData(spoolOptions=SpoolOptions(
                SpoolType.SCALE, defaultSpoolValue, False))[1]
            if spoolTime:
                text = "{0}s".format(formatAmount(spoolTime, 3, 0, 3))
                tooltip = "spool up time"
                info.append((text, tooltip))
            if not info:
                return "", None
            text = ' | '.join(i[0] for i in info)
            tooltip = ' and '.join(i[1] for i in info).capitalize()
            return text, tooltip
        elif itemCategory == "Subsystem":
            slots = ("hi", "med", "low")
            info = []
            for slot in slots:
                n = int(stuff.getModifiedItemAttr("%sSlotModifier" % slot))
                if n > 0:
                    info.append("{0}{1}".format(n, slot[0].upper()))
            return "+ " + ", ".join(info), "Slot Modifiers"
        elif itemGroup == "Energy Neutralizer":
            neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount")
            cycleTime = stuff.cycleTime
            if not neutAmount or not cycleTime:
                return "", None
            capPerSec = float(-neutAmount) * 1000 / cycleTime
            text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
            tooltip = "Energy neutralization per second"
            return text, tooltip
        elif itemGroup == "Energy Nosferatu":
            neutAmount = stuff.getModifiedItemAttr("powerTransferAmount")
            cycleTime = stuff.cycleTime
            if not neutAmount or not cycleTime:
                return "", None
            capPerSec = float(-neutAmount) * 1000 / cycleTime
            text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
            tooltip = "Energy neutralization per second"
            return text, tooltip
        elif itemGroup == "Salvager":
            chance = stuff.getModifiedItemAttr("accessDifficultyBonus")
            if not chance:
                return "", None
            text = "{0}%".format(formatAmount(chance, 3, 0, 3))
            tooltip = "Item retrieval chance"
            return text, tooltip
        elif itemGroup == "Data Miners":
            strength = stuff.getModifiedItemAttr("virusStrength")
            coherence = stuff.getModifiedItemAttr("virusCoherence")
            if not strength or not coherence:
                return "", None
            text = "{0} | {1}".format(formatAmount(strength, 3, 0, 3),
                                      formatAmount(coherence, 3, 0, 3))
            tooltip = "Virus strength and coherence"
            return text, tooltip
        elif itemGroup in ("Warp Scrambler", "Warp Core Stabilizer"):
            scramStr = stuff.getModifiedItemAttr("warpScrambleStrength")
            if not scramStr:
                return "", None
            text = "{0}".format(
                formatAmount(-scramStr, 3, 0, 3, forceSign=True))
            tooltip = "Warp core strength modification"
            return text, tooltip
        elif itemGroup in ("Stasis Web", "Stasis Webifying Drone"):
            speedFactor = stuff.getModifiedItemAttr("speedFactor")
            if not speedFactor:
                return "", None
            text = "{0}%".format(formatAmount(speedFactor, 3, 0, 3))
            tooltip = "Speed reduction"
            return text, tooltip
        elif itemGroup == "Target Painter":
            sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus")
            if not sigRadBonus:
                return "", None
            text = "{0}%".format(
                formatAmount(sigRadBonus, 3, 0, 3, forceSign=True))
            tooltip = "Signature radius increase"
            return text, tooltip
        elif itemGroup == "Sensor Dampener":
            lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus")
            scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus")
            if lockRangeBonus is None or scanResBonus is None:
                return "", None
            display = 0
            for bonus in (lockRangeBonus, scanResBonus):
                if abs(bonus) > abs(display):
                    display = bonus
            if not display:
                return "", None
            text = "{0}%".format(formatAmount(display, 3, 0, 3,
                                              forceSign=True))
            ttEntries = []
            if display == lockRangeBonus:
                ttEntries.append("lock range")
            if display == scanResBonus:
                ttEntries.append("scan resolution")
            tooltip = "{0} dampening".format(
                formatList(ttEntries)).capitalize()
            return text, tooltip
        elif itemGroup == "Weapon Disruptor":
            # Weapon disruption now covers both tracking and guidance (missile) disruptors
            # First get the attributes for tracking disruptors
            optimalRangeBonus = stuff.getModifiedItemAttr("maxRangeBonus")
            falloffRangeBonus = stuff.getModifiedItemAttr("falloffBonus")
            trackingSpeedBonus = stuff.getModifiedItemAttr(
                "trackingSpeedBonus")

            trackingDisruptorAttributes = {
                "optimal range": optimalRangeBonus,
                "falloff range": falloffRangeBonus,
                "tracking speed": trackingSpeedBonus
            }

            isTrackingDisruptor = any([
                x is not None and x != 0
                for x in list(trackingDisruptorAttributes.values())
            ])

            # Then get the attributes for guidance disruptors
            explosionVelocityBonus = stuff.getModifiedItemAttr(
                "aoeVelocityBonus")
            explosionRadiusBonus = stuff.getModifiedItemAttr(
                "aoeCloudSizeBonus")

            flightTimeBonus = stuff.getModifiedItemAttr("explosionDelayBonus")
            missileVelocityBonus = stuff.getModifiedItemAttr(
                "missileVelocityBonus")

            guidanceDisruptorAttributes = {
                "explosion velocity": explosionVelocityBonus,
                "explosion radius": explosionRadiusBonus,
                "flight time": flightTimeBonus,
                "missile velocity": missileVelocityBonus
            }

            isGuidanceDisruptor = any([
                x is not None and x != 0
                for x in list(guidanceDisruptorAttributes.values())
            ])

            if isTrackingDisruptor:
                attributes = trackingDisruptorAttributes
            elif isGuidanceDisruptor:
                attributes = guidanceDisruptorAttributes
            else:
                return "", None

            display = max(list(attributes.values()), key=lambda x: abs(x))

            text = "{0}%".format(formatAmount(display, 3, 0, 3,
                                              forceSign=True))

            ttEntries = []
            for attributeName, attributeValue in list(attributes.items()):
                if attributeValue == display:
                    ttEntries.append(attributeName)

            tooltip = "{0} disruption".format(
                formatList(ttEntries)).capitalize()
            return text, tooltip
        elif itemGroup in ("ECM", "Burst Jammer", "Burst Projectors"):
            grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus")
            ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus")
            radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus")
            magnet = stuff.getModifiedItemAttr(
                "scanMagnetometricStrengthBonus")
            displayMax = max(grav, ladar, radar, magnet)
            displayMin = min(grav, ladar, radar, magnet)
            if grav is None or ladar is None or radar is None or magnet is None or displayMax is None:
                return "", None

            if displayMax == displayMin or displayMin is None:
                text = "{0}".format(formatAmount(displayMax, 3, 0, 3), )
            else:
                text = "{0} | {1}".format(
                    formatAmount(displayMax, 3, 0, 3),
                    formatAmount(displayMin, 3, 0, 3),
                )
            tooltip = "ECM Jammer Strength:\n{0} Gravimetric | {1} Ladar | {2} Magnetometric | {3} Radar".format(
                formatAmount(grav, 3, 0, 3),
                formatAmount(ladar, 3, 0, 3),
                formatAmount(magnet, 3, 0, 3),
                formatAmount(radar, 3, 0, 3),
            )
            return text, tooltip
        elif itemGroup in ("Remote Sensor Booster", "Sensor Booster",
                           "Signal Amplifier"):
            scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus")
            lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus")
            gravBonus = stuff.getModifiedItemAttr(
                "scanGravimetricStrengthPercent")
            if scanResBonus is None or lockRangeBonus is None or gravBonus is None:
                return "", None

            text = "{0}% | {1}% | {2}%".format(
                formatAmount(scanResBonus, 3, 0, 3),
                formatAmount(lockRangeBonus, 3, 0, 3),
                formatAmount(gravBonus, 3, 0, 3),
            )
            tooltip = "Applied bonuses:\n{0}% scan resolution | {1}% lock range | {2}% sensor strength".format(
                formatAmount(scanResBonus, 3, 0, 3),
                formatAmount(lockRangeBonus, 3, 0, 3),
                formatAmount(gravBonus, 3, 0, 3),
            )
            return text, tooltip
        elif itemGroup in ("Projected ECCM", "ECCM", "Sensor Backup Array"):
            grav = stuff.getModifiedItemAttr("scanGravimetricStrengthPercent")
            ladar = stuff.getModifiedItemAttr("scanLadarStrengthPercent")
            radar = stuff.getModifiedItemAttr("scanRadarStrengthPercent")
            magnet = stuff.getModifiedItemAttr(
                "scanMagnetometricStrengthPercent")
            if grav is None or ladar is None or radar is None or magnet is None:
                return "", None
            display = max(grav, ladar, radar, magnet)
            if not display:
                return "", None
            text = "{0}%".format(formatAmount(display, 3, 0, 3,
                                              forceSign=True))
            ttEntries = []
            if display == grav:
                ttEntries.append("gravimetric")
            if display == ladar:
                ttEntries.append("ladar")
            if display == magnet:
                ttEntries.append("magnetometric")
            if display == radar:
                ttEntries.append("radar")
            plu = "" if len(ttEntries) == 1 else "s"
            tooltip = "{0} strength{1} bonus".format(formatList(ttEntries),
                                                     plu).capitalize()
            return text, tooltip
        elif itemGroup == "Cloaking Device":
            recalibration = stuff.getModifiedItemAttr("cloakingTargetingDelay")
            if recalibration is None:
                return "", None
            text = "{0}s".format(
                formatAmount(float(recalibration) / 1000, 3, 0, 3))
            tooltip = "Sensor recalibration time"
            return text, tooltip
        elif itemGroup == "Remote Armor Repairer":
            rps = stuff.getRemoteReps(ignoreState=True)[1]
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Armor repaired per second"
            return text, tooltip
        elif itemGroup == "Mutadaptive Remote Armor Repairer":
            # TODO: fetch spoolup option
            defaultSpoolValue = 1
            spoolOptDefault = SpoolOptions(SpoolType.SCALE, defaultSpoolValue,
                                           False)
            spoolOptPre = SpoolOptions(SpoolType.SCALE, 0, True)
            spoolOptFull = SpoolOptions(SpoolType.SCALE, 1, True)
            rrType, rps = stuff.getRemoteReps(spoolOptions=spoolOptDefault,
                                              ignoreState=True)
            rrTypePre, rpsPre = stuff.getRemoteReps(spoolOptions=spoolOptPre,
                                                    ignoreState=True)
            rrTypeFull, rpsFull = stuff.getRemoteReps(
                spoolOptions=spoolOptFull, ignoreState=True)
            if not rps:
                return "", None
            text = []
            tooltip = []
            text.append("{}/s".format(
                formatAmount(rps, 3, 0, 3, forceSign=True)))
            tooltip.append("Armor repaired per second")
            spoolTime = stuff.getSpoolData(spoolOptDefault)[1]
            if spoolTime:
                text.append("{}s".format(formatAmount(spoolTime, 3, 0, 3)))
                tooltip.append("spool up time")
            text = " | ".join(text)
            tooltip = " and ".join(tooltip)
            spoolTimePre = stuff.getSpoolData(spoolOptPre)[1]
            spoolTimeFull = stuff.getSpoolData(spoolOptFull)[1]
            if spoolTimePre != spoolTimeFull:
                tooltip = "{}\nSpool up: {}-{} over {}s".format(
                    tooltip, formatAmount(rpsPre, 3, 0, 3),
                    formatAmount(rpsFull, 3, 0, 3),
                    formatAmount(spoolTimeFull - spoolTimePre, 3, 0, 3))
            return text, tooltip
        elif itemGroup == "Remote Shield Booster":
            rps = stuff.getRemoteReps(ignoreState=True)[1]
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Shield transferred per second"
            return text, tooltip
        elif itemGroup == "Remote Capacitor Transmitter":
            rps = stuff.getRemoteReps(ignoreState=True)[1]
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Energy transferred per second"
            return text, tooltip
        elif itemGroup == "Remote Hull Repairer":
            rps = stuff.getRemoteReps(ignoreState=True)[1]
            if not rps:
                return "", None
            text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
            tooltip = "Structure repaired per second"
            return text, tooltip
        elif itemGroup == "Gang Coordinator":
            command = stuff.getModifiedItemAttr(
                "commandBonus") or stuff.getModifiedItemAttr(
                    "commandBonusHidden")
            if not command:
                return "", None
            text = "{0}%".format(formatAmount(command, 3, 0, 3,
                                              forceSign=True))
            tooltip = "Gang bonus strength"
            return text, tooltip
        elif itemGroup == "Electronic Warfare Drone":
            sigRadBonus = stuff.getModifiedItemAttr("signatureRadiusBonus")
            lockRangeMult = stuff.getModifiedItemAttr(
                "maxTargetRangeMultiplier")
            scanResMult = stuff.getModifiedItemAttr("scanResolutionMultiplier")
            falloffRangeMult = stuff.getModifiedItemAttr("fallofMultiplier")
            optimalRangeMult = stuff.getModifiedItemAttr("maxRangeMultiplier")
            trackingSpeedMult = stuff.getModifiedItemAttr(
                "trackingSpeedMultiplier")
            grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus")
            ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus")
            radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus")
            magnet = stuff.getModifiedItemAttr(
                "scanMagnetometricStrengthBonus")
            if sigRadBonus:
                text = "{0}%".format(
                    formatAmount(sigRadBonus, 3, 0, 3, forceSign=True))
                tooltip = "Signature radius increase"
                return text, tooltip
            if lockRangeMult is not None and scanResMult is not None:
                lockRangeBonus = (lockRangeMult - 1) * 100
                scanResBonus = (scanResMult - 1) * 100
                display = 0
                for bonus in (lockRangeBonus, scanResBonus):
                    if abs(bonus) > abs(display):
                        display = bonus
                if not display:
                    return "", None
                text = "{0}%".format(
                    formatAmount(display, 3, 0, 3, forceSign=True))
                ttEntries = []
                if display == lockRangeBonus:
                    ttEntries.append("lock range")
                if display == scanResBonus:
                    ttEntries.append("scan resolution")
                tooltip = "{0} dampening".format(
                    formatList(ttEntries)).capitalize()
                return text, tooltip
            if falloffRangeMult is not None and optimalRangeMult is not None and trackingSpeedMult is not None:
                falloffRangeBonus = (falloffRangeMult - 1) * 100
                optimalRangeBonus = (optimalRangeMult - 1) * 100
                trackingSpeedBonus = (trackingSpeedMult - 1) * 100
                display = 0
                for bonus in (falloffRangeBonus, optimalRangeBonus,
                              trackingSpeedBonus):
                    if abs(bonus) > abs(display):
                        display = bonus
                if not display:
                    return "", None
                text = "{0}%".format(formatAmount(display, 3, 0, 3),
                                     forceSign=True)
                ttEntries = []
                if display == optimalRangeBonus:
                    ttEntries.append("optimal range")
                if display == falloffRangeBonus:
                    ttEntries.append("falloff range")
                if display == trackingSpeedBonus:
                    ttEntries.append("tracking speed")
                tooltip = "{0} disruption".format(
                    formatList(ttEntries)).capitalize()
                return text, tooltip
            if grav is not None and ladar is not None and radar is not None and magnet is not None:
                display = max(grav, ladar, radar, magnet)
                if not display:
                    return "", None
                text = "{0}".format(formatAmount(display, 3, 0, 3))
                ttEntries = []
                if display == grav:
                    ttEntries.append("gravimetric")
                if display == ladar:
                    ttEntries.append("ladar")
                if display == magnet:
                    ttEntries.append("magnetometric")
                if display == radar:
                    ttEntries.append("radar")
                plu = "" if len(ttEntries) == 1 else "s"
                tooltip = "{0} strength{1}".format(formatList(ttEntries),
                                                   plu).capitalize()
                return text, tooltip
            else:
                return "", None
        elif itemGroup == "Fighter Bomber":
            optimalSig = stuff.getModifiedItemAttr("optimalSigRadius")
            if not optimalSig:
                return "", None
            text = "{0}m".format(formatAmount(optimalSig, 3, 0, 3))
            tooltip = "Optimal signature radius"
            return text, tooltip
        elif itemGroup in ("Frequency Mining Laser", "Strip Miner",
                           "Mining Laser", "Gas Cloud Harvester",
                           "Mining Drone"):
            miningAmount = stuff.getModifiedItemAttr(
                "specialtyMiningAmount") or stuff.getModifiedItemAttr(
                    "miningAmount")
            cycleTime = getattr(stuff, 'cycleTime',
                                stuff.getModifiedItemAttr("duration"))
            if not miningAmount or not cycleTime:
                return "", None
            minePerSec = (float(miningAmount) * 1000 / cycleTime)
            text = "{0} m3/s".format(formatAmount(minePerSec, 3, 0, 3))
            tooltip = "Mining Yield per second ({0} per hour)".format(
                formatAmount(minePerSec * 3600, 3, 0, 3))
            return text, tooltip
        elif itemGroup == "Logistic Drone":
            repType, rps = stuff.getRemoteReps(ignoreState=True)
            if not repType:
                return "", None
            text = "{}/s".format(formatAmount(rps, 3, 0, 3))
            tooltip = "{} HP repaired per second\n{} HP/s per drone".format(
                repType, formatAmount(rps / stuff.amount, 3, 0, 3))
            return text, tooltip
        elif itemGroup == "Energy Neutralizer Drone":
            neutAmount = stuff.getModifiedItemAttr("energyNeutralizerAmount")
            cycleTime = stuff.getModifiedItemAttr("energyNeutralizerDuration")
            if not neutAmount or not cycleTime:
                return "", None
            capPerSec = float(-neutAmount) * 1000 / cycleTime
            text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
            tooltip = "Energy neutralization per second"
            return text, tooltip
        elif itemGroup == "Micro Jump Drive":
            cycleTime = stuff.getModifiedItemAttr("duration") / 1000
            text = "{0}s".format(cycleTime)
            tooltip = "Spoolup time"
            return text, tooltip
        elif itemGroup in ("Siege Module", "Cynosural Field"):
            amt = stuff.getModifiedItemAttr("consumptionQuantity")
            if amt:
                typeID = stuff.getModifiedItemAttr("consumptionType")
                item = Market.getInstance().getItem(typeID)
                text = "{0} units".format(formatAmount(amt, 3, 0, 3))
                return text, item.name
            else:
                return "", None
        elif itemGroup in (
                "Ancillary Armor Repairer",
                "Ancillary Shield Booster",
                "Capacitor Booster",
                "Ancillary Remote Armor Repairer",
                "Ancillary Remote Shield Booster",
        ):
            if "Armor" in itemGroup or "Shield" in itemGroup:
                boosted_attribute = "HP"
                reload_time = item.getAttribute("reloadTime", 0) / 1000
            elif "Capacitor" in itemGroup:
                boosted_attribute = "Cap"
                reload_time = 10
            else:
                boosted_attribute = ""
                reload_time = 0

            cycles = max(stuff.numShots, 0)
            cycleTime = max(stuff.rawCycleTime, 0)

            # Get HP or boosted amount
            stuff_hp = max(stuff.hpBeforeReload, 0)
            armor_hp = stuff.getModifiedItemAttr("armorDamageAmount", 0)
            capacitor_hp = stuff.getModifiedChargeAttr("capacitorBonus", 0)
            shield_hp = stuff.getModifiedItemAttr("shieldBonus", 0)
            hp = max(stuff_hp, armor_hp * cycles, capacitor_hp * cycles,
                     shield_hp * cycles, 0)

            if not hp or not cycleTime or not cycles:
                return "", None

            fit = Fit.getInstance().getFit(self.fittingView.getActiveFit())
            ehpTotal = fit.ehp
            hpTotal = fit.hp
            useEhp = self.mainFrame.statsPane.nameViewMap[
                "resistancesViewFull"].showEffective
            tooltip = "{0} restored over duration using charges (plus reload)".format(
                boosted_attribute)

            if useEhp and boosted_attribute == "HP" and "Remote" not in itemGroup:
                if "Ancillary Armor Repairer" in itemGroup:
                    hpRatio = ehpTotal["armor"] / hpTotal["armor"]
                else:
                    hpRatio = ehpTotal["shield"] / hpTotal["shield"]
                tooltip = "E{0}".format(tooltip)
            else:
                hpRatio = 1

            if "Ancillary" in itemGroup and "Armor" in itemGroup:
                hpRatio *= stuff.getModifiedItemAttr(
                    "chargedArmorDamageMultiplier", 1)

            ehp = hp * hpRatio

            duration = cycles * cycleTime / 1000
            for number_of_cycles in {5, 10, 25}:
                tooltip = "{0}\n{1} charges lasts {2} seconds ({3} cycles)".format(
                    tooltip, formatAmount(number_of_cycles * cycles, 3, 0, 3),
                    formatAmount((duration + reload_time) * number_of_cycles,
                                 3, 0, 3),
                    formatAmount(number_of_cycles, 3, 0, 3))
            text = "{0} / {1}s (+{2}s)".format(
                formatAmount(ehp, 3, 0, 9), formatAmount(duration, 3, 0, 3),
                formatAmount(reload_time, 3, 0, 3))

            return text, tooltip
        elif itemGroup == "Armor Resistance Shift Hardener":
            itemArmorResistanceShiftHardenerEM = (
                1 - stuff.getModifiedItemAttr("armorEmDamageResonance")) * 100
            itemArmorResistanceShiftHardenerTherm = (
                1 -
                stuff.getModifiedItemAttr("armorThermalDamageResonance")) * 100
            itemArmorResistanceShiftHardenerKin = (
                1 -
                stuff.getModifiedItemAttr("armorKineticDamageResonance")) * 100
            itemArmorResistanceShiftHardenerExp = (
                1 - stuff.getModifiedItemAttr("armorExplosiveDamageResonance")
            ) * 100

            text = "{0}% | {1}% | {2}% | {3}%".format(
                formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3),
            )
            tooltip = "Resistances Shifted to Damage Profile:\n{0}% EM | {1}% Therm | {2}% Kin | {3}% Exp".format(
                formatAmount(itemArmorResistanceShiftHardenerEM, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerTherm, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerKin, 3, 0, 3),
                formatAmount(itemArmorResistanceShiftHardenerExp, 3, 0, 3),
            )
            return text, tooltip
        elif stuff.charge is not None:
            chargeGroup = stuff.charge.group.name
            if chargeGroup.endswith("Rocket") or chargeGroup.endswith(
                    "Missile") or chargeGroup.endswith("Torpedo"):
                cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize")
                aoeVelocity = stuff.getModifiedChargeAttr("aoeVelocity")
                if not cloudSize or not aoeVelocity:
                    return "", None
                text = "{0}{1} | {2}{3}".format(
                    formatAmount(cloudSize, 3, 0, 3), "m",
                    formatAmount(aoeVelocity, 3, 0, 3), "m/s")
                tooltip = "Explosion radius and explosion velocity"
                return text, tooltip
            elif chargeGroup == "Bomb":
                cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize")
                if not cloudSize:
                    return "", None
                text = "{0}{1}".format(formatAmount(cloudSize, 3, 0, 3), "m")
                tooltip = "Explosion radius"
                return text, tooltip
            elif chargeGroup in ("Scanner Probe", ):
                scanStr = stuff.getModifiedChargeAttr("baseSensorStrength")
                baseRange = stuff.getModifiedChargeAttr("baseScanRange")
                if not scanStr or not baseRange:
                    return "", None
                strTwoAu = scanStr / (2.0 / baseRange)
                text = "{0}".format(formatAmount(strTwoAu, 3, 0, 3))
                tooltip = "Scan strength with 2 AU scan range"
                return text, tooltip
            else:
                return "", None
        else:
            return "", None
예제 #17
0
 def _getValue(self, fit):
     defaultSpoolValue = eos.config.settings['globalDefaultSpoolupPercentage']
     return fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, defaultSpoolValue, False)).hull, 'HP/s'
예제 #18
0
 def _getValue(self, fit):
     defaultSpoolValue = eos.config.settings['globalDefaultSpoolupPercentage']
     return fit.getTotalDps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, defaultSpoolValue, False)).total, None
예제 #19
0
 def getWeaponSystemData(fit):
     weaponSystems = []
     groups = {}
     # Export at maximum spool for consistency, spoolup data is exported anyway.
     defaultSpoolValue = 1
     spoolOptions = SpoolOptions(SpoolType.SPOOL_SCALE, defaultSpoolValue,
                                 True)
     for mod in fit.modules:
         if mod.getDps(spoolOptions=spoolOptions).total > 0:
             # Group weapon + ammo combinations that occur more than once
             keystr = str(mod.itemID) + "-" + str(mod.chargeID)
             if keystr in groups:
                 groups[keystr][1] += 1
             else:
                 groups[keystr] = [mod, 1]
     for wepGroup in groups.values():
         stats = wepGroup[0]
         n = wepGroup[1]
         tracking = 0
         maxVelocity = 0
         explosionDelay = 0
         damageReductionFactor = 0
         explosionRadius = 0
         explosionVelocity = 0
         aoeFieldRange = 0
         typeing = 'None'
         if stats.charge:
             name = stats.item.typeName + ", " + stats.charge.typeName
         else:
             name = stats.item.typeName
         if stats.hardpoint == FittingHardpoint.TURRET:
             tracking = stats.getModifiedItemAttr("trackingSpeed")
             typeing = "Turret"
         # Bombs share most attributes with missiles despite not needing the hardpoint
         elif stats.hardpoint == FittingHardpoint.MISSILE or "Bomb Launcher" in stats.item.typeName:
             maxVelocity = stats.getModifiedChargeAttr("maxVelocity")
             explosionDelay = stats.getModifiedChargeAttr("explosionDelay")
             damageReductionFactor = stats.getModifiedChargeAttr(
                 "aoeDamageReductionFactor")
             explosionRadius = stats.getModifiedChargeAttr("aoeCloudSize")
             explosionVelocity = stats.getModifiedChargeAttr("aoeVelocity")
             typeing = "Missile"
         # AoE DDs can be treated like missiles with a damageReductionFactor of 0
         elif stats.item.group.name == 'Super Weapon' and stats.maxRange:
             explosionRadius = stats.getModifiedItemAttr("signatureRadius")
             typeing = "Missile"
         elif stats.hardpoint == FittingHardpoint.NONE:
             aoeFieldRange = stats.getModifiedItemAttr("empFieldRange")
             # This also covers non-bomb weapons with dps values and no hardpoints, most notably targeted doomsdays.
             typeing = "SmartBomb"
         # Targeted DDs are the only non drone/fighter weapon without an explicit max range
         if stats.item.group.name == 'Super Weapon' and stats.maxRange is None:
             maxRange = 300000
         else:
             maxRange = stats.maxRange
         statDict = {
             "dps":
             stats.getDps(spoolOptions=spoolOptions).total * n,
             "capUse":
             stats.capUse * n,
             "falloff":
             stats.falloff,
             "type":
             typeing,
             "name":
             name,
             "optimal":
             maxRange,
             "numCharges":
             stats.numCharges,
             "numShots":
             stats.numShots,
             "reloadTime":
             stats.reloadTime,
             "cycleTime":
             stats.getCycleParameters().averageTime,
             "volley":
             stats.getVolley(spoolOptions=spoolOptions).total * n,
             "tracking":
             tracking,
             "maxVelocity":
             maxVelocity,
             "explosionDelay":
             explosionDelay,
             "damageReductionFactor":
             damageReductionFactor,
             "explosionRadius":
             explosionRadius,
             "explosionVelocity":
             explosionVelocity,
             "aoeFieldRange":
             aoeFieldRange,
             "damageMultiplierBonusMax":
             stats.getModifiedItemAttr("damageMultiplierBonusMax"),
             "damageMultiplierBonusPerCycle":
             stats.getModifiedItemAttr("damageMultiplierBonusPerCycle")
         }
         weaponSystems.append(statDict)
     for drone in fit.drones:
         if drone.getDps().total > 0 and drone.amountActive > 0:
             droneAttr = drone.getModifiedItemAttr
             # Drones are using the old tracking formula for trackingSpeed. This updates it to match turrets.
             newTracking = droneAttr("trackingSpeed") / (
                 droneAttr("optimalSigRadius") / 40000)
             statDict = {
                 "dps": drone.getDps().total,
                 "cycleTime": drone.getCycleParameters().averageTime,
                 "type": "Drone",
                 "optimal": drone.maxRange,
                 "name": drone.item.typeName,
                 "falloff": drone.falloff,
                 "maxSpeed": droneAttr("maxVelocity"),
                 "tracking": newTracking,
                 "volley": drone.getVolley().total
             }
             weaponSystems.append(statDict)
     for fighter in fit.fighters:
         if fighter.getDps().total > 0 and fighter.amount > 0:
             fighterAttr = fighter.getModifiedItemAttr
             abilities = []
             if "fighterAbilityAttackMissileDamageEM" in fighter.item.attributes.keys(
             ):
                 baseRef = "fighterAbilityAttackMissile"
                 ability = EfsPort.getFighterAbilityData(
                     fighterAttr, fighter, baseRef)
                 abilities.append(ability)
             if "fighterAbilityMissilesDamageEM" in fighter.item.attributes.keys(
             ):
                 baseRef = "fighterAbilityMissiles"
                 ability = EfsPort.getFighterAbilityData(
                     fighterAttr, fighter, baseRef)
                 abilities.append(ability)
             statDict = {
                 "dps": fighter.getDps().total,
                 "type": "Fighter",
                 "name": fighter.item.typeName,
                 "maxSpeed": fighterAttr("maxVelocity"),
                 "abilities": abilities,
                 "ehp":
                 fighterAttr("shieldCapacity") / 0.8875 * fighter.amount,
                 "volley": fighter.getVolley().total,
                 "signatureRadius": fighterAttr("signatureRadius")
             }
             weaponSystems.append(statDict)
     return weaponSystems
예제 #20
0
#
# You should have received a copy of the GNU General Public License
# along with pyfa.  If not, see <http://www.gnu.org/licenses/>.
# ===============================================================================

# noinspection PyPackageRequirements
import wx
from gui.statsView import StatsView
from gui.utils.numberFormatter import formatAmount, roundToPrec
from eos.utils.spoolSupport import SpoolType, SpoolOptions
import eos.config

stats = [
    ("labelRemoteCapacitor", "Capacitor:", "{}{} GJ/s", "capacitorInfo",
     "Capacitor restored",
     lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(
         SpoolType.SPOOL_SCALE, spool, False)).capacitor,
     lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(
         SpoolType.SPOOL_SCALE, 0, True)).capacitor,
     lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(
         SpoolType.SPOOL_SCALE, 1, True)).capacitor, 3, 0, 0),
    ("labelRemoteShield", "Shield:", "{}{} HP/s", "shieldActive",
     "Shield restored",
     lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(
         SpoolType.SPOOL_SCALE, spool, False)).shield,
     lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(
         SpoolType.SPOOL_SCALE, 0, True)).shield,
     lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(
         SpoolType.SPOOL_SCALE, 1, True)).shield, 3, 0, 0),
    ("labelRemoteArmor", "Armor:", "{}{} HP/s", "armorActive",
     "Armor restored", lambda fit, spool: fit.getRemoteReps(
         spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).armor,
예제 #21
0
    def refreshPanel(self, fit):
        # If we did anything intresting, we'd update our labels to reflect the new fit's stats here
        if fit is not None and fit.targetProfile is not None:
            self.stEff.Show()
        else:
            self.stEff.Hide()

        def hasSpoolUp(preSpool, fullSpool):
            if preSpool is None or fullSpool is None:
                return False
            return roundToPrec(preSpool.total, prec) != roundToPrec(
                fullSpool.total, prec)

        def dpsToolTip(normal, preSpool, fullSpool, prec, lowest, highest):
            if normal is None or preSpool is None or fullSpool is None:
                return ""
            hasSpool = hasSpoolUp(preSpool, fullSpool)
            lines = []
            if hasSpool:
                lines.append(
                    _t("Spool up") + ": {}-{}".format(
                        formatAmount(preSpool.total, prec, lowest, highest),
                        formatAmount(fullSpool.total, prec, lowest, highest)))
            if getattr(normal, 'total', None):
                if hasSpool:
                    lines.append("")
                    lines.append(
                        _t("Current") + ": {}".format(
                            formatAmount(normal.total, prec, lowest, highest)))
                for dmgType in normal.names():
                    val = getattr(normal, dmgType, None)
                    if val:
                        lines.append("{}{}: {}%".format(
                            "  " if hasSpool else "",
                            _t(dmgType).capitalize(),
                            formatAmount(val / normal.total * 100, 3, 0, 0)))
            return "\n".join(lines)

        defaultSpoolValue = eos.config.settings[
            'globalDefaultSpoolupPercentage']
        stats = (("labelFullDpsWeapon",
                  lambda: fit.getWeaponDps(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, defaultSpoolValue, False)),
                  lambda: fit.getWeaponDps(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, 0, True)),
                  lambda: fit.getWeaponDps(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, 1, True)), 3, 0, 0, "{}{} DPS"),
                 ("labelFullDpsDrone", lambda: fit.getDroneDps(),
                  lambda: fit.getDroneDps(), lambda: fit.getDroneDps(), 3, 0,
                  0, "{}{} DPS"),
                 ("labelFullVolleyTotal",
                  lambda: fit.getTotalVolley(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, defaultSpoolValue, False)),
                  lambda: fit.getTotalVolley(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, 0, True)),
                  lambda: fit.getTotalVolley(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, 1, True)), 3, 0, 0, "{}{}"),
                 ("labelFullDpsTotal",
                  lambda: fit.getTotalDps(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, defaultSpoolValue, False)),
                  lambda: fit.getTotalDps(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, 0, True)),
                  lambda: fit.getTotalDps(spoolOptions=SpoolOptions(
                      SpoolType.SPOOL_SCALE, 1, True)), 3, 0, 0, "{}{}"))

        counter = 0
        for labelName, val, preSpoolVal, fullSpoolVal, prec, lowest, highest, valueFormat in stats:
            label = getattr(self, labelName)
            val = val() if fit is not None else None
            preSpoolVal = preSpoolVal() if fit is not None else None
            fullSpoolVal = fullSpoolVal() if fit is not None else None
            if self._cachedValues[counter] != val:
                tooltipText = dpsToolTip(val, preSpoolVal, fullSpoolVal, prec,
                                         lowest, highest)
                label.SetLabel(
                    valueFormat.format(
                        formatAmount(0 if val is None else val.total, prec,
                                     lowest, highest), "\u02e2" if hasSpoolUp(
                                         preSpoolVal, fullSpoolVal) else ""))
                label.SetToolTip(wx.ToolTip(tooltipText))
                self._cachedValues[counter] = val
            counter += 1

        self.panel.Layout()
        self.headerPanel.Layout()
예제 #22
0
파일: fitDpsVsTime.py 프로젝트: AlanAu/Pyfa
    def __generateCache(self, fit, maxTime):
        cache = []

        def addDmg(addedTimeStart, addedTimeFinish, addedDmg):
            if addedDmg == 0:
                return
            addedDps = 1000 * addedDmg / (addedTimeFinish - addedTimeStart)
            cache.append((addedTimeStart, addedTimeFinish, addedDps))

        # We'll handle calculations in milliseconds
        maxTime = maxTime * 1000
        for mod in fit.modules:
            if not mod.isDealingDamage():
                continue
            cycleParams = mod.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            nonstopCycles = 0
            for cycleTime, inactiveTime in cycleParams.iterCycles():
                cycleDamage = 0
                volleyParams = mod.getVolleyParameters(spoolOptions=SpoolOptions(SpoolType.CYCLES, nonstopCycles, True))
                for volleyTime, volley in volleyParams.items():
                    cycleDamage += volley.total
                addDmg(currentTime, currentTime + cycleTime, cycleDamage)
                currentTime += cycleTime + inactiveTime
                if inactiveTime > 0:
                    nonstopCycles = 0
                else:
                    nonstopCycles += 1
                if currentTime > maxTime:
                    break
        for drone in fit.drones:
            if not drone.isDealingDamage():
                continue
            cycleParams = drone.getCycleParameters(reloadOverride=True)
            if cycleParams is None:
                continue
            currentTime = 0
            for cycleTime, inactiveTime in cycleParams.iterCycles():
                cycleDamage = 0
                volleyParams = drone.getVolleyParameters()
                for volleyTime, volley in volleyParams.items():
                    cycleDamage += volley.total
                addDmg(currentTime, currentTime + cycleTime, cycleDamage)
                currentTime += cycleTime + inactiveTime
                if currentTime > maxTime:
                    break
        for fighter in fit.fighters:
            if not fighter.isDealingDamage():
                continue
            cycleParams = fighter.getCycleParametersPerEffectOptimizedDps(reloadOverride=True)
            if cycleParams is None:
                continue
            volleyParams = fighter.getVolleyParametersPerEffect()
            for effectID, abilityCycleParams in cycleParams.items():
                if effectID not in volleyParams:
                    continue
                abilityVolleyParams = volleyParams[effectID]
                currentTime = 0
                for cycleTime, inactiveTime in abilityCycleParams.iterCycles():
                    cycleDamage = 0
                    for volleyTime, volley in abilityVolleyParams.items():
                        cycleDamage += volley.total
                    addDmg(currentTime, currentTime + cycleTime, cycleDamage)
                    currentTime += cycleTime + inactiveTime
                    if currentTime > maxTime:
                        break

        # Post-process cache
        finalCache = {}
        for time in sorted(set(chain((i[0] for i in cache), (i[1] for i in cache)))):
            entries = (e for e in cache if e[0] <= time < e[1])
            dps = sum(e[2] for e in entries)
            finalCache[time] = dps
        self._cache[fit.ID] = finalCache