Merge branch 'master' into spoolup

This commit is contained in:
DarkPhoenix
2019-03-18 16:04:45 +03:00
50 changed files with 562 additions and 431 deletions

View File

@@ -129,7 +129,8 @@ def Saveddata():
from eos.saveddata.ship import Ship
from eos.saveddata.fit import Fit
from eos.saveddata.character import Character
from eos.saveddata.module import Module, State
from eos.saveddata.module import Module
from eos.const import FittingModuleState
from eos.saveddata.citadel import Citadel
from eos.saveddata.booster import Booster
@@ -139,7 +140,7 @@ def Saveddata():
'Fit' : Fit,
'Character': Character,
'Module' : Module,
'State' : State,
'State' : FittingModuleState,
'Booster' : Booster,
}
return helper

View File

@@ -6,7 +6,7 @@ import wx
from logbook import CRITICAL, DEBUG, ERROR, FingersCrossedHandler, INFO, Logger, NestedSetup, NullHandler, \
StreamHandler, TimedRotatingFileHandler, WARNING
import hashlib
from eos.const import Slot
from eos.const import FittingSlot
from cryptography.fernet import Fernet
@@ -50,11 +50,11 @@ LOGLEVEL_MAP = {
}
slotColourMap = {
Slot.LOW: wx.Colour(250, 235, 204), # yellow = low slots
Slot.MED: wx.Colour(188, 215, 241), # blue = mid slots
Slot.HIGH: wx.Colour(235, 204, 209), # red = high slots
Slot.RIG: '',
Slot.SUBSYSTEM: ''
FittingSlot.LOW: wx.Colour(250, 235, 204), # yellow = low slots
FittingSlot.MED: wx.Colour(188, 215, 241), # blue = mid slots
FittingSlot.HIGH: wx.Colour(235, 204, 209), # red = high slots
FittingSlot.RIG: '',
FittingSlot.SUBSYSTEM: ''
}
def getClientSecret():

View File

@@ -19,7 +19,7 @@ if istravis is True or hasattr(sys, '_called_from_test'):
# Running in Travis. Run saveddata database in memory.
saveddata_connectionstring = 'sqlite:///:memory:'
else:
saveddata_connectionstring = 'sqlite:///' + realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata-py3-db.db"))
saveddata_connectionstring = 'sqlite:///' + realpath(join(dirname(abspath(__file__)), "..", "saveddata", "saveddata.db"))
pyfalog.debug("Saveddata connection string: {0}", saveddata_connectionstring)

View File

@@ -1,8 +1,30 @@
from eos.enum import Enum
# =============================================================================
# Copyright (C) 2019 Ryan Holmes
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
from enum import IntEnum,unique
class Slot(Enum):
@unique
class FittingSlot(IntEnum):
"""
Contains slots for ship fittings
"""
# These are self-explanatory
LOW = 1
MED = 2
@@ -24,3 +46,40 @@ class Slot(Enum):
FS_LIGHT = 13
FS_SUPPORT = 14
FS_HEAVY = 15
@unique
class ImplantLocation(IntEnum):
"""
Contains location of the implant
"""
FIT = 0
CHARACTER = 1
@unique
class CalcType(IntEnum):
"""
Contains location of the calculation
"""
LOCAL = 0
PROJECTED = 1
COMMAND = 2
@unique
class FittingModuleState(IntEnum):
"""
Contains the state of a fitting module
"""
OFFLINE = -1
ONLINE = 0
ACTIVE = 1
OVERHEATED = 2
@unique
class FittingHardpoint(IntEnum):
"""
Contains the types of a fitting hardpoint
"""
NONE = 0
MISSILE = 1
TURRET = 2

View File

@@ -21,6 +21,7 @@ import sys
from sqlalchemy.sql import and_
from sqlalchemy import desc, select
from sqlalchemy import func
from eos.db import saveddata_session, sd_lock
from eos.db.saveddata.fit import projectedFits_table
@@ -283,6 +284,12 @@ def countAllFits():
return count
def countFitGroupedByShip():
with sd_lock:
count = eos.db.saveddata_session.query(Fit.shipID, func.count(Fit.shipID)).group_by(Fit.shipID).all()
return count
def countFitsWithShip(lookfor, ownerID=None, where=None, eager=None):
"""
Get all the fits using a certain ship.

View File

@@ -3,15 +3,15 @@
# Used by:
# Module: Energy Neutralization Burst Projector
# Structure Module: Standup Energy Neutralization Burst Projector
from eos.saveddata.module import State
from eos.const import FittingModuleState
from eos.modifiedAttributeDict import ModifiedAttributeDict
type = "active", "projected"
def handler(fit, src, context, **kwargs):
if "projected" in context and ((hasattr(src, "state") and src.state >= State.ACTIVE) or
hasattr(src, "amountActive")):
if "projected" in context and ((hasattr(src, "state") and src.state >= FittingModuleState.ACTIVE) or
hasattr(src, "amountActive")):
amount = src.getModifiedItemAttr("energyNeutralizerAmount")
if 'effect' in kwargs:

View File

@@ -2,15 +2,15 @@
#
# Used by:
# Modules from group: Energy Neutralizer (54 of 54)
from eos.saveddata.module import State
from eos.const import FittingModuleState
from eos.modifiedAttributeDict import ModifiedAttributeDict
type = "active", "projected"
def handler(fit, src, context, **kwargs):
if "projected" in context and ((hasattr(src, "state") and src.state >= State.ACTIVE) or
hasattr(src, "amountActive")):
if "projected" in context and ((hasattr(src, "state") and src.state >= FittingModuleState.ACTIVE) or
hasattr(src, "amountActive")):
amount = src.getModifiedItemAttr("energyNeutralizerAmount")
if 'effect' in kwargs:

View File

@@ -2,15 +2,15 @@
#
# Used by:
# Drones from group: Energy Neutralizer Drone (3 of 3)
from eos.saveddata.module import State
from eos.const import FittingModuleState
from eos.modifiedAttributeDict import ModifiedAttributeDict
type = "active", "projected"
def handler(fit, src, context, **kwargs):
if "projected" in context and ((hasattr(src, "state") and src.state >= State.ACTIVE) or
hasattr(src, "amountActive")):
if "projected" in context and ((hasattr(src, "state") and src.state >= FittingModuleState.ACTIVE) or
hasattr(src, "amountActive")):
amount = src.getModifiedItemAttr("energyNeutralizerAmount")
time = src.getModifiedItemAttr("energyNeutralizerDuration")

View File

@@ -0,0 +1,17 @@
runTime = "early"
type = "passive"
def handler(fit, module, context):
secModifier = module.getModifiedItemAttr("securityModifier")
module.multiplyItemAttr("structureRigDoomsdayDamageLossTargetBonus", secModifier)
module.multiplyItemAttr("structureRigScanResBonus", secModifier)
module.multiplyItemAttr("structureRigPDRangeBonus", secModifier)
module.multiplyItemAttr("structureRigPDCapUseBonus", secModifier)
module.multiplyItemAttr("structureRigMissileExploVeloBonus", secModifier)
module.multiplyItemAttr("structureRigMissileVelocityBonus", secModifier)
module.multiplyItemAttr("structureRigEwarOptimalBonus", secModifier)
module.multiplyItemAttr("structureRigEwarFalloffBonus", secModifier)
module.multiplyItemAttr("structureRigEwarCapUseBonus", secModifier)
module.multiplyItemAttr("structureRigMissileExplosionRadiusBonus", secModifier)
module.multiplyItemAttr("structureRigMaxTargetRangeBonus", secModifier)

View File

@@ -2,7 +2,7 @@
#
# Used by:
# Structure Modules from group: Structure Energy Neutralizer (5 of 5)
from eos.saveddata.module import State
from eos.const import FittingModuleState
from eos.modifiedAttributeDict import ModifiedAttributeDict
type = "active", "projected"
@@ -11,7 +11,7 @@ type = "active", "projected"
def handler(fit, src, context, **kwargs):
amount = 0
if "projected" in context:
if (hasattr(src, "state") and src.state >= State.ACTIVE) or hasattr(src, "amountActive"):
if (hasattr(src, "state") and src.state >= FittingModuleState.ACTIVE) or hasattr(src, "amountActive"):
amount = src.getModifiedItemAttr("energyNeutralizerAmount")
if 'effect' in kwargs:

View File

@@ -2,7 +2,7 @@
#
# Used by:
# Structure Modules from group: Structure Warp Scrambler (2 of 2)
from eos.saveddata.module import State
from eos.const import FittingModuleState
# Not used by any item
runTime = "early"
@@ -14,7 +14,7 @@ def handler(fit, module, context):
fit.ship.increaseItemAttr("warpScrambleStatus", module.getModifiedItemAttr("warpScrambleStrength"))
if module.charge is not None and module.charge.ID == 47336:
for mod in fit.modules:
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > State.ONLINE:
mod.state = State.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
mod.state = State.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > FittingModuleState.ONLINE:
mod.state = FittingModuleState.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > FittingModuleState.ONLINE:
mod.state = FittingModuleState.ONLINE

View File

@@ -7,7 +7,7 @@
#
# Used by:
# Modules from group: Warp Disrupt Field Generator (7 of 7)
from eos.saveddata.module import State
from eos.const import FittingModuleState
type = "projected", "active"
runTime = "early"
@@ -19,10 +19,10 @@ def handler(fit, module, context):
fit.ship.increaseItemAttr("warpScrambleStatus", module.getModifiedItemAttr("warpScrambleStrength"))
if module.charge is not None and module.charge.ID == 45010:
for mod in fit.modules:
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > State.ONLINE:
mod.state = State.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
mod.state = State.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("High Speed Maneuvering") and mod.state > FittingModuleState.ONLINE:
mod.state = FittingModuleState.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > FittingModuleState.ONLINE:
mod.state = FittingModuleState.ONLINE
else:
if module.charge is None:
fit.ship.boostItemAttr("mass", module.getModifiedItemAttr("massBonusPercentage"))

View File

@@ -2,7 +2,7 @@
#
# Used by:
# Modules named like: Warp Scrambler (27 of 27)
from eos.saveddata.module import State
from eos.const import FittingModuleState
runTime = "early"
type = "projected", "active"
@@ -16,10 +16,10 @@ def handler(fit, module, context):
# this is such a dirty hack
for mod in fit.modules:
if not mod.isEmpty and mod.state > State.ONLINE and (
if not mod.isEmpty and mod.state > FittingModuleState.ONLINE and (
mod.item.requiresSkill("Micro Jump Drive Operation") or
mod.item.requiresSkill("High Speed Maneuvering")
):
mod.state = State.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > State.ONLINE:
mod.state = State.ONLINE
mod.state = FittingModuleState.ONLINE
if not mod.isEmpty and mod.item.requiresSkill("Micro Jump Drive Operation") and mod.state > FittingModuleState.ONLINE:
mod.state = FittingModuleState.ONLINE

View File

@@ -1,23 +0,0 @@
class Enum(object):
def __init__(self):
pass
@classmethod
def getTypes(cls):
for stuff in cls.__dict__:
if stuff.upper() == stuff:
yield stuff
@classmethod
def getName(cls, v):
map = getattr(cls, "_map", None)
if map is None:
map = cls._map = {}
for type in cls.getTypes():
map[cls.getValue(type)] = type
return map.get(v)
@classmethod
def getValue(cls, type):
return cls.__dict__[type]

View File

@@ -20,7 +20,7 @@
from math import log, sin, radians, exp
from eos.graph import Graph
from eos.saveddata.module import State, Hardpoint
from eos.const import FittingModuleState, FittingHardpoint
from logbook import Logger
pyfalog = Logger(__name__)
@@ -46,7 +46,7 @@ class FitDpsGraph(Graph):
abssort = lambda _val: -abs(_val - 1)
for mod in fit.modules:
if not mod.isEmpty and mod.state >= State.ACTIVE:
if not mod.isEmpty and mod.state >= FittingModuleState.ACTIVE:
if "remoteTargetPaintFalloff" in mod.item.effects or "structureModuleEffectTargetPainter" in mod.item.effects:
ew['signatureRadius'].append(
1 + (mod.getModifiedItemAttr("signatureRadiusBonus") / 100) * self.calculateModuleMultiplier(
@@ -76,12 +76,12 @@ class FitDpsGraph(Graph):
for mod in fit.modules:
dps = mod.getDps(targetResists=fit.targetResists).total
if mod.hardpoint == Hardpoint.TURRET:
if mod.state >= State.ACTIVE:
if mod.hardpoint == FittingHardpoint.TURRET:
if mod.state >= FittingModuleState.ACTIVE:
total += dps * self.calculateTurretMultiplier(mod, data)
elif mod.hardpoint == Hardpoint.MISSILE:
if mod.state >= State.ACTIVE and mod.maxRange is not None and mod.maxRange >= distance:
elif mod.hardpoint == FittingHardpoint.MISSILE:
if mod.state >= FittingModuleState.ACTIVE and mod.maxRange is not None and mod.maxRange >= distance:
total += dps * self.calculateMissileMultiplier(mod, data)
if distance <= fit.extraAttributes["droneControlRange"]:

View File

@@ -25,8 +25,8 @@ import eos.db
from eos.effectHandlerHelpers import HandledItem, HandledCharge
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut, ChargeAttrShortcut
from eos.saveddata.fighterAbility import FighterAbility
from eos.saveddata.module import Slot
from eos.utils.stats import DmgTypes
from eos.const import FittingSlot
pyfalog = Logger(__name__)
@@ -116,12 +116,12 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def __calculateSlot(self, item):
types = {
"Light" : Slot.F_LIGHT,
"Support": Slot.F_SUPPORT,
"Heavy" : Slot.F_HEAVY,
"StandupLight": Slot.FS_LIGHT,
"StandupSupport": Slot.FS_SUPPORT,
"StandupHeavy": Slot.FS_HEAVY
"Light" : FittingSlot.F_LIGHT,
"Support": FittingSlot.F_SUPPORT,
"Heavy" : FittingSlot.F_HEAVY,
"StandupLight": FittingSlot.FS_LIGHT,
"StandupSupport": FittingSlot.FS_SUPPORT,
"StandupHeavy": FittingSlot.FS_HEAVY
}
for t, slot in types.items():

View File

@@ -28,28 +28,19 @@ from sqlalchemy.orm import validates, reconstructor
import eos.db
from eos import capSim
from eos.effectHandlerHelpers import HandledModuleList, HandledDroneCargoList, HandledImplantBoosterList, HandledProjectedDroneList, HandledProjectedModList
from eos.enum import Enum
from eos.const import ImplantLocation, CalcType, FittingSlot
from eos.saveddata.ship import Ship
from eos.saveddata.drone import Drone
from eos.saveddata.character import Character
from eos.saveddata.citadel import Citadel
from eos.saveddata.module import Module, State, Slot, Hardpoint
from eos.const import FittingModuleState, FittingHardpoint
from eos.saveddata.module import Module
from eos.utils.stats import DmgTypes
from logbook import Logger
pyfalog = Logger(__name__)
class ImplantLocation(Enum):
FIT = 0
CHARACTER = 1
class CalcType(Enum):
LOCAL = 0
PROJECTED = 1
COMMAND = 2
class Fit(object):
"""Represents a fitting, with modules, ship, implants, etc."""
@@ -741,7 +732,7 @@ class Fit(object):
The type of calculation our current iteration is in. This helps us determine the interactions between
fits that rely on others for proper calculations
"""
pyfalog.info("Starting fit calculation on: {0}, calc: {1}", repr(self), CalcType.getName(type))
pyfalog.info("Starting fit calculation on: {0}, calc: {1}", repr(self), CalcType(type).name)
# If we are projecting this fit onto another one, collect the projection info for later use
@@ -901,7 +892,7 @@ class Fit(object):
if self.ship is None:
return
for slotType in (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE):
for slotType in (FittingSlot.LOW.value, FittingSlot.MED.value, FittingSlot.HIGH.value, FittingSlot.RIG.value, FittingSlot.SUBSYSTEM.value, FittingSlot.SERVICE.value):
amount = self.getSlotsFree(slotType, True)
if amount > 0:
for _ in range(int(amount)):
@@ -948,7 +939,7 @@ class Fit(object):
def getItemAttrOnlineSum(dict, attr):
amount = 0
for mod in dict:
add = mod.getModifiedItemAttr(attr) if mod.state >= State.ONLINE else None
add = mod.getModifiedItemAttr(attr) if mod.state >= FittingModuleState.ONLINE else None
if add is not None:
amount += add
@@ -967,29 +958,29 @@ class Fit(object):
for mod in chain(self.modules, self.fighters):
if mod.slot is type and (not getattr(mod, "isEmpty", False) or countDummies):
if type in (Slot.F_HEAVY, Slot.F_SUPPORT, Slot.F_LIGHT, Slot.FS_HEAVY, Slot.FS_LIGHT, Slot.FS_SUPPORT) and not mod.active:
if type in (FittingSlot.F_HEAVY, FittingSlot.F_SUPPORT, FittingSlot.F_LIGHT, FittingSlot.FS_HEAVY, FittingSlot.FS_LIGHT, FittingSlot.FS_SUPPORT) and not mod.active:
continue
amount += 1
return amount
slots = {
Slot.LOW : "lowSlots",
Slot.MED : "medSlots",
Slot.HIGH : "hiSlots",
Slot.RIG : "rigSlots",
Slot.SUBSYSTEM: "maxSubSystems",
Slot.SERVICE : "serviceSlots",
Slot.F_LIGHT : "fighterLightSlots",
Slot.F_SUPPORT: "fighterSupportSlots",
Slot.F_HEAVY : "fighterHeavySlots",
Slot.FS_LIGHT: "fighterStandupLightSlots",
Slot.FS_SUPPORT: "fighterStandupSupportSlots",
Slot.FS_HEAVY: "fighterStandupHeavySlots",
FittingSlot.LOW : "lowSlots",
FittingSlot.MED : "medSlots",
FittingSlot.HIGH : "hiSlots",
FittingSlot.RIG : "rigSlots",
FittingSlot.SUBSYSTEM: "maxSubSystems",
FittingSlot.SERVICE : "serviceSlots",
FittingSlot.F_LIGHT : "fighterLightSlots",
FittingSlot.F_SUPPORT: "fighterSupportSlots",
FittingSlot.F_HEAVY : "fighterHeavySlots",
FittingSlot.FS_LIGHT: "fighterStandupLightSlots",
FittingSlot.FS_SUPPORT: "fighterStandupSupportSlots",
FittingSlot.FS_HEAVY: "fighterStandupHeavySlots",
}
def getSlotsFree(self, type, countDummies=False):
if type in (Slot.MODE, Slot.SYSTEM):
if type in (FittingSlot.MODE, FittingSlot.SYSTEM):
# These slots don't really exist, return default 0
return 0
@@ -1001,12 +992,12 @@ class Fit(object):
return self.ship.getModifiedItemAttr(self.slots[type]) or 0
def getHardpointsFree(self, type):
if type == Hardpoint.NONE:
if type == FittingHardpoint.NONE:
return 1
elif type == Hardpoint.TURRET:
return self.ship.getModifiedItemAttr('turretSlotsLeft') - self.getHardpointsUsed(Hardpoint.TURRET)
elif type == Hardpoint.MISSILE:
return self.ship.getModifiedItemAttr('launcherSlotsLeft') - self.getHardpointsUsed(Hardpoint.MISSILE)
elif type == FittingHardpoint.TURRET:
return self.ship.getModifiedItemAttr('turretSlotsLeft') - self.getHardpointsUsed(FittingHardpoint.TURRET)
elif type == FittingHardpoint.MISSILE:
return self.ship.getModifiedItemAttr('launcherSlotsLeft') - self.getHardpointsUsed(FittingHardpoint.MISSILE)
else:
raise ValueError("%d is not a valid value for Hardpoint Enum", type)
@@ -1168,7 +1159,7 @@ class Fit(object):
capUsed = 0
capAdded = 0
for mod in self.modules:
if mod.state >= State.ACTIVE:
if mod.state >= FittingModuleState.ACTIVE:
if (mod.getModifiedItemAttr("capacitorNeed") or 0) != 0:
cycleTime = mod.rawCycleTime or 0
reactivationTime = mod.getModifiedItemAttr("moduleReactivationDelay") or 0
@@ -1182,7 +1173,7 @@ class Fit(object):
capAdded -= capNeed
# If this is a turret, don't stagger activations
disableStagger = mod.hardpoint == Hardpoint.TURRET
disableStagger = mod.hardpoint == FittingHardpoint.TURRET
drains.append((int(fullCycleTime), mod.getModifiedItemAttr("capacitorNeed") or 0,
mod.numShots or 0, disableStagger, reloadTime))

View File

@@ -23,9 +23,8 @@ from logbook import Logger
from sqlalchemy.orm import reconstructor, validates
import eos.db
from eos.const import Slot
from eos.const import FittingModuleState, FittingHardpoint, FittingSlot
from eos.effectHandlerHelpers import HandledCharge, HandledItem
from eos.enum import Enum
from eos.modifiedAttributeDict import ChargeAttrShortcut, ItemAttrShortcut, ModifiedAttributeDict
from eos.saveddata.citadel import Citadel
from eos.saveddata.mutator import Mutator
@@ -35,44 +34,30 @@ from eos.utils.stats import DmgTypes
pyfalog = Logger(__name__)
class State(Enum):
OFFLINE = -1
ONLINE = 0
ACTIVE = 1
OVERHEATED = 2
ProjectedMap = {
State.OVERHEATED: State.ACTIVE,
State.ACTIVE: State.OFFLINE,
State.OFFLINE: State.ACTIVE,
State.ONLINE: State.ACTIVE # Just in case
FittingModuleState.OVERHEATED: FittingModuleState.ACTIVE,
FittingModuleState.ACTIVE: FittingModuleState.OFFLINE,
FittingModuleState.OFFLINE: FittingModuleState.ACTIVE,
FittingModuleState.ONLINE: FittingModuleState.ACTIVE # Just in case
}
# Old state : New State
LocalMap = {
State.OVERHEATED: State.ACTIVE,
State.ACTIVE: State.ONLINE,
State.OFFLINE: State.ONLINE,
State.ONLINE: State.ACTIVE
FittingModuleState.OVERHEATED: FittingModuleState.ACTIVE,
FittingModuleState.ACTIVE: FittingModuleState.ONLINE,
FittingModuleState.OFFLINE: FittingModuleState.ONLINE,
FittingModuleState.ONLINE: FittingModuleState.ACTIVE
}
# For system effects. They should only ever be online or offline
ProjectedSystem = {
State.OFFLINE: State.ONLINE,
State.ONLINE: State.OFFLINE
FittingModuleState.OFFLINE: FittingModuleState.ONLINE,
FittingModuleState.ONLINE: FittingModuleState.OFFLINE
}
class Hardpoint(Enum):
NONE = 0
MISSILE = 1
TURRET = 2
class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
"""An instance of this class represents a module together with its charge and modified attributes"""
MINING_ATTRIBUTES = ("miningAmount",)
@@ -104,7 +89,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
self.__charge = None
self.projected = False
self.state = State.ONLINE
self.state = FittingModuleState.ONLINE
self.build()
@reconstructor
@@ -153,7 +138,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
self.__reloadTime = None
self.__reloadForce = None
self.__chargeCycles = None
self.__hardpoint = Hardpoint.NONE
self.__hardpoint = FittingHardpoint.NONE
self.__itemModifiedAttributes = ModifiedAttributeDict(parent=self)
self.__chargeModifiedAttributes = ModifiedAttributeDict(parent=self)
self.__slot = self.dummySlot # defaults to None
@@ -396,7 +381,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if self.isEmpty:
self.__miningyield = 0
else:
if self.state >= State.ACTIVE:
if self.state >= FittingModuleState.ACTIVE:
volley = self.getModifiedItemAttr("specialtyMiningAmount") or self.getModifiedItemAttr(
"miningAmount") or 0
if volley:
@@ -410,7 +395,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
return self.__miningyield
def getVolley(self, spoolOptions=None, targetResists=None, ignoreState=False):
if self.isEmpty or (self.state < State.ACTIVE and not ignoreState):
if self.isEmpty or (self.state < FittingModuleState.ACTIVE and not ignoreState):
return DmgTypes(0, 0, 0, 0)
if self.__baseVolley is None:
dmgGetter = self.getModifiedChargeAttr if self.charge else self.getModifiedItemAttr
@@ -448,7 +433,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
return dps
def getRemoteReps(self, spoolOptions=None, ignoreState=False):
if self.isEmpty or (self.state < State.ACTIVE and not ignoreState):
if self.isEmpty or (self.state < FittingModuleState.ACTIVE and not ignoreState):
return None, 0
def getBaseRemoteReps(module):
@@ -590,14 +575,14 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
return False
# If the mod is a subsystem, don't let two subs in the same slot fit
if self.slot == Slot.SUBSYSTEM:
if self.slot == FittingSlot.SUBSYSTEM:
subSlot = self.getModifiedItemAttr("subSystemSlot")
for mod in fit.modules:
if mod.getModifiedItemAttr("subSystemSlot") == subSlot:
return False
# Check rig sizes
if self.slot == Slot.RIG:
if self.slot == FittingSlot.RIG:
if self.getModifiedItemAttr("rigSize") != fit.ship.getModifiedItemAttr("rigSize"):
return False
@@ -627,9 +612,9 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
# Check if we're within bounds
if state < -1 or state > 2:
return False
elif state >= State.ACTIVE and not self.item.isType("active"):
elif state >= FittingModuleState.ACTIVE and not self.item.isType("active"):
return False
elif state == State.OVERHEATED and not self.item.isType("overheat"):
elif state == FittingModuleState.OVERHEATED and not self.item.isType("overheat"):
return False
else:
return True
@@ -641,7 +626,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
# If we're going to set module to offline or online for local modules or offline for projected,
# it should be fine for all cases
item = self.item
if (state <= State.ONLINE and projectedOnto is None) or (state <= State.OFFLINE):
if (state <= FittingModuleState.ONLINE and projectedOnto is None) or (state <= FittingModuleState.OFFLINE):
return True
# Check if the local module is over it's max limit; if it's not, we're fine
@@ -655,7 +640,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
group = item.group.name
for mod in self.owner.modules:
currItem = getattr(mod, "item", None)
if mod.state >= State.ACTIVE and currItem is not None and currItem.group.name == group:
if mod.state >= FittingModuleState.ACTIVE and currItem is not None and currItem.group.name == group:
currActive += 1
if currActive > maxGroupActive:
break
@@ -718,28 +703,28 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
@staticmethod
def __calculateHardpoint(item):
effectHardpointMap = {
"turretFitted" : Hardpoint.TURRET,
"launcherFitted": Hardpoint.MISSILE
"turretFitted" : FittingHardpoint.TURRET,
"launcherFitted": FittingHardpoint.MISSILE
}
if item is None:
return Hardpoint.NONE
return FittingHardpoint.NONE
for effectName, slot in effectHardpointMap.items():
if effectName in item.effects:
return slot
return Hardpoint.NONE
return FittingHardpoint.NONE
@staticmethod
def calculateSlot(item):
effectSlotMap = {
"rigSlot" : Slot.RIG,
"loPower" : Slot.LOW,
"medPower" : Slot.MED,
"hiPower" : Slot.HIGH,
"subSystem" : Slot.SUBSYSTEM,
"serviceSlot": Slot.SERVICE
"rigSlot" : FittingSlot.RIG.value,
"loPower" : FittingSlot.LOW.value,
"medPower" : FittingSlot.MED.value,
"hiPower" : FittingSlot.HIGH.value,
"subSystem" : FittingSlot.SUBSYSTEM.value,
"serviceSlot": FittingSlot.SERVICE.value
}
if item is None:
return None
@@ -747,7 +732,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if effectName in item.effects:
return slot
if item.group.name in Module.SYSTEM_GROUPS:
return Slot.SYSTEM
return FittingSlot.SYSTEM
return None
@@ -801,8 +786,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if effect.runTime == runTime and \
effect.activeByDefault and \
(effect.isType("offline") or
(effect.isType("passive") and self.state >= State.ONLINE) or
(effect.isType("active") and self.state >= State.ACTIVE)) and \
(effect.isType("passive") and self.state >= FittingModuleState.ONLINE) or
(effect.isType("active") and self.state >= FittingModuleState.ACTIVE)) and \
(not gang or (gang and effect.isType("gang"))):
chargeContext = ("moduleCharge",)
@@ -815,7 +800,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
effect.handler(fit, self, chargeContext)
if self.item:
if self.state >= State.OVERHEATED:
if self.state >= FittingModuleState.OVERHEATED:
for effect in self.item.effects.values():
if effect.runTime == runTime and \
effect.isType("overheat") \
@@ -828,8 +813,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if effect.runTime == runTime and \
effect.activeByDefault and \
(effect.isType("offline") or
(effect.isType("passive") and self.state >= State.ONLINE) or
(effect.isType("active") and self.state >= State.ACTIVE)) \
(effect.isType("passive") and self.state >= FittingModuleState.ONLINE) or
(effect.isType("active") and self.state >= FittingModuleState.ACTIVE)) \
and ((projected and effect.isType("projected")) or not projected) \
and ((gang and effect.isType("gang")) or not gang):
try:
@@ -904,7 +889,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
@property
def capUse(self):
capNeed = self.getModifiedItemAttr("capacitorNeed")
if capNeed and self.state >= State.ACTIVE:
if capNeed and self.state >= FittingModuleState.ACTIVE:
cycleTime = self.cycleTime
if cycleTime > 0:
capUsed = capNeed / (cycleTime / 1000.0)
@@ -916,10 +901,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def getProposedState(mod, click, proposedState=None):
# todo: instead of passing in module, make this a instanced function.
pyfalog.debug("Get proposed state for module.")
if mod.slot == Slot.SUBSYSTEM or mod.isEmpty:
return State.ONLINE
if mod.slot == FittingSlot.SUBSYSTEM or mod.isEmpty:
return FittingModuleState.ONLINE
if mod.slot == Slot.SYSTEM:
if mod.slot == FittingSlot.SYSTEM:
transitionMap = ProjectedSystem
else:
transitionMap = ProjectedMap if mod.projected else LocalMap
@@ -929,9 +914,9 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if proposedState is not None:
state = proposedState
elif click == "right":
state = State.OVERHEATED
state = FittingModuleState.OVERHEATED
elif click == "ctrl":
state = State.OFFLINE
state = FittingModuleState.OFFLINE
else:
state = transitionMap[currState]
if not mod.isValidState(state):

View File

@@ -25,7 +25,7 @@ from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED
import gui.mainFrame
import gui.display as d
from gui.builtinViewColumns.state import State
from eos.saveddata.module import Slot
from eos.const import FittingSlot
from gui.contextMenu import ContextMenu
from gui.utils.staticHelpers import DragDropHelper
from service.fit import Fit
@@ -93,9 +93,9 @@ class FighterView(wx.Panel):
if fit:
for x in self.labels:
if fit.isStructure:
slot = getattr(Slot, "FS_{}".format(x.upper()))
slot = getattr(FittingSlot, "FS_{}".format(x.upper()))
else:
slot = getattr(Slot, "F_{}".format(x.upper()))
slot = getattr(FittingSlot, "F_{}".format(x.upper()))
used = fit.getSlotsUsed(slot)
total = fit.getNumSlots(slot)
color = wx.Colour(204, 51, 51) if used > total else wx.SystemSettings.GetColour(

View File

@@ -26,7 +26,7 @@ from gui.builtinViewColumns.state import State
from gui.utils.staticHelpers import DragDropHelper
from gui.contextMenu import ContextMenu
import gui.globalEvents as GE
from eos.saveddata.fit import ImplantLocation
from eos.const import ImplantLocation
from service.fit import Fit
from service.market import Market
import gui.fitCommands as cmd

View File

@@ -5,7 +5,7 @@ import wx
import gui.fitCommands as cmd
import gui.mainFrame
from eos.saveddata.module import Hardpoint
from eos.const import FittingHardpoint
from gui.bitmap_loader import BitmapLoader
from gui.contextMenu import ContextMenu
from service.market import Market
@@ -136,7 +136,7 @@ class ModuleAmmoPicker(ContextMenu):
hardpoint = self.module.hardpoint
moduleName = self.module.item.name
# Make sure we do not consider mining turrets as combat turrets
if hardpoint == Hardpoint.TURRET and self.module.getModifiedItemAttr("miningAmount", None) is None:
if hardpoint == FittingHardpoint.TURRET and self.module.getModifiedItemAttr("miningAmount", None) is None:
self.addSeperator(m, "Long Range")
items = []
range_ = None
@@ -180,7 +180,7 @@ class ModuleAmmoPicker(ContextMenu):
m.Append(item)
self.addSeperator(m, "Short Range")
elif hardpoint == Hardpoint.MISSILE and moduleName != 'Festival Launcher':
elif hardpoint == FittingHardpoint.MISSILE and moduleName != 'Festival Launcher':
self.charges.sort(key=self.missileSorter)
type_ = None
sub = None

View File

@@ -1,22 +1,4 @@
from enum import Enum, auto
# Define the various groups of attributes
class AttrGroup(Enum):
FITTING = auto()
STRUCTURE = auto()
SHIELD = auto()
ARMOR = auto()
TARGETING = auto()
EWAR_RESISTS = auto()
CAPACITOR = auto()
SHARED_FACILITIES = auto()
FIGHTER_FACILITIES = auto()
ON_DEATH = auto()
JUMP_SYSTEMS = auto()
PROPULSIONS = auto()
FIGHTERS = auto()
from service.const import GuiAttrGroup
RequiredSkillAttrs = sum((["requiredSkill{}".format(x), "requiredSkill{}Level".format(x)] for x in range(1, 7)), [])
@@ -45,7 +27,7 @@ for x in AttrGroups:
# Start defining all the known attribute groups
AttrGroupDict = {
AttrGroup.FITTING : {
GuiAttrGroup.FITTING : {
"label" : "Fitting",
"attributes": [
# parent-level attributes
@@ -67,7 +49,7 @@ AttrGroupDict = {
# "mass",
]
},
AttrGroup.STRUCTURE : {
GuiAttrGroup.STRUCTURE : {
"label" : "Structure",
"attributes": [
"hp",
@@ -97,7 +79,7 @@ AttrGroupDict = {
"explosiveDamageResonance"
]
},
AttrGroup.ARMOR : {
GuiAttrGroup.ARMOR : {
"label": "Armor",
"attributes":[
"armorHP",
@@ -109,7 +91,7 @@ AttrGroupDict = {
]
},
AttrGroup.SHIELD : {
GuiAttrGroup.SHIELD : {
"label": "Shield",
"attributes": [
"shieldCapacity",
@@ -122,7 +104,7 @@ AttrGroupDict = {
]
},
AttrGroup.EWAR_RESISTS : {
GuiAttrGroup.EWAR_RESISTS : {
"label": "Electronic Warfare",
"attributes": [
"ECMResistance",
@@ -135,14 +117,14 @@ AttrGroupDict = {
"weaponDisruptionResistance",
]
},
AttrGroup.CAPACITOR : {
GuiAttrGroup.CAPACITOR : {
"label": "Capacitor",
"attributes": [
"capacitorCapacity",
"rechargeRate",
]
},
AttrGroup.TARGETING : {
GuiAttrGroup.TARGETING : {
"label": "Targeting",
"attributes": [
"maxTargetRange",
@@ -160,7 +142,7 @@ AttrGroupDict = {
"scanLadarStrength",
]
},
AttrGroup.SHARED_FACILITIES : {
GuiAttrGroup.SHARED_FACILITIES : {
"label" : "Shared Facilities",
"attributes": [
"fleetHangarCapacity",
@@ -168,7 +150,7 @@ AttrGroupDict = {
"maxJumpClones",
]
},
AttrGroup.FIGHTER_FACILITIES: {
GuiAttrGroup.FIGHTER_FACILITIES: {
"label": "Fighter Squadron Facilities",
"attributes": [
"fighterCapacity",
@@ -181,7 +163,7 @@ AttrGroupDict = {
"fighterStandupHeavySlots",
]
},
AttrGroup.ON_DEATH : {
GuiAttrGroup.ON_DEATH : {
"label": "On Death",
"attributes": [
"onDeathDamageEM",
@@ -192,7 +174,7 @@ AttrGroupDict = {
"onDeathSignatureRadius",
]
},
AttrGroup.JUMP_SYSTEMS : {
GuiAttrGroup.JUMP_SYSTEMS : {
"label": "Jump Drive Systems",
"attributes": [
"jumpDriveCapacitorNeed",
@@ -206,13 +188,13 @@ AttrGroupDict = {
"jumpPortalDuration",
]
},
AttrGroup.PROPULSIONS : {
GuiAttrGroup.PROPULSIONS : {
"label": "Propulsion",
"attributes": [
"maxVelocity"
]
},
AttrGroup.FIGHTERS : {
GuiAttrGroup.FIGHTERS : {
"label": "Fighter",
"attributes": [
"mass",
@@ -228,25 +210,25 @@ AttrGroupDict = {
}
Group1 = [
AttrGroup.FITTING,
AttrGroup.STRUCTURE,
AttrGroup.ARMOR,
AttrGroup.SHIELD,
AttrGroup.EWAR_RESISTS,
AttrGroup.CAPACITOR,
AttrGroup.TARGETING,
AttrGroup.SHARED_FACILITIES,
AttrGroup.FIGHTER_FACILITIES,
AttrGroup.ON_DEATH,
AttrGroup.JUMP_SYSTEMS,
AttrGroup.PROPULSIONS,
GuiAttrGroup.FITTING,
GuiAttrGroup.STRUCTURE,
GuiAttrGroup.ARMOR,
GuiAttrGroup.SHIELD,
GuiAttrGroup.EWAR_RESISTS,
GuiAttrGroup.CAPACITOR,
GuiAttrGroup.TARGETING,
GuiAttrGroup.SHARED_FACILITIES,
GuiAttrGroup.FIGHTER_FACILITIES,
GuiAttrGroup.ON_DEATH,
GuiAttrGroup.JUMP_SYSTEMS,
GuiAttrGroup.PROPULSIONS,
]
CategoryGroups = {
"Fighter" : [
AttrGroup.FIGHTERS,
AttrGroup.SHIELD,
AttrGroup.TARGETING,
GuiAttrGroup.FIGHTERS,
GuiAttrGroup.SHIELD,
GuiAttrGroup.TARGETING,
],
"Ship" : Group1,
"Drone" : Group1,

View File

@@ -4,12 +4,12 @@ import config
# noinspection PyPackageRequirements
import wx
import wx.lib.agw.hypertreelist
from gui.builtinItemStatsViews.helpers import AutoListCtrl
from gui.bitmap_loader import BitmapLoader
from gui.utils.numberFormatter import formatAmount, roundDec
from enum import IntEnum
from gui.builtinItemStatsViews.attributeGrouping import *
from service.const import GuiAttrGroup
class AttributeView(IntEnum):
@@ -19,7 +19,8 @@ class AttributeView(IntEnum):
class ItemParams(wx.Panel):
def __init__(self, parent, stuff, item, context=None):
wx.Panel.__init__(self, parent)
# Had to manually set the size here, otherwise column widths couldn't be calculated correctly. See #1878
wx.Panel.__init__(self, parent, size=(1000, 1000))
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.paramList = wx.lib.agw.hypertreelist.HyperTreeList(self, wx.ID_ANY, agwStyle=wx.TR_HIDE_ROOT | wx.TR_NO_LINES | wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_HAS_BUTTONS)
@@ -28,7 +29,7 @@ class ItemParams(wx.Panel):
mainSizer.Add(self.paramList, 1, wx.ALL | wx.EXPAND, 0)
self.SetSizer(mainSizer)
self.toggleView = 1
self.toggleView = AttributeView.NORMAL
self.stuff = stuff
self.item = item
self.attrInfo = {}
@@ -40,9 +41,6 @@ class ItemParams(wx.Panel):
if self.stuff is not None:
self.paramList.AddColumn("Base Value")
self.paramList.SetMainColumn(0) # the one with the tree in it...
self.paramList.SetColumnWidth(0, 300)
self.m_staticline = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
mainSizer.Add(self.m_staticline, 0, wx.EXPAND)
bSizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -62,6 +60,8 @@ class ItemParams(wx.Panel):
mainSizer.Add(bSizer, 0, wx.ALIGN_RIGHT)
self.imageList = wx.ImageList(16, 16)
self.PopulateList()
self.toggleViewBtn.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleViewMode)
@@ -164,6 +164,14 @@ class ItemParams(wx.Panel):
]
)
def SetupImageList(self):
self.imageList.RemoveAll()
self.blank_icon = self.imageList.Add(BitmapLoader.getBitmap("transparent16x16", "gui"))
self.unknown_icon = self.imageList.Add(BitmapLoader.getBitmap("0", "icons"))
self.paramList.AssignImageList(self.imageList)
def AddAttribute(self, parent, attr):
if attr in self.attrValues and attr not in self.processed_attribs:
@@ -188,14 +196,14 @@ class ItemParams(wx.Panel):
def PopulateList(self):
# self.paramList.setResizeColumn(0)
self.imageList = wx.ImageList(16, 16)
self.SetupImageList()
self.processed_attribs = set()
root = self.paramList.AddRoot("The Root Item")
misc_parent = root
# We must first deet4ermine if it's categorey already has defined groupings set for it. Otherwise, we default to just using the fitting group
order = CategoryGroups.get(self.item.category.categoryName, [AttrGroup.FITTING])
order = CategoryGroups.get(self.item.category.categoryName, [GuiAttrGroup.FITTING])
# start building out the tree
for data in [AttrGroupDict[o] for o in order]:
heading = data.get("label")
@@ -243,9 +251,11 @@ class ItemParams(wx.Panel):
self.AddAttribute(root, name)
self.paramList.AssignImageList(self.imageList)
self.Layout()
for i in range(self.paramList.GetMainWindow().GetColumnCount()):
self.paramList.SetColumnWidth(i, wx.LIST_AUTOSIZE)
def GetData(self, attr):
info = self.attrInfo.get(attr)
att = self.attrValues[attr]
@@ -264,7 +274,7 @@ class ItemParams(wx.Panel):
if self.toggleView == AttributeView.NORMAL and ((attr not in GroupedAttributes and not value) or info is None or not info.published or attr in RequiredSkillAttrs):
return None
if info and info.displayName and self.toggleView == 1:
if info and info.displayName and self.toggleView == AttributeView.NORMAL:
attrName = info.displayName
else:
attrName = attr
@@ -278,27 +288,27 @@ class ItemParams(wx.Panel):
icon = BitmapLoader.getBitmap(iconFile, "icons")
if icon is None:
icon = BitmapLoader.getBitmap("transparent16x16", "gui")
attrIcon = self.imageList.Add(icon)
attrIcon = self.blank_icon
else:
attrIcon = self.imageList.Add(icon)
else:
attrIcon = self.imageList.Add(BitmapLoader.getBitmap("0", "icons"))
attrIcon = self.unknown_icon
else:
attrIcon = self.imageList.Add(BitmapLoader.getBitmap("0", "icons"))
attrIcon = self.unknown_icon
# index = self.paramList.AppendItem(root, attrName)
# idNameMap[idCount] = attrName
# self.paramList.SetPyData(index, idCount)
# idCount += 1
if self.toggleView != 1:
if self.toggleView == AttributeView.RAW:
valueUnit = str(value)
elif info and info.unit:
valueUnit = self.FormatValue(*info.unit.PreformatValue(value))
else:
valueUnit = formatAmount(value, 3, 0, 0)
if self.toggleView != 1:
if self.toggleView == AttributeView.RAW:
valueUnitDefault = str(valueDefault)
elif info and info.unit:
valueUnitDefault = self.FormatValue(*info.unit.PreformatValue(valueDefault))
@@ -346,6 +356,7 @@ if __name__ == "__main__":
#item = eos.db.getItem(526) # Stasis Webifier I
item = eos.db.getItem(486) # 200mm AutoCannon I
#item = eos.db.getItem(200) # Phased Plasma L
super().__init__(None, title="Test Attribute Window | {} - {}".format(item.ID, item.name), size=(1000, 500))
if 'wxMSW' in wx.PlatformInfo:
@@ -359,6 +370,7 @@ if __name__ == "__main__":
main_sizer.Add(panel, 1, wx.EXPAND | wx.ALL, 2)
self.SetSizer(main_sizer)
self.Layout()
app = wx.App(redirect=False) # Error messages go to popup window
top = Frame()

View File

@@ -43,8 +43,12 @@ class ItemMutator(wx.Panel):
self.badColor = wx.Colour(255, 64, 0)
self.event_mapping = {}
higOverrides = {
('Stasis Web', 'speedFactor'): False,
}
for m in sorted(stuff.mutators.values(), key=lambda x: x.attribute.displayName):
highIsGood = higOverrides.get((stuff.item.group.name, m.attribute.name), m.highIsGood)
# Format: [raw value, modifier applied to base raw value, display value]
range1 = (m.minValue, m.attribute.unit.SimplifyValue(m.minValue))
range2 = (m.maxValue, m.attribute.unit.SimplifyValue(m.maxValue))
@@ -59,7 +63,7 @@ class ItemMutator(wx.Panel):
minRange = range2
maxRange = range1
if (m.highIsGood and minRange[0] >= maxRange[0]) or (not m.highIsGood and minRange[0] <= maxRange[0]):
if (highIsGood and minRange[0] >= maxRange[0]) or (not highIsGood and minRange[0] <= maxRange[0]):
betterRange = minRange
worseRange = maxRange
else:

View File

@@ -26,7 +26,7 @@ import gui.mainFrame
from gui.chrome_tabs import EVT_NOTEBOOK_PAGE_CHANGED
from gui.utils import fonts
from eos.saveddata.module import Hardpoint
from eos.const import FittingHardpoint
from gui.utils.numberFormatter import formatAmount
@@ -196,9 +196,9 @@ class ResourcesViewFull(StatsView):
# If we did anything intresting, we'd update our labels to reflect the new fit's stats here
stats = (
("label%sUsedTurretHardpoints", lambda: fit.getHardpointsUsed(Hardpoint.TURRET), 0, 0, 0),
("label%sUsedTurretHardpoints", lambda: fit.getHardpointsUsed(FittingHardpoint.TURRET), 0, 0, 0),
("label%sTotalTurretHardpoints", lambda: fit.ship.getModifiedItemAttr('turretSlotsLeft'), 0, 0, 0),
("label%sUsedLauncherHardpoints", lambda: fit.getHardpointsUsed(Hardpoint.MISSILE), 0, 0, 0),
("label%sUsedLauncherHardpoints", lambda: fit.getHardpointsUsed(FittingHardpoint.MISSILE), 0, 0, 0),
("label%sTotalLauncherHardpoints", lambda: fit.ship.getModifiedItemAttr('launcherSlotsLeft'), 0, 0, 0),
("label%sUsedDronesActive", lambda: fit.activeDrones, 0, 0, 0),
("label%sTotalDronesActive", lambda: fit.extraAttributes["maxActiveDrones"], 0, 0, 0),
@@ -278,12 +278,16 @@ class ResourcesViewFull(StatsView):
totalCalibrationPoints = value
labelTCP = label
# See #1877
shown = label.Shown
label.Show(True)
if isinstance(value, str):
label.SetLabel(value)
label.SetToolTip(wx.ToolTip(value))
else:
label.SetLabel(formatAmount(value, prec, lowest, highest))
label.SetToolTip(wx.ToolTip("%.1f" % value))
label.Show(shown)
colorWarn = wx.Colour(204, 51, 51)
colorNormal = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)

View File

@@ -2,8 +2,9 @@
import wx
from eos.saveddata.implant import Implant
from eos.saveddata.drone import Drone
from eos.saveddata.module import Module, Slot, Rack
from eos.saveddata.module import Module, Rack
from eos.saveddata.fit import Fit
from eos.const import FittingSlot
from gui.viewColumn import ViewColumn
@@ -32,7 +33,7 @@ class BaseIcon(ViewColumn):
return self.shipImage
elif isinstance(stuff, Module):
if stuff.isEmpty:
return self.fittingView.imageList.GetImageIndex("slot_%s_small" % Slot.getName(stuff.slot).lower(),
return self.fittingView.imageList.GetImageIndex("slot_%s_small" % FittingSlot(stuff.slot).name.lower(),
"gui")
else:
return self.loadIconFile(stuff.item.iconID or "")

View File

@@ -25,8 +25,9 @@ from eos.saveddata.cargo import Cargo
from eos.saveddata.implant import Implant
from eos.saveddata.drone import Drone
from eos.saveddata.fighter import Fighter
from eos.saveddata.module import Module, Slot, Rack
from eos.saveddata.module import Module, Rack
from eos.saveddata.fit import Fit
from eos.const import FittingSlot
from service.fit import Fit as FitSvc
from service.market import Market
from gui.viewColumn import ViewColumn
@@ -72,10 +73,10 @@ class BaseName(ViewColumn):
return "%s (%s)" % (stuff.name, stuff.ship.item.name)
elif isinstance(stuff, Rack):
if FitSvc.getInstance().serviceFittingOptions["rackLabels"]:
if stuff.slot == Slot.MODE:
if stuff.slot == FittingSlot.MODE:
return '─ Tactical Mode ─'
else:
return '{} {} Slot{}'.format(stuff.num, Slot.getName(stuff.slot).capitalize(), '' if stuff.num == 1 else 's')
return '{} {} Slot{}'.format(stuff.num, FittingSlot(stuff.slot).name.capitalize(), '' if stuff.num == 1 else 's')
else:
return ""
elif isinstance(stuff, Module):
@@ -89,7 +90,7 @@ class BaseName(ViewColumn):
return "{} {}".format(type.name, stuff.item.name[-1:])
if stuff.isEmpty:
return "%s Slot" % Slot.getName(stuff.slot).capitalize()
return "%s Slot" % FittingSlot(stuff.slot).name.capitalize()
else:
return stuff.item.name
elif isinstance(stuff, Implant):

View File

@@ -24,7 +24,8 @@ import wx
from eos.saveddata.fit import Fit
from eos.saveddata.implant import Implant
from eos.saveddata.drone import Drone
from eos.saveddata.module import Module, State as State_, Rack
from eos.saveddata.module import Module, Rack
from eos.const import FittingModuleState as State_
from gui.viewColumn import ViewColumn
import gui.mainFrame
@@ -46,12 +47,11 @@ class State(ViewColumn):
def getToolTip(self, mod):
if isinstance(mod, Module) and not mod.isEmpty:
return State_.getName(mod.state).title()
return State_(mod.state).name.title()
def getImageId(self, stuff):
generic_active = self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(1).lower(), "gui")
generic_inactive = self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(-1).lower(),
"gui")
generic_active = self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.ACTIVE.name.lower(), "gui")
generic_inactive = self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.OFFLINE.name.lower(), "gui")
if isinstance(stuff, Drone):
if stuff.amountActive > 0:
@@ -64,7 +64,7 @@ class State(ViewColumn):
if stuff.isEmpty:
return -1
else:
return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(stuff.state).lower(),
return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_(stuff.state).name.lower(),
"gui")
elif isinstance(stuff, Fit):
fitID = self.mainFrame.getActiveFit()
@@ -83,7 +83,7 @@ class State(ViewColumn):
return generic_inactive
elif isinstance(stuff, Implant) and stuff.character:
# if we're showing character implants, show an "online" state, which should not be changed
return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(0).lower(), "gui")
return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.ONLINE.name.lower(), "gui")
else:
active = getattr(stuff, "active", None)
if active is None:

View File

@@ -30,7 +30,8 @@ import gui.globalEvents as GE
import gui.mainFrame
import gui.multiSwitch
from eos.saveddata.mode import Mode
from eos.saveddata.module import Module, Rack, Slot
from eos.saveddata.module import Module, Rack
from eos.const import FittingSlot
from gui.bitmap_loader import BitmapLoader
from gui.builtinMarketBrowser.events import ITEM_SELECTED
from gui.builtinShipBrowser.events import EVT_FIT_REMOVED, EVT_FIT_RENAMED, EVT_FIT_SELECTED, FitSelected
@@ -474,7 +475,14 @@ class FittingView(d.Display):
sFit = Fit.getInstance()
fit = sFit.getFit(self.activeFitID)
slotOrder = [Slot.SUBSYSTEM, Slot.HIGH, Slot.MED, Slot.LOW, Slot.RIG, Slot.SERVICE]
slotOrder = [
FittingSlot.SUBSYSTEM,
FittingSlot.HIGH,
FittingSlot.MED,
FittingSlot.LOW,
FittingSlot.RIG,
FittingSlot.SERVICE
]
if fit is not None:
self.mods = fit.modules[:]
@@ -507,7 +515,7 @@ class FittingView(d.Display):
# while also marking the mode header position in the Blanks list
if sFit.serviceFittingOptions["rackSlots"]:
self.blanks.append(len(self.mods))
self.mods.append(Rack.buildRack(Slot.MODE, None))
self.mods.append(Rack.buildRack(FittingSlot.MODE, None))
self.mods.append(fit.mode)
else:
@@ -648,8 +656,7 @@ class FittingView(d.Display):
slotMap = {}
# test for too many modules (happens with t3s / CCP change in slot layout)
for slotType in Slot.getTypes():
slot = Slot.getValue(slotType)
for slot in [e.value for e in FittingSlot]:
slotMap[slot] = fit.getSlotsFree(slot) < 0
for i, mod in enumerate(self.mods):
@@ -735,8 +742,8 @@ class FittingView(d.Display):
return
slotMap = {}
for slotType in Slot.getTypes():
slot = Slot.getValue(slotType)
for slot in [e.value for e in FittingSlot]:
slotMap[slot] = fit.getSlotsFree(slot) < 0
padding = 2

View File

@@ -150,7 +150,7 @@ class CharacterEntityEditor(EntityEditor):
class CharacterEditor(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="pyfa: Character Editor", pos=wx.DefaultPosition,
size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER | wx.FRAME_FLOAT_ON_PARENT)
i = wx.Icon(BitmapLoader.getBitmap("character_small", "gui"))
self.SetIcon(i)
@@ -353,7 +353,7 @@ class SkillTreeView(wx.Panel):
self.skillBookDirtyImageId = self.imageList.Add(wx.Icon(BitmapLoader.getBitmap("skill_small_red", "gui")))
tree.AppendColumn("Skill")
tree.AppendColumn("Level")
tree.AppendColumn("Level", align=wx.ALIGN_RIGHT)
# tree.SetMainColumn(0)
self.root = tree.GetRootItem()
@@ -427,7 +427,8 @@ class SkillTreeView(wx.Panel):
self.levelChangeMenu.Bind(wx.EVT_MENU, self.changeLevel)
self.SetSizer(pmainSizer)
self.Layout()
# This cuases issues with GTK, see #1866
# self.Layout()
def importSkills(self, evt):

View File

@@ -1,5 +1,6 @@
import wx
from eos.saveddata.module import Module, State
from eos.saveddata.module import Module
from eos.const import FittingModuleState
import eos.db
from logbook import Logger
from service.fit import Fit
@@ -52,8 +53,8 @@ class FitAddModuleCommand(wx.Command):
self.module.owner = fit
numSlots = len(fit.modules)
fit.modules.append(self.module)
if self.module.isValidState(State.ACTIVE):
self.module.state = State.ACTIVE
if self.module.isValidState(FittingModuleState.ACTIVE):
self.module.state = FittingModuleState.ACTIVE
# todo: fix these
# As some items may affect state-limiting attributes of the ship, calculate new attributes first

View File

@@ -1,5 +1,6 @@
import wx
from eos.saveddata.module import Module, State
from eos.saveddata.module import Module
from eos.const import FittingModuleState
import eos.db
from logbook import Logger
pyfalog = Logger(__name__)
@@ -28,7 +29,7 @@ class FitAddProjectedEnvCommand(wx.Command):
# todo: thing to check for existing environmental effects
module.state = State.ONLINE
module.state = FittingModuleState.ONLINE
if module.isExclusiveSystemEffect:
# if this is an exclusive system effect, we need to cache the old one. We make room for the new one here, which returns the old one
self.old_item = fit.projectedModules.makeRoom(module)

View File

@@ -1,7 +1,8 @@
import wx
import eos.db
from logbook import Logger
from eos.saveddata.module import Module, State
from eos.saveddata.module import Module
from eos.const import FittingModuleState
pyfalog = Logger(__name__)
@@ -27,9 +28,9 @@ class FitAddProjectedModuleCommand(wx.Command):
except ValueError:
return False
module.state = State.ACTIVE
module.state = FittingModuleState.ACTIVE
if not module.canHaveState(module.state, fit):
module.state = State.OFFLINE
module.state = FittingModuleState.OFFLINE
fit.projectedModules.append(module)
eos.db.commit()

View File

@@ -1,5 +1,6 @@
import wx
from eos.saveddata.module import Module, State
from eos.saveddata.module import Module
from eos.const import FittingModuleState
import eos.db
from eos.db.gamedata.queries import getDynamicItem
from logbook import Logger
@@ -62,8 +63,8 @@ class FitImportMutatedCommand(wx.Command):
module.owner = fit
numSlots = len(fit.modules)
fit.modules.append(module)
if module.isValidState(State.ACTIVE):
module.state = State.ACTIVE
if module.isValidState(FittingModuleState.ACTIVE):
module.state = FittingModuleState.ACTIVE
# todo: fix these
# As some items may affect state-limiting attributes of the ship, calculate new attributes first

View File

@@ -2,7 +2,8 @@ import wx
from logbook import Logger
import eos.db
from eos.saveddata.module import Module, State
from eos.saveddata.module import Module
from eos.const import FittingModuleState
from gui.fitCommands.helpers import ModuleInfoCache
pyfalog = Logger(__name__)
@@ -75,8 +76,8 @@ class FitReplaceModuleCommand(wx.Command):
if self.module.fits(fit):
self.module.owner = fit
fit.modules.toModule(self.position, self.module)
if self.module.isValidState(State.ACTIVE):
self.module.state = State.ACTIVE
if self.module.isValidState(FittingModuleState.ACTIVE):
self.module.state = FittingModuleState.ACTIVE
if self.old_module and self.old_module.charge and self.module.isValidCharge(self.old_module.charge):
self.module.charge = self.old_module.charge

View File

@@ -3,7 +3,7 @@ from service.fit import Fit
import gui.mainFrame
from gui import globalEvents as GE
from eos.saveddata.fit import ImplantLocation
from eos.const import ImplantLocation
from .calc.fitAddImplant import FitAddImplantCommand
from .calc.fitChangeImplantLocation import FitChangeImplantLocation

View File

@@ -164,11 +164,12 @@ class ShipBrowser(wx.Panel):
self.categoryList = list(sMkt.getShipRoot())
self.categoryList.sort(key=lambda _ship: _ship.name)
counts = sFit.countAllFitsGroupedByShip()
# set map & cache of fittings per category
for cat in self.categoryList:
itemIDs = [x.ID for x in cat.items]
num = sFit.countFitsWithShip(itemIDs)
self.categoryFitCache[cat.ID] = num > 0
self.categoryFitCache[cat.ID] = sum([count for shipID, count in counts if shipID in itemIDs]) > 0
for ship in self.categoryList:
if self.filterShipsWithNoFits and not self.categoryFitCache[ship.ID]:

View File

@@ -37,7 +37,8 @@ from service.esi import Esi
from eos.saveddata.implant import Implant as es_Implant
from eos.saveddata.character import Character as es_Character, Skill
from eos.saveddata.module import Slot as es_Slot, Module as es_Module
from eos.saveddata.module import Module as es_Module
from eos.const import FittingSlot as es_Slot
from eos.saveddata.fighter import Fighter as es_Fighter
pyfalog = Logger(__name__)

102
service/const.py Normal file
View File

@@ -0,0 +1,102 @@
# =============================================================================
# Copyright (C) 2019 Ryan Holmes
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
from enum import Enum, IntEnum, unique, auto
@unique
class EsiLoginMethod(IntEnum):
"""
Contains the method of ESI login
"""
SERVER = 0
MANUAL = 1
@unique
class EsiSsoMode(IntEnum):
"""
Contains the mode of ESI sso mode
"""
AUTO = 0
CUSTOM = 1
class EsiEndpoints(Enum):
"""
Contains the endpoint paths for the ESI access
"""
CHAR = "/v4/characters/{character_id}/"
CHAR_SKILLS = "/v4/characters/{character_id}/skills/"
CHAR_FITTINGS = "/v1/characters/{character_id}/fittings/"
CHAR_DEL_FIT = "/v1/characters/{character_id}/fittings/{fitting_id}/"
@unique
class PortMultiBuyOptions(IntEnum):
"""
Contains different types of items for multibuy export
"""
IMPLANTS = 1
CARGO = 2
LOADED_CHARGES = 3
@unique
class PortEftOptions(IntEnum):
"""
Contains different options for eft-export
"""
IMPLANTS = 1
MUTATIONS = 2
LOADED_CHARGES = 3
@unique
class PortEftRigSize(IntEnum):
"""
Contains different sizes of ship rigs
This enum is not actively used, but maybe useful someday.
"""
SMALL = 1
MEDIUM = 2
LARGE = 3
CAPITAL = 4
@unique
class GuiAttrGroup(IntEnum):
"""
Define the various groups of attributes.
This enum is used for GUI functions and getting redefined in
/gui/builtinItemStatsViews/attributeGrouping.py
"""
FITTING = auto()
STRUCTURE = auto()
SHIELD = auto()
ARMOR = auto()
TARGETING = auto()
EWAR_RESISTS = auto()
CAPACITOR = auto()
SHARED_FACILITIES = auto()
FIGHTER_FACILITIES = auto()
ON_DEATH = auto()
JUMP_SYSTEMS = auto()
PROPULSIONS = auto()
FIGHTERS = auto()

View File

@@ -9,9 +9,9 @@ import config
import webbrowser
import eos.db
from eos.enum import Enum
from service.const import EsiLoginMethod, EsiSsoMode
from eos.saveddata.ssocharacter import SsoCharacter
from service.esiAccess import APIException, SsoMode
from service.esiAccess import APIException
import gui.globalEvents as GE
from gui.ssoLogin import SsoLogin, SsoLoginServer
from service.server import StoppableHTTPServer, AuthHandler
@@ -24,11 +24,6 @@ from requests import Session
pyfalog = Logger(__name__)
class LoginMethod(Enum):
SERVER = 0
MANUAL = 1
class Esi(EsiAccess):
_instance = None
@@ -107,8 +102,8 @@ class Esi(EsiAccess):
def login(self):
# always start the local server if user is using client details. Otherwise, start only if they choose to do so.
if self.settings.get('ssoMode') == SsoMode.CUSTOM or self.settings.get('loginMode') == LoginMethod.SERVER:
dlg = gui.ssoLogin.SsoLoginServer(6461 if self.settings.get('ssoMode') == SsoMode.CUSTOM else 0)
if self.settings.get('ssoMode') == EsiSsoMode.CUSTOM or self.settings.get('loginMode') == EsiLoginMethod.SERVER:
dlg = gui.ssoLogin.SsoLoginServer(6461 if self.settings.get('ssoMode') == EsiSsoMode.CUSTOM else 0)
dlg.ShowModal()
else:
dlg = gui.ssoLogin.SsoLogin()
@@ -142,7 +137,7 @@ class Esi(EsiAccess):
def handleLogin(self, message):
# we already have authenticated stuff for the auto mode
if self.settings.get('ssoMode') == SsoMode.AUTO:
if self.settings.get('ssoMode') == EsiSsoMode.AUTO:
ssoInfo = message['SSOInfo'][0]
auth_response = json.loads(base64.b64decode(ssoInfo))
else:

View File

@@ -17,7 +17,7 @@ import config
import base64
import datetime
from eos.enum import Enum
from service.const import EsiSsoMode, EsiEndpoints
from service.settings import EsiSettings, NetworkSettings
from requests import Session
@@ -42,11 +42,6 @@ scopes = [
]
class SsoMode(Enum):
AUTO = 0
CUSTOM = 1
class APIException(Exception):
""" Exception for SSO related errors """
@@ -66,13 +61,6 @@ class APIException(Exception):
return 'HTTP Error %s' % self.status_code
class ESIEndpoints(Enum):
CHAR = "/v4/characters/{character_id}/"
CHAR_SKILLS = "/v4/characters/{character_id}/skills/"
CHAR_FITTINGS = "/v1/characters/{character_id}/fittings/"
CHAR_DEL_FIT = "/v1/characters/{character_id}/fittings/{fitting_id}/"
class EsiAccess(object):
def __init__(self):
self.settings = EsiSettings.getInstance()
@@ -89,7 +77,7 @@ class EsiAccess(object):
@property
def sso_url(self):
if self.settings.get("ssoMode") == SsoMode.CUSTOM:
if self.settings.get("ssoMode") == EsiSsoMode.CUSTOM:
return "https://login.eveonline.com"
return "https://www.pyfa.io"
@@ -110,20 +98,20 @@ class EsiAccess(object):
return '%s/oauth/token' % self.sso_url
def getSkills(self, char):
return self.get(char, ESIEndpoints.CHAR_SKILLS, character_id=char.characterID)
return self.get(char, EsiEndpoints.CHAR_SKILLS, character_id=char.characterID)
def getSecStatus(self, char):
return self.get(char, ESIEndpoints.CHAR, character_id=char.characterID)
return self.get(char, EsiEndpoints.CHAR, character_id=char.characterID)
def getFittings(self, char):
return self.get(char, ESIEndpoints.CHAR_FITTINGS, character_id=char.characterID)
return self.get(char, EsiEndpoints.CHAR_FITTINGS, character_id=char.characterID)
def postFitting(self, char, json_str):
# @todo: new fitting ID can be recovered from resp.data,
return self.post(char, ESIEndpoints.CHAR_FITTINGS, json_str, character_id=char.characterID)
return self.post(char, EsiEndpoints.CHAR_FITTINGS, json_str, character_id=char.characterID)
def delFitting(self, char, fittingID):
return self.delete(char, ESIEndpoints.CHAR_DEL_FIT, character_id=char.characterID, fitting_id=fittingID)
return self.delete(char, EsiEndpoints.CHAR_DEL_FIT, character_id=char.characterID, fitting_id=fittingID)
@staticmethod
def update_token(char, tokenResponse):
@@ -136,7 +124,7 @@ class EsiAccess(object):
def getLoginURI(self, redirect=None):
self.state = str(uuid.uuid4())
if self.settings.get("ssoMode") == SsoMode.AUTO:
if self.settings.get("ssoMode") == EsiSsoMode.AUTO:
args = {
'state': self.state,
'pyfa_version': config.version,
@@ -183,7 +171,7 @@ class EsiAccess(object):
'refresh_token': refreshToken,
}
if self.settings.get('ssoMode') == SsoMode.AUTO:
if self.settings.get('ssoMode') == EsiSsoMode.AUTO:
# data is all we really need, the rest is handled automatically by pyfa.io
return {
'data': data,

View File

@@ -30,8 +30,9 @@ from eos.saveddata.citadel import Citadel as es_Citadel
from eos.saveddata.damagePattern import DamagePattern as es_DamagePattern
from eos.saveddata.drone import Drone as es_Drone
from eos.saveddata.fighter import Fighter as es_Fighter
from eos.saveddata.fit import Fit as FitType, ImplantLocation
from eos.saveddata.module import Module as es_Module, State
from eos.const import ImplantLocation, FittingModuleState
from eos.saveddata.fit import Fit as FitType
from eos.saveddata.module import Module as es_Module
from eos.saveddata.ship import Ship as es_Ship
from service.character import Character
from service.damagePattern import DamagePattern
@@ -146,6 +147,11 @@ class Fit(FitDeprecated):
pyfalog.debug("Getting count of all fits.")
return eos.db.countAllFits()
@staticmethod
def countAllFitsGroupedByShip():
count = eos.db.countFitGroupedByShip()
return count
@staticmethod
def countFitsWithShip(stuff):
pyfalog.debug("Getting count of all fits for: {0}", stuff)
@@ -347,7 +353,7 @@ class Fit(FitDeprecated):
elif isinstance(thing, es_Module):
thing.state = es_Module.getProposedState(thing, click)
if not thing.canHaveState(thing.state, fit):
thing.state = State.OFFLINE
thing.state = FittingModuleState.OFFLINE
elif isinstance(thing, FitType):
projectionInfo = thing.getProjectionInfo(fitID)
if projectionInfo:
@@ -379,8 +385,8 @@ class Fit(FitDeprecated):
if m.fits(fit):
m.owner = fit
fit.modules.toModule(position, m)
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
# As some items may affect state-limiting attributes of the ship, calculate new attributes first
self.recalc(fit)
@@ -534,13 +540,13 @@ class Fit(FitDeprecated):
if mod != base:
# fix for #529, where a module may be in incorrect state after CCP changes mechanics of module
if not mod.canHaveState(mod.state) or not mod.isValidState(mod.state):
mod.state = State.ONLINE
mod.state = FittingModuleState.ONLINE
changed = True
for mod in fit.projectedModules:
# fix for #529, where a module may be in incorrect state after CCP changes mechanics of module
if not mod.canHaveState(mod.state, fit) or not mod.isValidState(mod.state):
mod.state = State.OFFLINE
mod.state = FittingModuleState.OFFLINE
changed = True
for drone in fit.projectedDrones:

View File

@@ -27,7 +27,8 @@ from eos.saveddata.cargo import Cargo as es_Cargo
from eos.saveddata.drone import Drone as es_Drone
from eos.saveddata.fighter import Fighter as es_Fighter
from eos.saveddata.implant import Implant as es_Implant
from eos.saveddata.module import Module as es_Module, State
from eos.saveddata.module import Module as es_Module
from eos.const import FittingModuleState
from eos.saveddata.fit import Fit as FitType
from utils.deprecated import deprecated
@@ -304,16 +305,16 @@ class FitDeprecated(object):
fit.projectedFighters.append(fighter)
elif thing.group.name in es_Module.SYSTEM_GROUPS:
module = es_Module(thing)
module.state = State.ONLINE
module.state = FittingModuleState.ONLINE
fit.projectedModules.append(module)
else:
try:
module = es_Module(thing)
except ValueError:
return False
module.state = State.ACTIVE
module.state = FittingModuleState.ACTIVE
if not module.canHaveState(module.state, fit):
module.state = State.OFFLINE
module.state = FittingModuleState.OFFLINE
fit.projectedModules.append(module)
eos.db.commit()
@@ -396,8 +397,8 @@ class FitDeprecated(object):
m.owner = fit
numSlots = len(fit.modules)
fit.modules.append(m)
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
# As some items may affect state-limiting attributes of the ship, calculate new attributes first
self.recalc(fit)
@@ -465,8 +466,8 @@ class FitDeprecated(object):
if m.fits(fit):
m.owner = fit
fit.modules.toModule(position, m)
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
if recalc:
# As some items may affect state-limiting attributes of the ship, calculate new attributes first
@@ -508,8 +509,8 @@ class FitDeprecated(object):
try:
cargoP = es_Module(cargo.item)
cargoP.owner = fit
if cargoP.isValidState(State.ACTIVE):
cargoP.state = State.ACTIVE
if cargoP.isValidState(FittingModuleState.ACTIVE):
cargoP.state = FittingModuleState.ACTIVE
except:
pyfalog.warning("Invalid item: {0}", cargo.item)
return

View File

@@ -28,8 +28,9 @@ from eos.saveddata.citadel import Citadel
from eos.saveddata.drone import Drone
from eos.saveddata.fighter import Fighter
from eos.saveddata.fit import Fit
from eos.saveddata.module import Module, State, Slot
from eos.saveddata.module import Module
from eos.saveddata.ship import Ship
from eos.const import FittingSlot, FittingModuleState
from service.fit import Fit as svcFit
from service.market import Market
@@ -106,8 +107,8 @@ def importDna(string):
f.modules.append(m)
else:
m.owner = f
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
moduleList.append(m)
# Recalc to get slot numbers correct for T3 cruisers
@@ -116,8 +117,8 @@ def importDna(string):
for module in moduleList:
if module.fits(f):
module.owner = f
if module.isValidState(State.ACTIVE):
module.state = State.ACTIVE
if module.isValidState(FittingModuleState.ACTIVE):
module.state = FittingModuleState.ACTIVE
f.modules.append(module)
return f
@@ -131,7 +132,7 @@ def exportDna(fit):
sFit = svcFit.getInstance()
for mod in fit.modules:
if not mod.isEmpty:
if mod.slot == Slot.SUBSYSTEM:
if mod.slot == FittingSlot.SUBSYSTEM:
subsystems.append(mod)
continue
if mod.itemID not in mods:

View File

@@ -6,8 +6,9 @@ from numbers import Number
from config import version as pyfaVersion
from service.fit import Fit
from service.market import Market
from eos.enum import Enum
from eos.saveddata.module import Hardpoint, Slot, Module, State
from eos.const import FittingModuleState, FittingHardpoint, FittingSlot
from service.const import PortEftRigSize
from eos.saveddata.module import Module
from eos.saveddata.drone import Drone
from eos.effectHandlerHelpers import HandledList
from eos.db import gamedata_session, getCategory, getAttributeInfo, getGroup
@@ -19,14 +20,6 @@ from logbook import Logger
pyfalog = Logger(__name__)
class RigSize(Enum):
# Matches to item attribute "rigSize" on ship and rig items
SMALL = 1
MEDIUM = 2
LARGE = 3
CAPITAL = 4
class EfsPort:
wepTestSet = {}
version = 0.03
@@ -58,13 +51,13 @@ class EfsPort:
mwd50mn = mapPropData("50MN Microwarpdrive II")
mwd500mn = mapPropData("500MN Microwarpdrive II")
mwd50000mn = mapPropData("50000MN Microwarpdrive II")
if rigSize == RigSize.SMALL or rigSize is None:
if rigSize == PortEftRigSize.SMALL or rigSize is None:
propID = mwd5mn["id"] if shipPower > mwd5mn["powerReq"] else None
elif rigSize == RigSize.MEDIUM:
elif rigSize == PortEftRigSize.MEDIUM:
propID = mwd50mn["id"] if shipPower > mwd50mn["powerReq"] else mwd5mn["id"]
elif rigSize == RigSize.LARGE:
elif rigSize == PortEftRigSize.LARGE:
propID = mwd500mn["id"] if shipPower > mwd500mn["powerReq"] else mwd50mn["id"]
elif rigSize == RigSize.CAPITAL:
elif rigSize == PortEftRigSize.CAPITAL:
propID = mwd50000mn["id"] if shipPower > mwd50000mn["powerReq"] else mwd500mn["id"]
if propID is None:
@@ -86,7 +79,7 @@ class EfsPort:
propWithBloom = next(filter(activePropWBloomFilter, propMods), None)
if propWithBloom is not None:
oldPropState = propWithBloom.state
propWithBloom.state = State.ONLINE
propWithBloom.state = FittingModuleState.ONLINE
sFit.recalc(fit)
sp = fit.maxSpeed
sig = fit.ship.getModifiedItemAttr("signatureRadius")
@@ -198,8 +191,8 @@ class EfsPort:
def getModuleInfo(fit, padTypeIDs=False):
moduleNames = []
modTypeIDs = []
moduleNameSets = {Slot.LOW: [], Slot.MED: [], Slot.HIGH: [], Slot.RIG: [], Slot.SUBSYSTEM: []}
modTypeIDSets = {Slot.LOW: [], Slot.MED: [], Slot.HIGH: [], Slot.RIG: [], Slot.SUBSYSTEM: []}
moduleNameSets = {FittingSlot.LOW: [], FittingSlot.MED: [], FittingSlot.HIGH: [], FittingSlot.RIG: [], FittingSlot.SUBSYSTEM: []}
modTypeIDSets = {FittingSlot.LOW: [], FittingSlot.MED: [], FittingSlot.HIGH: [], FittingSlot.RIG: [], FittingSlot.SUBSYSTEM: []}
for mod in fit.modules:
try:
if mod.item is not None:
@@ -216,17 +209,17 @@ class EfsPort:
pyfalog.error("Could not find name for module {0}".format(vars(mod)))
for modInfo in [
["High Slots:"], moduleNameSets[Slot.HIGH], ["", "Med Slots:"], moduleNameSets[Slot.MED],
["", "Low Slots:"], moduleNameSets[Slot.LOW], ["", "Rig Slots:"], moduleNameSets[Slot.RIG]
["High Slots:"], moduleNameSets[FittingSlot.HIGH], ["", "Med Slots:"], moduleNameSets[FittingSlot.MED],
["", "Low Slots:"], moduleNameSets[FittingSlot.LOW], ["", "Rig Slots:"], moduleNameSets[FittingSlot.RIG]
]:
moduleNames.extend(modInfo)
if len(moduleNameSets[Slot.SUBSYSTEM]) > 0:
if len(moduleNameSets[FittingSlot.SUBSYSTEM]) > 0:
moduleNames.extend(["", "Subsystems:"])
moduleNames.extend(moduleNameSets[Slot.SUBSYSTEM])
moduleNames.extend(moduleNameSets[FittingSlot.SUBSYSTEM])
for slotType in [Slot.HIGH, Slot.MED, Slot.LOW, Slot.RIG, Slot.SUBSYSTEM]:
if slotType is not Slot.SUBSYSTEM or len(modTypeIDSets[slotType]) > 0:
modTypeIDs.extend([0, 0] if slotType is not Slot.HIGH else [0])
for slotType in [FittingSlot.HIGH, FittingSlot.MED, FittingSlot.LOW, FittingSlot.RIG, FittingSlot.SUBSYSTEM]:
if slotType is not FittingSlot.SUBSYSTEM or len(modTypeIDSets[slotType]) > 0:
modTypeIDs.extend([0, 0] if slotType is not FittingSlot.HIGH else [0])
modTypeIDs.extend(modTypeIDSets[slotType])
droneNames = []
@@ -331,18 +324,18 @@ class EfsPort:
name = stats.item.name + ", " + stats.charge.name
else:
name = stats.item.name
if stats.hardpoint == Hardpoint.TURRET:
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 == Hardpoint.MISSILE or "Bomb Launcher" in stats.item.name:
elif stats.hardpoint == FittingHardpoint.MISSILE or "Bomb Launcher" in stats.item.name:
maxVelocity = stats.getModifiedChargeAttr("maxVelocity")
explosionDelay = stats.getModifiedChargeAttr("explosionDelay")
damageReductionFactor = stats.getModifiedChargeAttr("aoeDamageReductionFactor")
explosionRadius = stats.getModifiedChargeAttr("aoeCloudSize")
explosionVelocity = stats.getModifiedChargeAttr("aoeVelocity")
typeing = "Missile"
elif stats.hardpoint == Hardpoint.NONE:
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"
@@ -496,11 +489,11 @@ class EfsPort:
getDroneMulti = lambda d: sumDamage(d.getModifiedItemAttr) * d.getModifiedItemAttr("damageMultiplier")
fitMultipliers["drones"] = list(map(getDroneMulti, tf.drones))
getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.TURRET, f.modules)
getFitTurrets = lambda f: filter(lambda mod: mod.hardpoint == FittingHardpoint.TURRET, f.modules)
getTurretMulti = lambda mod: mod.getModifiedItemAttr("damageMultiplier") / mod.cycleTime
fitMultipliers["turrets"] = list(map(getTurretMulti, getFitTurrets(tf)))
getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == Hardpoint.MISSILE, f.modules)
getFitLaunchers = lambda f: filter(lambda mod: mod.hardpoint == FittingHardpoint.MISSILE, f.modules)
getLauncherMulti = lambda mod: sumDamage(mod.getModifiedChargeAttr) / mod.cycleTime
fitMultipliers["launchers"] = list(map(getLauncherMulti, getFitLaunchers(tf)))
return fitMultipliers
@@ -538,7 +531,7 @@ class EfsPort:
if effect._Effect__effectModule is not None:
effect.handler(tf, fit.mode, [])
if fit.ship.item.groupID == getGroup("Strategic Cruiser").ID:
subSystems = list(filter(lambda mod: mod.slot == Slot.SUBSYSTEM and mod.item, fit.modules))
subSystems = list(filter(lambda mod: mod.slot == FittingSlot.SUBSYSTEM and mod.item, fit.modules))
for sub in subSystems:
for effect in sub.item.effects.values():
if effect._Effect__effectModule is not None:

View File

@@ -19,7 +19,7 @@
import re
from enum import Enum
from service.const import PortEftOptions, PortEftRigSize
from logbook import Logger
@@ -30,9 +30,10 @@ from eos.saveddata.booster import Booster
from eos.saveddata.drone import Drone
from eos.saveddata.fighter import Fighter
from eos.saveddata.implant import Implant
from eos.saveddata.module import Module, State, Slot
from eos.saveddata.module import Module
from eos.saveddata.ship import Ship
from eos.saveddata.fit import Fit
from eos.const import FittingSlot, FittingModuleState
from service.fit import Fit as svcFit
from service.market import Market
from service.port.muta import parseMutant, renderMutant
@@ -41,22 +42,15 @@ from service.port.shared import IPortUser, fetchItem, processing_notify
pyfalog = Logger(__name__)
class Options(Enum):
IMPLANTS = 1
MUTATIONS = 2
LOADED_CHARGES = 3
EFT_OPTIONS = (
(Options.LOADED_CHARGES.value, 'Loaded Charges', 'Export charges loaded into modules', True),
(Options.MUTATIONS.value, 'Mutated Attributes', 'Export mutated modules\' stats', True),
(Options.IMPLANTS.value, 'Implants && Boosters', 'Export implants and boosters', True),
(PortEftOptions.LOADED_CHARGES.value, 'Loaded Charges', 'Export charges loaded into modules', True),
(PortEftOptions.MUTATIONS.value, 'Mutated Attributes', 'Export mutated modules\' stats', True),
(PortEftOptions.IMPLANTS.value, 'Implants && Boosters', 'Export implants and boosters', True),
)
MODULE_CATS = ('Module', 'Subsystem', 'Structure Module')
SLOT_ORDER = (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE)
SLOT_ORDER = (FittingSlot.LOW, FittingSlot.MED, FittingSlot.HIGH, FittingSlot.RIG, FittingSlot.SUBSYSTEM, FittingSlot.SERVICE)
OFFLINE_SUFFIX = '/OFFLINE'
@@ -86,21 +80,21 @@ def exportEft(fit, options):
modName = module.baseItem.name
else:
modName = module.item.name
if module.isMutated and options[Options.MUTATIONS.value]:
if module.isMutated and options[PortEftOptions.MUTATIONS.value]:
mutants[mutantReference] = module
mutationSuffix = ' [{}]'.format(mutantReference)
mutantReference += 1
else:
mutationSuffix = ''
modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == State.OFFLINE else ''
if module.charge and options[Options.LOADED_CHARGES.value]:
modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == FittingModuleState.OFFLINE else ''
if module.charge and options[PortEftOptions.LOADED_CHARGES.value]:
rackLines.append('{}, {}{}{}'.format(
modName, module.charge.name, modOfflineSuffix, mutationSuffix))
else:
rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix))
else:
rackLines.append('[Empty {} slot]'.format(
Slot.getName(slotType).capitalize() if slotType is not None else ''))
FittingSlot(slotType).name.capitalize() if slotType is not None else ''))
if rackLines:
modSection.append('\n'.join(rackLines))
if modSection:
@@ -122,7 +116,7 @@ def exportEft(fit, options):
sections.append('\n\n'.join(minionSection))
# Section 3: implants, boosters
if options[Options.IMPLANTS.value]:
if options[PortEftOptions.IMPLANTS.value]:
charSection = []
implantLines = []
for implant in fit.implants:
@@ -149,7 +143,7 @@ def exportEft(fit, options):
# Section 5: mutated modules' details
mutationLines = []
if mutants and options[Options.MUTATIONS.value]:
if mutants and options[PortEftOptions.MUTATIONS.value]:
for mutantReference in sorted(mutants):
mutant = mutants[mutantReference]
mutationLines.append(renderMutant(mutant, firstPrefix='[{}] '.format(mutantReference), prefix=' '))
@@ -441,8 +435,8 @@ def importEftCfg(shipname, lines, iportuser):
else:
m.owner = fitobj
# Activate mod if it is activable
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
# Add charge to mod if applicable, on any errors just don't add anything
if chargeName:
try:
@@ -722,12 +716,12 @@ class AbstractFit:
@property
def __slotContainerMap(self):
return {
Slot.HIGH: self.modulesHigh,
Slot.MED: self.modulesMed,
Slot.LOW: self.modulesLow,
Slot.RIG: self.rigs,
Slot.SUBSYSTEM: self.subsystems,
Slot.SERVICE: self.services}
FittingSlot.HIGH: self.modulesHigh,
FittingSlot.MED: self.modulesMed,
FittingSlot.LOW: self.modulesLow,
FittingSlot.RIG: self.rigs,
FittingSlot.SUBSYSTEM: self.subsystems,
FittingSlot.SERVICE: self.services}
def getContainerBySlot(self, slotType):
return self.__slotContainerMap.get(slotType)
@@ -798,10 +792,10 @@ class AbstractFit:
if itemSpec.charge is not None and m.isValidCharge(itemSpec.charge):
m.charge = itemSpec.charge
if itemSpec.offline and m.isValidState(State.OFFLINE):
m.state = State.OFFLINE
elif m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if itemSpec.offline and m.isValidState(FittingModuleState.OFFLINE):
m.state = FittingModuleState.OFFLINE
elif m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
return m
def addImplant(self, itemSpec):

View File

@@ -28,7 +28,8 @@ from eos.saveddata.citadel import Citadel
from eos.saveddata.drone import Drone
from eos.saveddata.fighter import Fighter
from eos.saveddata.fit import Fit
from eos.saveddata.module import Module, State, Slot
from eos.saveddata.module import Module
from eos.const import FittingSlot, FittingModuleState
from eos.saveddata.ship import Ship
from service.fit import Fit as svcFit
from service.market import Market
@@ -41,12 +42,12 @@ class ESIExportException(Exception):
pyfalog = Logger(__name__)
INV_FLAGS = {
Slot.LOW: 11,
Slot.MED: 19,
Slot.HIGH: 27,
Slot.RIG: 92,
Slot.SUBSYSTEM: 125,
Slot.SERVICE: 164
FittingSlot.LOW: 11,
FittingSlot.MED: 19,
FittingSlot.HIGH: 27,
FittingSlot.RIG: 92,
FittingSlot.SUBSYSTEM: 125,
FittingSlot.SERVICE: 164
}
INV_FLAG_CARGOBAY = 5
@@ -82,7 +83,7 @@ def exportESI(ofit):
item = nested_dict()
slot = module.slot
if slot == Slot.SUBSYSTEM:
if slot == FittingSlot.SUBSYSTEM:
# Order of subsystem matters based on this attr. See GH issue #130
slot = int(module.getModifiedItemAttr("subSystemSlot"))
item['flag'] = slot
@@ -189,8 +190,8 @@ def importESI(string):
if m.fits(fitobj):
fitobj.modules.append(m)
else:
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
moduleList.append(m)

View File

@@ -18,19 +18,12 @@
# =============================================================================
from enum import Enum
class Options(Enum):
IMPLANTS = 1
CARGO = 2
LOADED_CHARGES = 3
from service.const import PortMultiBuyOptions
MULTIBUY_OPTIONS = (
(Options.LOADED_CHARGES.value, 'Loaded Charges', 'Export charges loaded into modules', True),
(Options.IMPLANTS.value, 'Implants && Boosters', 'Export implants and boosters', False),
(Options.CARGO.value, 'Cargo', 'Export cargo contents', True),
(PortMultiBuyOptions.LOADED_CHARGES.value, 'Loaded Charges', 'Export charges loaded into modules', True),
(PortMultiBuyOptions.IMPLANTS.value, 'Implants && Boosters', 'Export implants and boosters', False),
(PortMultiBuyOptions.CARGO.value, 'Cargo', 'Export cargo contents', True),
)
@@ -48,7 +41,7 @@ def exportMultiBuy(fit, options):
if module.isMutated:
continue
addItem(module.item)
if module.charge and options[Options.LOADED_CHARGES.value]:
if module.charge and options[PortMultiBuyOptions.LOADED_CHARGES.value]:
addItem(module.charge, module.numCharges)
for drone in fit.drones:
@@ -57,11 +50,11 @@ def exportMultiBuy(fit, options):
for fighter in fit.fighters:
addItem(fighter.item, fighter.amountActive)
if options[Options.CARGO.value]:
if options[PortMultiBuyOptions.CARGO.value]:
for cargo in fit.cargo:
addItem(cargo.item, cargo.amount)
if options[Options.IMPLANTS.value]:
if options[PortMultiBuyOptions.IMPLANTS.value]:
for implant in fit.implants:
addItem(implant.item)

View File

@@ -29,7 +29,7 @@ from bs4 import UnicodeDammit
from logbook import Logger
from eos import db
from eos.saveddata.fit import ImplantLocation
from eos.const import ImplantLocation
from service.fit import Fit as svcFit
from service.port.dna import exportDna, importDna
from service.port.eft import exportEft, importEft, importEftCfg

View File

@@ -28,8 +28,9 @@ from eos.saveddata.citadel import Citadel
from eos.saveddata.drone import Drone
from eos.saveddata.fighter import Fighter
from eos.saveddata.fit import Fit
from eos.saveddata.module import Module, State, Slot
from eos.saveddata.module import Module
from eos.saveddata.ship import Ship
from eos.const import FittingSlot, FittingModuleState
from service.fit import Fit as svcFit
from service.market import Market
from utils.strfunctions import sequential_rep, replace_ltgt
@@ -198,8 +199,8 @@ def importXml(text, iportuser):
m.owner = fitobj
fitobj.modules.append(m)
else:
if m.isValidState(State.ACTIVE):
m.state = State.ACTIVE
if m.isValidState(FittingModuleState.ACTIVE):
m.state = FittingModuleState.ACTIVE
moduleList.append(m)
@@ -266,7 +267,7 @@ def exportXml(iportuser, *fits):
slot = module.slot
if slot == Slot.SUBSYSTEM:
if slot == FittingSlot.SUBSYSTEM:
# Order of subsystem matters based on this attr. See GH issue #130
slotId = module.getModifiedItemAttr("subSystemSlot") - 125
else:
@@ -278,7 +279,7 @@ def exportXml(iportuser, *fits):
hardware = doc.createElement("hardware")
hardware.setAttribute("type", module.item.name)
slotName = Slot.getName(slot).lower()
slotName = FittingSlot(slot).name.lower()
slotName = slotName if slotName != "high" else "hi"
hardware.setAttribute("slot", "%s slot %d" % (slotName, slotId))
fitting.appendChild(hardware)