Merge branch 'citadel'

This commit is contained in:
blitzman
2016-08-14 20:40:32 -04:00
86 changed files with 460 additions and 73 deletions

View File

@@ -18,10 +18,10 @@ debug = False
saveInRoot = False
# Version data
version = "1.22.2"
tag = "Stable"
expansionName = "YC 118.6"
expansionVersion = "1.0"
version = "1.22.3"
tag = "git"
expansionName = "Singularity"
expansionVersion = "1053072"
evemonMinVersion = "4081"
pyfaPath = None

View File

@@ -0,0 +1,3 @@
type = 'active'
def handler(fit, module, context):
pass

View File

@@ -3,7 +3,7 @@
# Used by:
# Modules from group: Missile Guidance Enhancer (3 of 3)
type = "passive"
def handler(fit, container, context):
def handler(fit, module, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"aoeCloudSize", container.getModifiedItemAttr("aoeCloudSizeBonus"),
"aoeCloudSize", module.getModifiedItemAttr("aoeCloudSizeBonus"),
stackingPenalties=True)

View File

@@ -3,7 +3,7 @@
# Used by:
# Modules from group: Missile Guidance Enhancer (3 of 3)
type = "passive"
def handler(fit, container, context):
def handler(fit, module, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"aoeVelocity", container.getModifiedItemAttr("aoeVelocityBonus"),
"aoeVelocity", module.getModifiedItemAttr("aoeVelocityBonus"),
stackingPenalties=True)

View File

@@ -3,7 +3,7 @@
# Used by:
# Modules from group: Missile Guidance Enhancer (3 of 3)
type = "passive"
def handler(fit, container, context):
def handler(fit, module, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"explosionDelay", container.getModifiedItemAttr("explosionDelayBonus"),
"explosionDelay", module.getModifiedItemAttr("explosionDelayBonus"),
stackingPenalties=True)

View File

@@ -3,7 +3,7 @@
# Used by:
# Modules from group: Missile Guidance Enhancer (3 of 3)
type = "passive"
def handler(fit, container, context):
def handler(fit, module, context):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
"maxVelocity", container.getModifiedItemAttr("missileVelocityBonus"),
"maxVelocity", module.getModifiedItemAttr("missileVelocityBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,7 @@
# targetAttack
#
# Used by:
# Citadel Point Defense
type = 'active'
def handler(fit, module, context):
pass

View File

@@ -4,7 +4,7 @@
# Variations of module: Guidance Disruptor I (6 of 6)
type = "active", "projected"
def handler(fit, src, context):
def handler(fit, module, context):
if "projected" in context:
for srcAttr, tgtAttr in (
("aoeCloudSizeBonus", "aoeCloudSize"),
@@ -13,5 +13,5 @@ def handler(fit, src, context):
("explosionDelayBonus", "explosionDelay"),
):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
tgtAttr, src.getModifiedItemAttr(srcAttr),
tgtAttr, module.getModifiedItemAttr(srcAttr),
stackingPenalties=True, remoteResists=True)

View File

@@ -0,0 +1,4 @@
type = "passive", "structure"
def handler(fit, src, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Structure Doomsday Weapon",
"duration", src.getModifiedItemAttr("durationBonus"), skill="Structure Doomsday Operation")

View File

@@ -0,0 +1,5 @@
type = "passive", "structure"
def handler(fit, src, context):
groups = ("Structure Warp Scrambler", "Structure Disruption Battery", "Structure Stasis Webifier")
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups,
"capacitorNeed", src.getModifiedItemAttr("capNeedBonus"), skill="Structure Electronic Systems")

View File

@@ -0,0 +1,5 @@
type = "passive", "structure"
def handler(fit, src, context):
groups = ("Structure Energy Neutralizer", "Structure Area Denial Module")
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups,
"capacitorNeed", src.getModifiedItemAttr("capNeedBonus"), skill="Structure Engineering Systems")

View File

@@ -0,0 +1,6 @@
type = "passive", "structure"
def handler(fit, src, context):
groups = ("Structure Anti-Capital Missile", "Structure Anti-Subcapital Missile", "Structure Guided Bomb")
for damageType in ("em", "thermal", "explosive", "kinetic"):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name in groups,
"%sDamage"%damageType, src.getModifiedItemAttr("damageMultiplierBonus"), skill="Structure Missile Systems")

View File

@@ -0,0 +1,19 @@
# missileAOECloudSizeBonusOnline
#
# Used by:
# Modules from group: Missile Guidance Enhancer (3 of 3)
type = "passive"
def handler(fit, module, context):
groups = ("Structure Anti-Capital Missile", "Structure Anti-Subcapital Missile")
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name in groups,
"aoeCloudSize", module.getModifiedItemAttr("aoeCloudSizeBonus"),
stackingPenalties=True)
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name in groups,
"aoeVelocity", module.getModifiedItemAttr("aoeVelocityBonus"),
stackingPenalties=True)
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name in groups,
"explosionDelay", module.getModifiedItemAttr("explosionDelayBonus"),
stackingPenalties=True)
fit.modules.filteredChargeBoost(lambda mod: mod.charge.group.name in groups,
"maxVelocity", module.getModifiedItemAttr("missileVelocityBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,13 @@
type = "passive"
def handler(fit, module, context):
missileGroups = ("Structure Anti-Capital Missile", "Structure Anti-Subcapital Missile")
for dmgType in ("em", "kinetic", "explosive", "thermal"):
fit.modules.filteredChargeMultiply(lambda mod: mod.charge.group.name in missileGroups,
"%sDamage" % dmgType, module.getModifiedItemAttr("missileDamageMultiplierBonus"),
stackingPenalties = True)
launcherGroups = ("Structure AXL Missile Launcher", "Structure ASML Missile Launcher")
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name in launcherGroups,
"speed", module.getModifiedItemAttr("speedMultiplier"),
stackingPenalties=True)

View File

@@ -0,0 +1,8 @@
from eos.types import State
type = "active", "projected"
def handler(fit, container, context):
if "projected" in context and ((hasattr(container, "state") \
and container.state >= State.ACTIVE) or hasattr(container, "amountActive")):
amount = container.getModifiedItemAttr("energyNeutralizerAmount")
time = container.getModifiedItemAttr("duration")
fit.addDrain(time, amount, 0)

View File

@@ -0,0 +1,7 @@
type = "projected", "active"
def handler(fit, module, context):
if "projected" in context:
# jam formula: 1 - (1- (jammer str/ship str))^(# of jam mods with same str))
strModifier = 1 - module.getModifiedItemAttr("scan{0}StrengthBonus".format(fit.scanType))/fit.scanStrength
fit.ecmProjectedStr *= strModifier

View File

@@ -0,0 +1,11 @@
type= "projected", "active"
def handler(fit, module, context):
if "projected" not in context:
return
fit.ship.boostItemAttr("maxTargetRange", module.getModifiedItemAttr("maxTargetRangeBonus"),
stackingPenalties = True, remoteResists=True)
fit.ship.boostItemAttr("scanResolution", module.getModifiedItemAttr("scanResolutionBonus"),
stackingPenalties = True, remoteResists=True)

View File

@@ -0,0 +1,5 @@
type = "active", "projected"
def handler(fit, module, context):
if "projected" not in context: return
fit.ship.boostItemAttr("maxVelocity", module.getModifiedItemAttr("speedFactor"),
stackingPenalties = True, remoteResists=True)

View File

@@ -0,0 +1,5 @@
type = "projected", "active"
def handler(fit, container, context):
if "projected" in context:
fit.ship.boostItemAttr("signatureRadius", container.getModifiedItemAttr("signatureRadiusBonus"),
stackingPenalties = True, remoteResists=True)

View File

@@ -0,0 +1,24 @@
type = "active", "projected"
def handler(fit, module, context):
if "projected" in context:
for srcAttr, tgtAttr in (
("aoeCloudSizeBonus", "aoeCloudSize"),
("aoeVelocityBonus", "aoeVelocity"),
("missileVelocityBonus", "maxVelocity"),
("explosionDelayBonus", "explosionDelay"),
):
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Missile Launcher Operation"),
tgtAttr, module.getModifiedItemAttr(srcAttr),
stackingPenalties=True, remoteResists=True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"trackingSpeed", module.getModifiedItemAttr("trackingSpeedBonus"),
stackingPenalties = True, remoteResists=True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"maxRange", module.getModifiedItemAttr("maxRangeBonus"),
stackingPenalties = True, remoteResists=True)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Gunnery"),
"falloff", module.getModifiedItemAttr("falloffBonus"),
stackingPenalties = True, remoteResists=True)

View File

@@ -0,0 +1,7 @@
type = "passive"
def handler(fit, src, context):
groups = ("Structure Anti-Subcapital Missile", "Structure Anti-Capital Missile")
fit.modules.filteredChargeMultiply(lambda mod: mod.charge.group.name in groups,
"aoeVelocity", src.getModifiedItemAttr("structureRigMissileExploVeloBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Structure Doomsday Weapon",
"lightningWeaponDamageLossTarget", src.getModifiedItemAttr("structureRigDoomsdayDamageLossTargetBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Structure Doomsday Weapon",
"lightningWeaponTargetAmount", src.getModifiedItemAttr("structureRigDoomsdayTargetAmountBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,6 @@
type = "passive"
def handler(fit, src, context):
groups = ("Structure ECM Battery", "Structure Disruption Battery")
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name in groups,
"capacitorNeed", src.getModifiedItemAttr("structureRigEwarCapUseBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,15 @@
type = "passive"
def handler(fit, src, context):
groups = ("Structure ECM Battery", "Structure Disruption Battery")
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name in groups,
"falloff", src.getModifiedItemAttr("structureRigEwarFalloffBonus"),
stackingPenalties=True)
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name in groups,
"maxRange", src.getModifiedItemAttr("structureRigEwarOptimalBonus"),
stackingPenalties=True)
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name in groups,
"falloffEffectiveness", src.getModifiedItemAttr("structureRigEwarFalloffBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredChargeMultiply(lambda mod: mod.charge.group.name == "Structure Guided Bomb",
"aoeCloudSize", src.getModifiedItemAttr("structureRigMissileExplosionRadiusBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,3 @@
type = "passive"
def handler(fit, src, context):
fit.ship.increaseItemAttr("maxLockedTargets", src.getModifiedItemAttr("structureRigMaxTargetBonus"))

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Structure Energy Neutralizer",
"capacitorNeed", src.getModifiedItemAttr("structureRigEwarCapUseBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,9 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Structure Energy Neutralizer",
"maxRange", src.getModifiedItemAttr("structureRigEwarOptimalBonus"),
stackingPenalties=True)
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Structure Energy Neutralizer",
"falloffEffectiveness", src.getModifiedItemAttr("structureRigEwarFalloffBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Structure Area Denial Module",
"capacitorNeed", src.getModifiedItemAttr("structureRigPDCapUseBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.group.name == "Structure Area Denial Module",
"empFieldRange", src.getModifiedItemAttr("structureRigPDRangeBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, src, context):
fit.ship.boostItemAttr("scanResolution", src.getModifiedItemAttr("structureRigScanResBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, src, context):
fit.modules.filteredChargeMultiply(lambda mod: mod.charge.group.name == "Structure Guided Bomb",
"maxVelocity", src.getModifiedItemAttr("structureRigMissileVelocityBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,6 @@
type = "passive"
def handler(fit, src, context):
groups = ("Structure Anti-Subcapital Missile", "Structure Anti-Capital Missile")
fit.modules.filteredChargeMultiply(lambda mod: mod.charge.group.name in groups,
"maxVelocity", src.getModifiedItemAttr("structureRigMissileVelocityBonus"),
stackingPenalties=True)

View File

@@ -0,0 +1,12 @@
runTime = "early"
type = "projected", "active"
from eos.types import State
def handler(fit, module, context):
if "projected" not in context:
return
# this is such a dirty hack
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

View File

@@ -89,7 +89,7 @@ class Effect(EqBase):
The type of the effect, automaticly fetched from effects/<effectName>.py if the file exists.
Valid values are:
"passive", "active", "projected", "gang"
"passive", "active", "projected", "gang", "structure"
Each gives valuable information to eos about what type the module having
the effect is. passive vs active gives eos clues about wether to module

View File

@@ -24,6 +24,7 @@ from itertools import chain
from eos.effectHandlerHelpers import HandledItem, HandledImplantBoosterList
import eos.db
import eos
import eos.types
import logging
logger = logging.getLogger(__name__)
@@ -329,7 +330,7 @@ class Skill(HandledItem):
return
for effect in item.effects.itervalues():
if effect.runTime == runTime and effect.isType("passive"):
if effect.runTime == runTime and effect.isType("passive") and (not fit.isStructure or effect.isType("structure")):
try:
effect.handler(fit, self, ("skill",))
except AttributeError:

42
eos/saveddata/citadel.py Normal file
View File

@@ -0,0 +1,42 @@
#===============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
from eos.effectHandlerHelpers import HandledItem
from eos.saveddata.mode import Mode
import eos.db
from eos.types import Ship
import logging
logger = logging.getLogger(__name__)
class Citadel(Ship):
def validate(self, item):
if item.category.name != "Structure":
raise ValueError('Passed item "%s" (category: (%s)) is not under Structure category'%(item.name, item.category.name))
def __deepcopy__(self, memo):
copy = Citadel(self.item)
return copy
def __repr__(self):
return "Citadel(ID={}, name={}) at {}".format(
self.item.ID, self.item.name, hex(id(self))
)

View File

@@ -35,7 +35,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def __init__(self, item):
"""Initialize a fighter from the program"""
self.__item = item
print self.__item.category.name
if self.isInvalid:
raise ValueError("Passed item is not a Fighter")

View File

@@ -24,7 +24,7 @@ from itertools import chain
from eos import capSim
from copy import deepcopy
from math import sqrt, log, asinh
from eos.types import Drone, Cargo, Ship, Character, State, Slot, Module, Implant, Booster, Skill
from eos.types import Drone, Cargo, Ship, Character, State, Slot, Module, Implant, Booster, Skill, Citadel
from eos.saveddata.module import State, Hardpoint
from eos.saveddata.mode import Mode
import eos.db
@@ -92,7 +92,10 @@ class Fit(object):
return
try:
self.__ship = Ship(item, self)
try:
self.__ship = Ship(item, self)
except ValueError:
self.__ship = Citadel(item, self)
# @todo extra attributes is now useless, however it set to be
# the same as ship attributes for ease (so we don't have to
# change all instances in source). Remove this at some point
@@ -191,6 +194,10 @@ class Fit(object):
# set fit attributes the same as ship
self.extraAttributes = self.ship.itemModifiedAttributes
@property
def isStructure(self):
return isinstance(self.ship, Citadel)
@property
def drones(self):
return self.__drones
@@ -331,7 +338,7 @@ class Fit(object):
@property
def alignTime(self):
agility = self.ship.getModifiedItemAttr("agility")
agility = self.ship.getModifiedItemAttr("agility") or 0
mass = self.ship.getModifiedItemAttr("mass")
return -log(0.25) * agility * mass / 1000000
@@ -510,6 +517,11 @@ class Fit(object):
self.boosters,
self.appliedImplants,
self.modules
] if not self.isStructure else [
# Ensure a restricted set for citadels
(self.character, self.ship),
self.fighters,
self.modules
]
# Items that are restricted. These items are only run on the local
@@ -564,7 +576,7 @@ class Fit(object):
if self.ship is None:
return
for slotType in (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM):
for slotType in (Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE):
amount = self.getSlotsFree(slotType, True)
if amount > 0:
for _ in xrange(int(amount)):
@@ -639,6 +651,7 @@ class Fit(object):
Slot.HIGH: "hiSlots",
Slot.RIG: "rigSlots",
Slot.SUBSYSTEM: "maxSubSystems",
Slot.SERVICE: "serviceSlots",
Slot.F_LIGHT: "fighterLightSlots",
Slot.F_SUPPORT: "fighterSupportSlots",
Slot.F_HEAVY: "fighterHeavySlots"}
@@ -743,6 +756,10 @@ class Fit(object):
capacity = self.ship.getModifiedItemAttr("capacitorCapacity")
mass = self.ship.getModifiedItemAttr("mass")
warpCapNeed = self.ship.getModifiedItemAttr("warpCapacitorNeed")
if not warpCapNeed:
return 0
return capacity / (mass * warpCapNeed)
@property

View File

@@ -24,6 +24,7 @@ from eos.effectHandlerHelpers import HandledItem, HandledCharge
from eos.enum import Enum
from eos.mathUtils import floorFloat
import eos.db
from eos.types import Citadel
import logging
logger = logging.getLogger(__name__)
@@ -46,6 +47,8 @@ class Slot(Enum):
# system effects. They are projected "modules" and pyfa assumes all modules
# have a slot. In this case, make one up.
SYSTEM = 7
# used for citadel services
SERVICE = 8
# fighter 'slots'. Just easier to put them here...
F_LIGHT = 10
F_SUPPORT = 11
@@ -151,7 +154,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
def isInvalid(self):
if self.isEmpty:
return False
return self.__item is None or (self.__item.category.name not in ("Module", "Subsystem") and self.__item.group.name != "Effect Beacon")
return self.__item is None or (self.__item.category.name not in ("Module", "Subsystem", "Structure Module") and self.__item.group.name != "Effect Beacon")
@property
def numCharges(self):
@@ -393,6 +396,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
if (len(fitsOnGroup) > 0 or len(fitsOnType) > 0) and fit.ship.item.group.ID not in fitsOnGroup and fit.ship.item.ID not in fitsOnType:
return False
# AFAIK Citadel modules will always be restricted based on canFitShipType/Group. If we are fitting to a Citadel
# and the module does not have these properties, return false to prevent regular ship modules from being used
if isinstance(fit.ship, Citadel) and len(fitsOnGroup) == 0 and len(fitsOnType) == 0:
return False
# If the mod is a subsystem, don't let two subs in the same slot fit
if self.slot == Slot.SUBSYSTEM:
subSlot = self.getModifiedItemAttr("subSystemSlot")
@@ -534,7 +542,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
"loPower" : Slot.LOW,
"medPower" : Slot.MED,
"hiPower" : Slot.HIGH,
"subSystem" : Slot.SUBSYSTEM}
"subSystem" : Slot.SUBSYSTEM,
"serviceSlot": Slot.SERVICE}
if item is None:
return None
for effectName, slot in effectSlotMap.iteritems():

View File

@@ -42,9 +42,7 @@ class Ship(ItemAttrShortcut, HandledItem):
}
def __init__(self, item, parent=None):
if item.category.name != "Ship":
raise ValueError('Passed item "%s" (category: (%s)) is not under Ship category'%(item.name, item.category.name))
self.validate(item)
self.__item = item
self.__modeItems = self.__getModeItems()
@@ -58,6 +56,10 @@ class Ship(ItemAttrShortcut, HandledItem):
self.parent = parent
self.commandBonus = 0
def validate(self, item):
if item.category.name != "Ship":
raise ValueError('Passed item "%s" (category: (%s)) is not under Ship category'%(item.name, item.category.name))
@property
def item(self):
return self.__item

View File

@@ -25,6 +25,8 @@ from eos.saveddata.crestchar import CrestChar
from eos.saveddata.damagePattern import DamagePattern
from eos.saveddata.targetResists import TargetResists
from eos.saveddata.character import Character, Skill
from eos.saveddata.ship import Ship
from eos.saveddata.citadel import Citadel
from eos.saveddata.module import Module, State, Slot, Hardpoint, Rack
from eos.saveddata.drone import Drone
from eos.saveddata.fighterAbility import FighterAbility
@@ -34,10 +36,10 @@ from eos.saveddata.implant import Implant
from eos.saveddata.implantSet import ImplantSet
from eos.saveddata.booster import SideEffect
from eos.saveddata.booster import Booster
from eos.saveddata.ship import Ship
from eos.saveddata.fit import Fit, ImplantLocation
from eos.saveddata.mode import Mode
from eos.saveddata.fleet import Fleet, Wing, Squad
from eos.saveddata.miscData import MiscData
from eos.saveddata.override import Override
import eos.db

BIN
eve.db

Binary file not shown.

View File

@@ -58,23 +58,36 @@ class AdditionsPane(TogglePanel):
gangImg = BitmapLoader.getImage("fleet_fc_small", "gui")
cargoImg = BitmapLoader.getImage("cargo_small", "gui")
self.notebook.AddPage(DroneView(self.notebook), "Drones", tabImage = droneImg, showClose = False)
self.notebook.AddPage(FighterView(self.notebook), "Fighters", tabImage = fighterImg, showClose = False)
self.notebook.AddPage(CargoView(self.notebook), "Cargo", tabImage = cargoImg, showClose = False)
self.notebook.AddPage(ImplantView(self.notebook), "Implants", tabImage = implantImg, showClose = False)
self.notebook.AddPage(BoosterView(self.notebook), "Boosters", tabImage = boosterImg, showClose = False)
self.drone = DroneView(self.notebook)
self.notebook.AddPage(self.drone, "Drones", tabImage = droneImg, showClose = False)
self.fighter = FighterView(self.notebook)
self.notebook.AddPage(self.fighter, "Fighters", tabImage = fighterImg, showClose = False)
self.cargo = CargoView(self.notebook)
self.notebook.AddPage(self.cargo, "Cargo", tabImage = cargoImg, showClose = False)
self.implant = ImplantView(self.notebook)
self.notebook.AddPage(self.implant, "Implants", tabImage = implantImg, showClose = False)
self.booster = BoosterView(self.notebook)
self.notebook.AddPage(self.booster, "Boosters", tabImage = boosterImg, showClose = False)
self.projectedPage = ProjectedView(self.notebook)
self.notebook.AddPage(self.projectedPage, "Projected", tabImage = projectedImg, showClose = False)
self.gangPage = GangView(self.notebook)
self.notebook.AddPage(self.gangPage, "Fleet", tabImage = gangImg, showClose = False)
self.notebook.SetSelection(0)
PANES = ["Drones", "Fighters", "Cargo", "Implants", "Boosters", "Projected", "Fleet"]
def select(self, name):
self.notebook.SetSelection(self.PANES.index(name))
def toggleBoosters(self, event):
self.notebook.ToggleShown(self.booster)
def getName(self, idx):
return self.PANES[idx]

View File

@@ -85,6 +85,11 @@ class BoosterView(d.Display):
event.Skip()
def fitChanged(self, event):
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
#Clear list and get out if current fitId is None
if event.fitID is None and self.lastFitId is not None:
self.DeleteAllItems()
@@ -92,9 +97,6 @@ class BoosterView(d.Display):
event.Skip()
return
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.origional = fit.boosters if fit is not None else None
self.boosters = stuff = fit.boosters[:] if fit is not None else None
@@ -115,6 +117,12 @@ class BoosterView(d.Display):
def addItem(self, event):
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(fitID)
if fit.isStructure:
return
trigger = sFit.addBooster(fitID, event.itemID)
if trigger:
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))

View File

@@ -11,8 +11,12 @@ class Cargo(ContextMenu):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
def display(self, srcContext, selection):
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(fitID)
# Make sure context menu registers in the correct view
if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None:
if srcContext not in ("marketItemGroup", "marketItemMisc") or not fit or fit.isStructure:
return False
return True

View File

@@ -29,6 +29,9 @@ class MetaSwap(ContextMenu):
self.selection = selection
if len(self.variations) == 1:
return False # no variations from current module
return True
def getText(self, itmContext, selection):
@@ -38,6 +41,7 @@ class MetaSwap(ContextMenu):
self.moduleLookup = {}
def get_metalevel(x):
if "metaLevel" not in x.attributes: return 0
return x.attributes["metaLevel"].value
def get_metagroup(x):

View File

@@ -12,7 +12,7 @@ class ShipJump(ContextMenu):
return srcContext == "fittingShip"
def getText(self, itmContext, selection):
return "Open in Ship Browser"
return "Open in Fitting Browser"
def activate(self, fullContext, selection, i):
fitID = self.mainFrame.getActiveFit()

View File

@@ -201,7 +201,7 @@ class TargetingMiscViewFull(StatsView):
elif labelName == "labelFullAlignTime":
alignTime = "Align:\t%.3fs"%mainValue
mass = 'Mass:\t{:,.0f}kg'.format(fit.ship.getModifiedItemAttr("mass"))
agility = "Agility:\t%.3fx"%fit.ship.getModifiedItemAttr("agility")
agility = "Agility:\t%.3fx"%(fit.ship.getModifiedItemAttr("agility") or 0)
label.SetToolTip(wx.ToolTip("%s\n%s\n%s" % (alignTime, mass, agility)))
elif labelName == "labelFullCargo":
tipLines = []

View File

@@ -409,7 +409,7 @@ class FittingView(d.Display):
sFit = service.Fit.getInstance()
fit = sFit.getFit(self.activeFitID)
slotOrder = [Slot.SUBSYSTEM, Slot.HIGH, Slot.MED, Slot.LOW, Slot.RIG]
slotOrder = [Slot.SUBSYSTEM, Slot.HIGH, Slot.MED, Slot.LOW, Slot.RIG, Slot.SERVICE]
if fit is not None:
self.mods = fit.modules[:]
@@ -503,7 +503,10 @@ class FittingView(d.Display):
sel = self.GetNextSelected(sel)
contexts.append(("fittingShip", "Ship"))
sFit = service.Fit.getInstance()
fit = sFit.getFit(self.activeFitID)
contexts.append(("fittingShip", "Ship" if not fit.isStructure else "Citadel"))
menu = ContextMenu.getMenu(selection, *contexts)
self.PopupMenu(menu)

View File

@@ -125,6 +125,11 @@ class CargoView(d.Display):
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
def fitChanged(self, event):
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
#Clear list and get out if current fitId is None
if event.fitID is None and self.lastFitId is not None:
self.DeleteAllItems()
@@ -132,9 +137,6 @@ class CargoView(d.Display):
event.Skip()
return
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.original = fit.cargo if fit is not None else None
self.cargo = stuff = fit.cargo if fit is not None else None
if stuff is not None: stuff.sort(key=lambda cargo: cargo.itemID)

View File

@@ -227,6 +227,18 @@ class PFNotebook(wx.Panel):
self.activePage = tabWnd
self.ShowActive(True)
def DisablePage(self, page, toggle):
idx = self.GetPageIndex(page)
if toggle and page == self.activePage:
try:
# Set page to the first non-disabled page
self.SetSelection(next(i for i, _ in enumerate(self.pages) if not self.tabsContainer.tabs[i].disabled))
except StopIteration, ex:
self.SetSelection(0)
self.tabsContainer.DisableTab(idx, toggle)
def SetSelection(self, page):
oldsel = self.GetSelection()
if oldsel != page:
@@ -354,6 +366,7 @@ class PFTabRenderer:
self.inclination = inclination
self.text = text
self.disabled = False
self.tabSize = (width, height)
self.closeButton = closeButton
self.selected = False
@@ -548,7 +561,7 @@ class PFTabRenderer:
mdc.DrawBitmap(self.tabBackBitmap, 0, 0, True)
if self.tabImg:
bmp = wx.BitmapFromImage(self.tabImg)
bmp = wx.BitmapFromImage(self.tabImg.ConvertToGreyscale() if self.disabled else self.tabImg)
if self.contentWidth > 16: # @todo: is this conditional relevant anymore?
# Draw tab icon
mdc.DrawBitmap(bmp, self.leftWidth + self.padding - bmp.GetWidth()/2, (height - bmp.GetHeight())/2)
@@ -591,6 +604,10 @@ class PFTabRenderer:
bmp = wx.BitmapFromImage(img)
self.tabBitmap = bmp
def __repr__(self):
return "PFTabRenderer(text={}, disabled={}) at {}".format(
self.text, self.disabled, hex(id(self))
)
class PFAddRenderer:
def __init__(self):
@@ -848,6 +865,7 @@ class PFTabsContainer(wx.Panel):
return True
if self.TabHitTest(tab, x, y):
if tab.disabled: return
tab.SetSelected(True)
oldSelTab.SetSelected(False)
@@ -1186,6 +1204,13 @@ class PFTabsContainer(wx.Panel):
for tab in self.tabs:
tab.SetSelected(False)
def DisableTab(self, tab, disabled=True):
tabRenderer = self.tabs[tab]
tabRenderer.disabled = disabled
self.AdjustTabsSize()
self.Refresh()
def DeleteTab(self, tab, external=False):
tabRenderer = self.tabs[tab]
wasSelected = tabRenderer.GetSelected()

View File

@@ -159,6 +159,10 @@ class DroneView(d.Display):
drone.item.name)
def fitChanged(self, event):
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
#Clear list and get out if current fitId is None
if event.fitID is None and self.lastFitId is not None:
@@ -167,9 +171,6 @@ class DroneView(d.Display):
event.Skip()
return
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.original = fit.drones if fit is not None else None
self.drones = stuff = fit.drones[:] if fit is not None else None
@@ -194,6 +195,12 @@ class DroneView(d.Display):
def addItem(self, event):
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(fitID)
if fit.isStructure:
return
trigger = sFit.addDrone(fitID, event.itemID)
if trigger:
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))

View File

@@ -224,6 +224,10 @@ class FighterDisplay(d.Display):
'''
def fitChanged(self, event):
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.Parent.Parent.Parent.DisablePage(self.Parent, not fit)
#Clear list and get out if current fitId is None
if event.fitID is None and self.lastFitId is not None:
@@ -232,9 +236,6 @@ class FighterDisplay(d.Display):
event.Skip()
return
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.original = fit.fighters if fit is not None else None
self.fighters = stuff = fit.fighters[:] if fit is not None else None

View File

@@ -26,7 +26,6 @@ import gui.globalEvents as GE
from gui import characterEditor as CharEditor
class GangView ( ScrolledPanel ):
def __init__( self, parent ):
@@ -247,6 +246,9 @@ class GangView ( ScrolledPanel ):
activeFitID = self.mainFrame.getActiveFit()
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID or activeFitID)
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
commanders = (None, None, None)
if activeFitID:
@@ -363,8 +365,10 @@ class GangView ( ScrolledPanel ):
#Those are drags coming from pyfa sources, NOT builtin wx drags
self.draggedFitID = None
if type == "fit":
activeFit = self.mainFrame.getActiveFit()
if activeFit:
sFit = service.Fit.getInstance()
fit = sFit.getFit(self.mainFrame.getActiveFit())
if fit and not fit.isStructuree:
self.draggedFitID = fitID
pos = wx.GetMousePosition()

View File

@@ -107,6 +107,11 @@ class ImplantDisplay(d.Display):
event.Skip()
def fitChanged(self, event):
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.Parent.Parent.Parent.DisablePage(self.Parent, not fit or fit.isStructure)
#Clear list and get out if current fitId is None
if event.fitID is None and self.lastFitId is not None:
self.DeleteAllItems()
@@ -114,9 +119,6 @@ class ImplantDisplay(d.Display):
event.Skip()
return
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.original = fit.implants if fit is not None else None
self.implants = stuff = fit.appliedImplants if fit is not None else None
if stuff is not None: stuff.sort(key=lambda implant: implant.slot)
@@ -137,6 +139,12 @@ class ImplantDisplay(d.Display):
def addItem(self, event):
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(fitID)
if fit.isStructure:
return
trigger = sFit.addImplant(fitID, event.itemID)
if trigger:
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))

View File

@@ -24,7 +24,7 @@ from gui.bitmapLoader import BitmapLoader
import sys
import wx.lib.mixins.listctrl as listmix
import wx.html
from eos.types import Fit, Ship, Module, Skill, Booster, Implant, Drone, Mode, Fighter
from eos.types import Fit, Ship, Citadel, Module, Skill, Booster, Implant, Drone, Mode, Fighter
from gui.utils.numberFormatter import formatAmount
import service
import config
@@ -747,7 +747,7 @@ class ItemEffects (wx.Panel):
class ItemAffectedBy (wx.Panel):
ORDER = [Fit, Ship, Mode, Module, Drone, Fighter, Implant, Booster, Skill]
ORDER = [Fit, Ship, Citadel, Mode, Module, Drone, Fighter, Implant, Booster, Skill]
def __init__(self, parent, stuff, item):
wx.Panel.__init__(self, parent)
self.stuff = stuff

View File

@@ -156,7 +156,7 @@ class MainFrame(wx.Frame):
self.marketBrowser.splitter.SetSashPosition(self.marketHeight)
self.shipBrowser = ShipBrowser(self.notebookBrowsers)
self.notebookBrowsers.AddPage(self.shipBrowser, "Ships", tabImage = shipBrowserImg, showClose = False)
self.notebookBrowsers.AddPage(self.shipBrowser, "Fittings", tabImage = shipBrowserImg, showClose = False)
#=======================================================================
# DISABLED FOR RC2 RELEASE

View File

@@ -159,6 +159,11 @@ class ProjectedView(d.Display):
return fit.name
def fitChanged(self, event):
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
#Clear list and get out if current fitId is None
if event.fitID is None and self.lastFitId is not None:
self.DeleteAllItems()
@@ -166,8 +171,6 @@ class ProjectedView(d.Display):
event.Skip()
return
sFit = service.Fit.getInstance()
fit = sFit.getFit(event.fitID)
stuff = []
if fit is not None:
self.modules = fit.projectedModules[:]

View File

@@ -1538,7 +1538,10 @@ class FitItem(SFItem.SFBrowserItem):
menu.Check(toggleItem.GetId(), self.fitBooster)
self.Bind(wx.EVT_MENU, self.OnToggleBooster, toggleItem)
if self.mainFrame.getActiveFit():
sFit = service.Fit.getInstance()
fit = sFit.getFit(self.mainFrame.getActiveFit())
if fit and not fit.isStructure:
# If there is an active fit, get menu for setting individual boosters
menu.AppendSeparator()
boosterMenu = self.mainFrame.additionsPane.gangPage.buildBoostermenu()

BIN
imgs/icons/123_10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

BIN
imgs/icons/123_11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

BIN
imgs/icons/123_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

BIN
imgs/icons/123_6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

BIN
imgs/icons/123_8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 B

BIN
imgs/icons/123_9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

BIN
imgs/icons/127_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

BIN
imgs/icons/127_10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

BIN
imgs/icons/127_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

BIN
imgs/icons/127_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

BIN
imgs/icons/127_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

BIN
imgs/icons/127_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

BIN
imgs/icons/127_7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

BIN
imgs/icons/127_9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

BIN
imgs/icons/45_12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 800 B

After

Width:  |  Height:  |  Size: 800 B

BIN
imgs/renders/35832.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
imgs/renders/35833.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
imgs/renders/35834.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
imgs/renders/40340.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -38,7 +38,8 @@ ITEM_CATEGORIES = (
16, # Skill
18, # Drone
20, # Implant
32 # Subsystem
32, # Subsystem
66, # Structure Module
)
MARKET_ROOTS = {
@@ -48,7 +49,9 @@ MARKET_ROOTS = {
11, # Ammo
1112, # Subsystems
24, # Implants & Boosters
404 # Deployables
404, # Deployables
2202, # Structure Equipment
2203 # Structure Modifications (Rigs)
}
# Add children to market group list
@@ -153,7 +156,7 @@ for fname in os.listdir(icons_dir):
print fname,"exists"
existing.add(fname)
# Get a list of all the icons currently available
# Get a list of all the icons currently available in export
for dir in dirs:
for fname in os.listdir(dir):
if not os.path.isfile(os.path.join(dir, fname)):
@@ -164,7 +167,7 @@ for dir in dirs:
# convention without size specification
sizeless = re.sub('^(?P<prefix>[^_]+)_(?P<size>\d+)_(?P<suffix>[^_]+)$', r'\1_\3', stripped)
# Often items referred to with 01_01 format,
fnames = export.setdefault(stripped.lower(), set())
fnames = export.setdefault(sizeless.lower(), set())
fnames.add(fname)
def crop_image(img):

View File

@@ -30,7 +30,7 @@ cursor = db.cursor()
RENDER_SIZE = (32, 32)
query_ships = 'select it.typeID from invtypes as it inner join invgroups as ig on it.groupID = ig.groupID where ig.categoryID = 6'
query_ships = 'select it.typeID from invtypes as it inner join invgroups as ig on it.groupID = ig.groupID where ig.categoryID in (6, 65)'
needed = set()

View File

@@ -158,7 +158,10 @@ class Fit(object):
return fit.modules[pos]
def newFit(self, shipID, name=None):
ship = eos.types.Ship(eos.db.getItem(shipID))
try:
ship = eos.types.Ship(eos.db.getItem(shipID))
except ValueError:
ship = eos.types.Citadel(eos.db.getItem(shipID))
fit = eos.types.Fit(ship)
fit.name = name if name is not None else "New %s" % fit.ship.item.name
fit.damagePattern = self.pattern
@@ -361,7 +364,6 @@ class Fit(object):
drone.amount += 1
elif thing.category.name == "Fighter":
print "dskfnds"
fighter = eos.types.Fighter(thing)
fit.projectedFighters.append(fighter)
elif thing.group.name == "Effect Beacon":

View File

@@ -331,7 +331,7 @@ class Market():
("faction", frozenset((4, 3))),
("complex", frozenset((6,))),
("officer", frozenset((5,)))])
self.SEARCH_CATEGORIES = ("Drone", "Module", "Subsystem", "Charge", "Implant", "Deployable", "Fighter")
self.SEARCH_CATEGORIES = ("Drone", "Module", "Subsystem", "Charge", "Implant", "Deployable", "Fighter", "Structure", "Structure Module")
self.SEARCH_GROUPS = ("Ice Product",)
self.ROOT_MARKET_GROUPS = (9, # Modules
1111, # Rigs
@@ -339,7 +339,10 @@ class Market():
11, # Ammo
1112, # Subsystems
24, # Implants & Boosters
404) # Deployables
404, # Deployables
2202, # Structure Equipment
2203 # Structure Modifications
)
# Tell other threads that Market is at their service
mktRdy.set()
@@ -666,8 +669,10 @@ class Market():
return root
def getShipRoot(self):
cat = self.getCategory("Ship")
root = set(self.getGroupsByCategory(cat))
cat1 = self.getCategory("Ship")
cat2 = self.getCategory("Structure")
root = set(self.getGroupsByCategory(cat1) | self.getGroupsByCategory(cat2))
return root
def getShipList(self, grpid):