Merge branch 'master' into feature/alphaclones
Conflicts: eve.db
@@ -18,10 +18,10 @@ debug = False
|
||||
saveInRoot = False
|
||||
|
||||
# Version data
|
||||
version = "1.25.2"
|
||||
version = "1.26.1"
|
||||
tag = "git"
|
||||
expansionName = "Ascension"
|
||||
expansionVersion = "1.9"
|
||||
expansionName = "YC118.10"
|
||||
expansionVersion = "1.2"
|
||||
evemonMinVersion = "4081"
|
||||
|
||||
pyfaPath = None
|
||||
|
||||
@@ -8,7 +8,6 @@ __all__ = [
|
||||
"booster",
|
||||
"drone",
|
||||
"implant",
|
||||
"fleet",
|
||||
"damagePattern",
|
||||
"miscData",
|
||||
"targetResists",
|
||||
|
||||
104
eos/db/saveddata/databaseRepair.py
Normal file
@@ -0,0 +1,104 @@
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# 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/>.
|
||||
# ===============================================================================
|
||||
|
||||
import sqlalchemy
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DatabaseCleanup:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def OrphanedCharacterSkills(saveddata_engine):
|
||||
# Finds and fixes database corruption issues.
|
||||
logger.debug("Start databsae validation and cleanup.")
|
||||
|
||||
# Find orphaned character skills.
|
||||
# This solves an issue where the character doesn't exist, but skills for that character do.
|
||||
# See issue #917
|
||||
try:
|
||||
logger.debug("Running database cleanup for character skills.")
|
||||
results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM characterSkills "
|
||||
"WHERE characterID NOT IN (SELECT ID from characters)")
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
delete = saveddata_engine.execute("DELETE FROM characterSkills WHERE characterID NOT IN (SELECT ID from characters)")
|
||||
logger.error("Database corruption found. Cleaning up %d records.", delete.rowcount)
|
||||
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
logger.error("Failed to connect to database.")
|
||||
|
||||
@staticmethod
|
||||
def OrphanedFitDamagePatterns(saveddata_engine):
|
||||
# Find orphaned damage patterns.
|
||||
# This solves an issue where the damage pattern doesn't exist, but fits reference the pattern.
|
||||
# See issue #777
|
||||
try:
|
||||
logger.debug("Running database cleanup for orphaned damage patterns attached to fits.")
|
||||
|
||||
results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL")
|
||||
row = results.first()
|
||||
|
||||
if row and row['num']:
|
||||
# Get Uniform damage pattern ID
|
||||
query = saveddata_engine.execute("SELECT ID FROM damagePatterns WHERE name = 'Uniform'")
|
||||
rows = query.fetchall()
|
||||
|
||||
if len(rows) == 0:
|
||||
logger.error("Missing uniform damage pattern.")
|
||||
elif len(rows) > 1:
|
||||
logger.error("More than one uniform damage pattern found.")
|
||||
else:
|
||||
uniform_damage_pattern_id = rows[0]['ID']
|
||||
update = saveddata_engine.execute("UPDATE 'fits' SET 'damagePatternID' = ? "
|
||||
"WHERE damagePatternID NOT IN (SELECT ID FROM damagePatterns) OR damagePatternID IS NULL",
|
||||
uniform_damage_pattern_id)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", update.rowcount)
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
logger.error("Failed to connect to database.")
|
||||
|
||||
@staticmethod
|
||||
def OrphanedFitCharacterIDs(saveddata_engine):
|
||||
# Find orphaned character IDs. This solves an issue where the character doesn't exist, but fits reference the pattern.
|
||||
try:
|
||||
logger.debug("Running database cleanup for orphaned characters attached to fits.")
|
||||
results = saveddata_engine.execute("SELECT COUNT(*) AS num FROM fits WHERE characterID NOT IN (SELECT ID FROM characters) OR characterID IS NULL")
|
||||
row = results.first()
|
||||
|
||||
if row['num']:
|
||||
# Get All 5 character ID
|
||||
query = saveddata_engine.execute("SELECT ID FROM characters WHERE name = 'All 5'")
|
||||
rows = query.fetchall()
|
||||
|
||||
if len(rows) == 0:
|
||||
logger.error("Missing 'All 5' character.")
|
||||
elif len(rows) > 1:
|
||||
logger.error("More than one 'All 5' character found.")
|
||||
else:
|
||||
all5_id = rows[0]['ID']
|
||||
update = saveddata_engine.execute("UPDATE 'fits' SET 'characterID' = ? "
|
||||
"WHERE characterID not in (select ID from characters) OR characterID IS NULL",
|
||||
all5_id)
|
||||
logger.error("Database corruption found. Cleaning up %d records.", update.rowcount)
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
logger.error("Failed to connect to database.")
|
||||
@@ -1,65 +0,0 @@
|
||||
# ===============================================================================
|
||||
# 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 sqlalchemy import Table, Column, Integer, ForeignKey, String
|
||||
from sqlalchemy.orm import mapper, relation
|
||||
|
||||
from eos.db import saveddata_meta
|
||||
from eos.db.saveddata.fit import fits_table
|
||||
from eos.types import Fleet, Wing, Squad, Fit
|
||||
|
||||
gangs_table = Table("gangs", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
Column("leaderID", ForeignKey("fits.ID")),
|
||||
Column("boosterID", ForeignKey("fits.ID")),
|
||||
Column("name", String))
|
||||
|
||||
wings_table = Table("wings", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
Column("gangID", ForeignKey("gangs.ID")),
|
||||
Column("boosterID", ForeignKey("fits.ID")),
|
||||
Column("leaderID", ForeignKey("fits.ID")))
|
||||
|
||||
squads_table = Table("squads", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
Column("wingID", ForeignKey("wings.ID")),
|
||||
Column("leaderID", ForeignKey("fits.ID")),
|
||||
Column("boosterID", ForeignKey("fits.ID")))
|
||||
|
||||
squadmembers_table = Table("squadmembers", saveddata_meta,
|
||||
Column("squadID", ForeignKey("squads.ID"), primary_key=True),
|
||||
Column("memberID", ForeignKey("fits.ID"), primary_key=True))
|
||||
|
||||
mapper(Fleet, gangs_table,
|
||||
properties={"wings": relation(Wing, backref="gang"),
|
||||
"leader": relation(Fit, primaryjoin=gangs_table.c.leaderID == fits_table.c.ID),
|
||||
"booster": relation(Fit, primaryjoin=gangs_table.c.boosterID == fits_table.c.ID)})
|
||||
|
||||
mapper(Wing, wings_table,
|
||||
properties={"squads": relation(Squad, backref="wing"),
|
||||
"leader": relation(Fit, primaryjoin=wings_table.c.leaderID == fits_table.c.ID),
|
||||
"booster": relation(Fit, primaryjoin=wings_table.c.boosterID == fits_table.c.ID)})
|
||||
|
||||
mapper(Squad, squads_table,
|
||||
properties={"leader": relation(Fit, primaryjoin=squads_table.c.leaderID == fits_table.c.ID),
|
||||
"booster": relation(Fit, primaryjoin=squads_table.c.boosterID == fits_table.c.ID),
|
||||
"members": relation(Fit,
|
||||
primaryjoin=squads_table.c.ID == squadmembers_table.c.squadID,
|
||||
secondaryjoin=squadmembers_table.c.memberID == fits_table.c.ID,
|
||||
secondary=squadmembers_table)})
|
||||
@@ -17,14 +17,12 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy.sql import and_
|
||||
|
||||
from eos.db import saveddata_session, sd_lock
|
||||
from eos.db.saveddata.fit import projectedFits_table
|
||||
from eos.db.saveddata.fleet import squadmembers_table
|
||||
from eos.db.util import processEager, processWhere
|
||||
from eos.types import *
|
||||
from eos.db import saveddata_session, sd_lock
|
||||
|
||||
from eos.types import *
|
||||
from eos.db.saveddata.fit import projectedFits_table
|
||||
from sqlalchemy.sql import and_
|
||||
import eos.config
|
||||
|
||||
configVal = getattr(eos.config, "saveddataCache", None)
|
||||
@@ -212,52 +210,6 @@ def getFit(lookfor, eager=None):
|
||||
|
||||
return fit
|
||||
|
||||
|
||||
@cachedQuery(Fleet, 1, "fleetID")
|
||||
def getFleet(fleetID, eager=None):
|
||||
if isinstance(fleetID, int):
|
||||
if eager is None:
|
||||
with sd_lock:
|
||||
fleet = saveddata_session.query(Fleet).get(fleetID)
|
||||
else:
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
fleet = saveddata_session.query(Fleet).options(*eager).filter(Fleet.ID == fleetID).first()
|
||||
else:
|
||||
raise TypeError("Need integer as argument")
|
||||
return fleet
|
||||
|
||||
|
||||
@cachedQuery(Wing, 1, "wingID")
|
||||
def getWing(wingID, eager=None):
|
||||
if isinstance(wingID, int):
|
||||
if eager is None:
|
||||
with sd_lock:
|
||||
wing = saveddata_session.query(Wing).get(wingID)
|
||||
else:
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
wing = saveddata_session.query(Wing).options(*eager).filter(Wing.ID == wingID).first()
|
||||
else:
|
||||
raise TypeError("Need integer as argument")
|
||||
return wing
|
||||
|
||||
|
||||
@cachedQuery(Squad, 1, "squadID")
|
||||
def getSquad(squadID, eager=None):
|
||||
if isinstance(squadID, int):
|
||||
if eager is None:
|
||||
with sd_lock:
|
||||
squad = saveddata_session.query(Squad).get(squadID)
|
||||
else:
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
squad = saveddata_session.query(Squad).options(*eager).filter(Fleet.ID == squadID).first()
|
||||
else:
|
||||
raise TypeError("Need integer as argument")
|
||||
return squad
|
||||
|
||||
|
||||
def getFitsWithShip(shipID, ownerID=None, where=None, eager=None):
|
||||
"""
|
||||
Get all the fits using a certain ship.
|
||||
@@ -306,24 +258,31 @@ def countAllFits():
|
||||
return count
|
||||
|
||||
|
||||
def countFitsWithShip(shipID, ownerID=None, where=None, eager=None):
|
||||
def countFitsWithShip(lookfor, ownerID=None, where=None, eager=None):
|
||||
"""
|
||||
Get all the fits using a certain ship.
|
||||
If no user is passed, do this for all users.
|
||||
"""
|
||||
if isinstance(shipID, int):
|
||||
if ownerID is not None and not isinstance(ownerID, int):
|
||||
raise TypeError("OwnerID must be integer")
|
||||
filter = Fit.shipID == shipID
|
||||
if ownerID is not None:
|
||||
filter = and_(filter, Fit.ownerID == ownerID)
|
||||
if ownerID is not None and not isinstance(ownerID, int):
|
||||
raise TypeError("OwnerID must be integer")
|
||||
|
||||
filter = processWhere(filter, where)
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
count = saveddata_session.query(Fit).options(*eager).filter(filter).count()
|
||||
if isinstance(lookfor, int):
|
||||
filter = Fit.shipID == lookfor
|
||||
elif isinstance(lookfor, list):
|
||||
if len(lookfor) == 0:
|
||||
return 0
|
||||
filter = Fit.shipID.in_(lookfor)
|
||||
else:
|
||||
raise TypeError("ShipID must be integer")
|
||||
raise TypeError("You must supply either an integer or ShipID must be integer")
|
||||
|
||||
if ownerID is not None:
|
||||
filter = and_(filter, Fit.ownerID == ownerID)
|
||||
|
||||
filter = processWhere(filter, where)
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
count = saveddata_session.query(Fit).options(*eager).filter(filter).count()
|
||||
|
||||
return count
|
||||
|
||||
|
||||
@@ -334,14 +293,6 @@ def getFitList(eager=None):
|
||||
|
||||
return fits
|
||||
|
||||
|
||||
def getFleetList(eager=None):
|
||||
eager = processEager(eager)
|
||||
with sd_lock:
|
||||
fleets = saveddata_session.query(Fleet).options(*eager).all()
|
||||
return fleets
|
||||
|
||||
|
||||
@cachedQuery(Price, 1, "typeID")
|
||||
def getPrice(typeID):
|
||||
if isinstance(typeID, int):
|
||||
@@ -465,18 +416,6 @@ def searchFits(nameLike, where=None, eager=None):
|
||||
|
||||
return fits
|
||||
|
||||
|
||||
def getSquadsIDsWithFitID(fitID):
|
||||
if isinstance(fitID, int):
|
||||
with sd_lock:
|
||||
squads = saveddata_session.query(squadmembers_table.c.squadID).filter(
|
||||
squadmembers_table.c.memberID == fitID).all()
|
||||
squads = tuple(entry[0] for entry in squads)
|
||||
return squads
|
||||
else:
|
||||
raise TypeError("Need integer as argument")
|
||||
|
||||
|
||||
def getProjectedFits(fitID):
|
||||
if isinstance(fitID, int):
|
||||
with sd_lock:
|
||||
|
||||
@@ -172,10 +172,11 @@ class HandledModuleList(HandledList):
|
||||
self[index] = mod
|
||||
|
||||
def freeSlot(self, slot):
|
||||
for i in range(len(self) - 1, -1, -1):
|
||||
for i in range(len(self)):
|
||||
mod = self[i]
|
||||
if mod.getModifiedItemAttr("subSystemSlot") == slot:
|
||||
del self[i]
|
||||
self.toDummy(i)
|
||||
break
|
||||
|
||||
|
||||
class HandledDroneCargoList(HandledList):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# ammoSpeedMultiplier
|
||||
#
|
||||
# Used by:
|
||||
# Charges from group: Festival Charges (8 of 8)
|
||||
# Charges from group: Festival Charges (9 of 9)
|
||||
# Charges from group: Interdiction Probe (2 of 2)
|
||||
# Charges from group: Survey Probe (3 of 3)
|
||||
type = "passive"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterArmorHpPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 47)
|
||||
# Implants from group: Booster (12 of 48)
|
||||
type = "boosterSideEffect"
|
||||
activeByDefault = False
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterMaxVelocityPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 47)
|
||||
# Implants from group: Booster (12 of 48)
|
||||
type = "boosterSideEffect"
|
||||
activeByDefault = False
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# boosterShieldCapacityPenalty
|
||||
#
|
||||
# Used by:
|
||||
# Implants from group: Booster (12 of 47)
|
||||
# Implants from group: Booster (12 of 48)
|
||||
type = "boosterSideEffect"
|
||||
activeByDefault = False
|
||||
|
||||
|
||||
@@ -2,111 +2,9 @@
|
||||
#
|
||||
# Used by:
|
||||
# Items from market group: Ammunition & Charges > Command Burst Charges (15 of 15)
|
||||
type = "active"
|
||||
|
||||
|
||||
'''
|
||||
Some documentation:
|
||||
When the fit is calculated, we gather up all the gang effects and stick them onto the fit. We don't run the actual
|
||||
effect yet, only give the fit details so that it can run the effect at a later time. We need to do this so that we can
|
||||
only run the strongest effect. When we are done, one of the last things that we do with the fit is to loop through those
|
||||
bonuses and actually run the effect. To do this, we have a special argument passed into the effect handler that tells it
|
||||
which warfareBuffID to run (shouldn't need this right now, but better safe than sorry)
|
||||
'''
|
||||
|
||||
type = "active", "gang"
|
||||
def handler(fit, module, context, **kwargs):
|
||||
print "In chargeBonusWarfareEffect, context: ", context
|
||||
|
||||
def runEffect(id, value):
|
||||
print "RUN EFFECT: ", fit,
|
||||
|
||||
if id == 10: # Shield Burst: Shield Harmonizing: Shield Resistance
|
||||
for damageType in ("Em", "Explosive", "Thermal", "Kinetic"):
|
||||
fit.ship.boostItemAttr("shield%sDamageResonance" % damageType, value)
|
||||
|
||||
if id == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill("Shield Emission Systems"), "capacitorNeed", value)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill("Shield Emission Systems"), "duration", value)
|
||||
|
||||
if id == 12: # Shield Burst: Shield Extension: Shield HP
|
||||
fit.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
|
||||
if id == 13: # Armor Burst: Armor Energizing: Armor Resistance
|
||||
for damageType in ("Em", "Thermal", "Explosive", "Kinetic"):
|
||||
fit.ship.boostItemAttr("armor%sDamageResonance" % damageType, value)
|
||||
|
||||
if id == 14: # Armor Burst: Rapid Repair: Repair Duration/Capacitor
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or mod.item.requiresSkill("Repair Systems"), "capacitorNeed", value)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or mod.item.requiresSkill("Repair Systems"), "duration", value)
|
||||
|
||||
if id == 15: # Armor Burst: Armor Reinforcement: Armor HP
|
||||
fit.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
|
||||
|
||||
if id == 16: # Information Burst: Sensor Optimization: Scan Resolution
|
||||
fit.ship.boostItemAttr("scanResolution", value, stackingPenalties=True)
|
||||
|
||||
if id == 17: # Information Burst: Electronic Superiority: EWAR Range and Strength
|
||||
groups = ("ECM", "Sensor Dampener", "Weapon Disruptor", "Target Painter")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value, stackingPenalties=True)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "falloffEffectiveness", value, stackingPenalties=True)
|
||||
|
||||
for scanType in ("Magnetometric", "Radar", "Ladar", "Gravimetric"):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.nam == "ECM", "scan%sStrengthBonus" % scanType, value, stackingPenalties=True)
|
||||
|
||||
for attr in ("missileVelocityBonus", "explosionDelayBonus", "aoeVelocityBonus", "falloffBonus",
|
||||
"maxRangeBonus", "aoeCloudSizeBonus", "trackingSpeedBonus"):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Weapon Disruptor", attr, value)
|
||||
|
||||
for attr in ("maxTargetRangeBonus", "scanResolutionBonus"):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Sensor Dampener", attr, value)
|
||||
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.gorup.name == "Target Painter", "signatureRadiusBonus", value, stackingPenalties=True)
|
||||
|
||||
if id == 18: # Information Burst: Electronic Hardening: Scan Strength
|
||||
for scanType in ("Gravimetric", "Radar", "Ladar", "Magnetometric"):
|
||||
fit.ship.boostItemAttr("scan%sStrength" % scanType, value, stackingPenalties=True)
|
||||
|
||||
if id == 19: # Information Burst: Electronic Hardening: RSD/RWD Resistance
|
||||
fit.ship.boostItemAttr("sensorDampenerResistance", value)
|
||||
fit.ship.boostItemAttr("weaponDisruptionResistance", value)
|
||||
|
||||
if id == 26: # Information Burst: Sensor Optimization: Targeting Range
|
||||
fit.ship.boostItemAttr("maxTargetRange", value)
|
||||
|
||||
if id == 20: # Skirmish Burst: Evasive Maneuvers: Signature Radius
|
||||
fit.ship.boostItemAttr("signatureRadius", value, stackingPenalties=True)
|
||||
|
||||
if id == 21: # Skirmish Burst: Interdiction Maneuvers: Tackle Range
|
||||
groups = ("Stasis Web", "Warp Scrambler")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value, stackingPenalties=True)
|
||||
|
||||
if id == 22: # Skirmish Burst: Rapid Deployment: AB/MWD Speed Increase
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Afterburner") or mod.item.requiresSkill("High Speed Maneuvering"), "speedFactor", value, stackingPenalties=True)
|
||||
|
||||
if id == 23: # Mining Burst: Mining Laser Field Enhancement: Mining/Survey Range
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill("Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "maxRange", value, stackingPenalties=True)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("CPU Management"), "surveyScanRange", value, stackingPenalties=True)
|
||||
|
||||
if id == 24: # Mining Burst: Mining Laser Optimization: Mining Capacitor/Duration
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill("Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "capacitorNeed", value, stackingPenalties=True)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill("Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "duration", value, stackingPenalties = True)
|
||||
|
||||
if id == 25: # Mining Burst: Mining Equipment Preservation: Crystal Volatility
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"), "crystalVolatilityChance", value, stackingPenalties=True)
|
||||
|
||||
if id == 60: # Skirmish Burst: Evasive Maneuvers: Agility
|
||||
fit.ship.boostItemAttr("agility", value, stackingPenalties=True)
|
||||
|
||||
def handler(fit, module, context):
|
||||
for x in xrange(1, 4):
|
||||
if module.getModifiedChargeAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedChargeAttr("warfareBuff{}Multiplier".format(x))
|
||||
id = module.getModifiedChargeAttr("warfareBuff{}ID".format(x))
|
||||
print "Buff ID: ",id," value: ",value
|
||||
if id:
|
||||
if 'commandRun' not in context:
|
||||
print "Add buffID", id, " to ", fit
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
elif kwargs['warfareBuffID'] is not None and kwargs['warfareBuffID'] == id:
|
||||
print "Running buffID ", kwargs['warfareBuffID'], " on ", fit
|
||||
runEffect(kwargs['warfareBuffID'], value)
|
||||
|
||||
value = module.getModifiedChargeAttr("warfareBuff{}Multiplier".format(x))
|
||||
module.multiplyItemAttr("warfareBuff{}Value".format(x), value)
|
||||
@@ -10,6 +10,7 @@
|
||||
# Ships named like: Stratios (2 of 2)
|
||||
# Subsystems named like: Offensive Covert Reconfiguration (4 of 4)
|
||||
# Ship: Astero
|
||||
# Ship: Rabisu
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
# Ship: Rabisu
|
||||
type = "passive"
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "falloffEffectiveness", src.getModifiedItemAttr("eliteBonusLogistics1"), stackingPenalties=True, skill="Logistics Cruisers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "maxRange", src.getModifiedItemAttr("eliteBonusLogistics1"), stackingPenalties=True, skill="Logistics Cruisers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "falloffEffectiveness", src.getModifiedItemAttr("eliteBonusLogistics1"), skill="Logistics Cruisers")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "maxRange", src.getModifiedItemAttr("eliteBonusLogistics1"), skill="Logistics Cruisers")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# energyWeaponDamageMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Heat Sink (17 of 17)
|
||||
# Modules from group: Heat Sink (18 of 18)
|
||||
# Modules named like: QA Multiship Module Players (4 of 4)
|
||||
# Module: QA Damage Module
|
||||
type = "passive"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# energyWeaponSpeedMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Heat Sink (17 of 17)
|
||||
# Modules from group: Heat Sink (18 of 18)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# hybridWeaponDamageMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Magnetic Field Stabilizer (12 of 12)
|
||||
# Modules from group: Magnetic Field Stabilizer (14 of 14)
|
||||
# Modules named like: QA Multiship Module Players (4 of 4)
|
||||
# Module: QA Damage Module
|
||||
type = "passive"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# hybridWeaponSpeedMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Magnetic Field Stabilizer (12 of 12)
|
||||
# Modules from group: Magnetic Field Stabilizer (14 of 14)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
type = "passive"
|
||||
def handler(fit, src, context):
|
||||
lvl = src.level
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Multiplier", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff4Value", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff3Value", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff2Value", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining Foreman"), "warfareBuff1Value", src.getModifiedItemAttr("commandStrengthBonus") * lvl)
|
||||
@@ -6,16 +6,16 @@ type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"), "shieldCapacity",
|
||||
fit.fighters.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Fighters"), "shieldCapacity",
|
||||
src.getModifiedItemAttr("fighterBonusShieldCapacityPercent"))
|
||||
fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"), "maxVelocity",
|
||||
fit.fighters.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Fighters"), "maxVelocity",
|
||||
src.getModifiedItemAttr("fighterBonusVelocityPercent"), stackingPenalties=True)
|
||||
fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"),
|
||||
fit.fighters.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Fighters"),
|
||||
"fighterAbilityAttackMissileDuration",
|
||||
src.getModifiedItemAttr("fighterBonusROFPercent"), stackingPenalties=True)
|
||||
fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"), "fighterAbilityAttackTurretDuration",
|
||||
fit.fighters.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Fighters"), "fighterAbilityAttackTurretDuration",
|
||||
src.getModifiedItemAttr("fighterBonusROFPercent"), stackingPenalties=True)
|
||||
fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"), "fighterAbilityMissilesDuration",
|
||||
fit.fighters.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Fighters"), "fighterAbilityMissilesDuration",
|
||||
src.getModifiedItemAttr("fighterBonusROFPercent"), stackingPenalties=True)
|
||||
fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"), "shieldRechargeRate",
|
||||
fit.fighters.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Fighters"), "shieldRechargeRate",
|
||||
src.getModifiedItemAttr("fighterBonusShieldRechargePercent"))
|
||||
|
||||
@@ -2,10 +2,24 @@
|
||||
#
|
||||
# Used by:
|
||||
# Variations of module: Armor Command Burst I (2 of 2)
|
||||
type = "active"
|
||||
runTime = "early"
|
||||
|
||||
def handler(fit, module, context):
|
||||
for x in xrange(1, 4):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
module.multiplyChargeAttr("warfareBuff{}Multiplier".format(x), value)
|
||||
'''
|
||||
Some documentation:
|
||||
When the fit is calculated, we gather up all the gang effects and stick them onto the fit. We don't run the actual
|
||||
effect yet, only give the fit details so that it can run the effect at a later time. We need to do this so that we can
|
||||
only run the strongest effect. When we are done, one of the last things that we do with the fit is to loop through those
|
||||
bonuses and actually run the effect. To do this, we have a special argument passed into the effect handler that tells it
|
||||
which warfareBuffID to run (shouldn't need this right now, but better safe than sorry)
|
||||
'''
|
||||
|
||||
type = "active", "gang"
|
||||
def handler(fit, module, context, **kwargs):
|
||||
for x in xrange(1, 5):
|
||||
if module.getModifiedChargeAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
id = module.getModifiedChargeAttr("warfareBuff{}ID".format(x))
|
||||
|
||||
if id:
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
#
|
||||
# Used by:
|
||||
# Variations of module: Information Command Burst I (2 of 2)
|
||||
type = "active"
|
||||
runTime = "early"
|
||||
|
||||
def handler(fit, module, context):
|
||||
for x in xrange(1, 4):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
module.multiplyChargeAttr("warfareBuff{}Multiplier".format(x), value)
|
||||
type = "active", "gang"
|
||||
def handler(fit, module, context, **kwargs):
|
||||
for x in xrange(1, 5):
|
||||
if module.getModifiedChargeAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
id = module.getModifiedChargeAttr("warfareBuff{}ID".format(x))
|
||||
|
||||
if id:
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
@@ -2,10 +2,13 @@
|
||||
#
|
||||
# Used by:
|
||||
# Variations of module: Mining Foreman Burst I (2 of 2)
|
||||
type = "active"
|
||||
runTime = "late"
|
||||
|
||||
def handler(fit, module, context):
|
||||
for x in xrange(1, 4):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
module.multiplyChargeAttr("warfareBuff{}Multiplier".format(x), value)
|
||||
type = "active", "gang"
|
||||
def handler(fit, module, context, **kwargs):
|
||||
for x in xrange(1, 5):
|
||||
if module.getModifiedChargeAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
id = module.getModifiedChargeAttr("warfareBuff{}ID".format(x))
|
||||
|
||||
if id:
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
@@ -2,10 +2,13 @@
|
||||
#
|
||||
# Used by:
|
||||
# Variations of module: Shield Command Burst I (2 of 2)
|
||||
type = "active"
|
||||
runTime = "early"
|
||||
|
||||
def handler(fit, module, context):
|
||||
for x in xrange(1, 4):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
module.multiplyChargeAttr("warfareBuff{}Multiplier".format(x), value)
|
||||
type = "active", "gang"
|
||||
def handler(fit, module, context, **kwargs):
|
||||
for x in xrange(1, 5):
|
||||
if module.getModifiedChargeAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
id = module.getModifiedChargeAttr("warfareBuff{}ID".format(x))
|
||||
|
||||
if id:
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
@@ -2,10 +2,13 @@
|
||||
#
|
||||
# Used by:
|
||||
# Variations of module: Skirmish Command Burst I (2 of 2)
|
||||
type = "active"
|
||||
runTime = "early"
|
||||
|
||||
def handler(fit, module, context):
|
||||
for x in xrange(1, 4):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
module.multiplyChargeAttr("warfareBuff{}Multiplier".format(x), value)
|
||||
type = "active", "gang"
|
||||
def handler(fit, module, context, **kwargs):
|
||||
for x in xrange(1, 5):
|
||||
if module.getModifiedChargeAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
id = module.getModifiedChargeAttr("warfareBuff{}ID".format(x))
|
||||
|
||||
if id:
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
@@ -2,74 +2,16 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Titan Phenomena Generator (4 of 4)
|
||||
|
||||
type = "active", "gang"
|
||||
def handler(fit, module, context, **kwargs):
|
||||
def runEffect(id, value):
|
||||
if id == 39: # Avatar Effect Generator : Capacitor Recharge bonus
|
||||
fit.ship.boostItemAttr("rechargeRate", value, stackingPenalties=True)
|
||||
|
||||
if id == 40: # Avatar Effect Generator : Kinetic resistance bonus
|
||||
for attr in ("armorKineticDamageResonance", "shieldKineticDamageResonance", "hullKineticDamageResonance"):
|
||||
fit.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if id == 41: # Erebus Effect Generator : Armor HP bonus
|
||||
fit.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
|
||||
|
||||
if id == 42: # Leviathan Effect Generator : Shield HP bonus
|
||||
fit.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
|
||||
if id == 43: # Erebus Effect Generator : Explosive resistance bonus
|
||||
for attr in ("armorExplosiveDamageResonance", "shieldExplosiveDamageResonance", "hullExplosiveDamageResonance"):
|
||||
fit.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if id == 44: # Erebus Effect Generator : Thermal resistance penalty
|
||||
for attr in ("armorThermalDamageResonance", "shieldThermalDamageResonance", "hullThermalDamageResonance"):
|
||||
fit.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if id == 45: # Ragnarok Effect Generator : Signature Radius bonus
|
||||
fit.ship.boostItemAttr("signatureRadius", value, stackingPenalties=True)
|
||||
|
||||
if id == 46: # Ragnarok Effect Generator : Thermal resistance bonus
|
||||
for attr in ("armorThermalDamageResonance", "shieldThermalDamageResonance", "hullThermalDamageResonance"):
|
||||
fit.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if id == 47: # Ragnarok Effect Generator : Explosive resistance penaly
|
||||
for attr in ("armorExplosiveDamageResonance", "shieldExplosiveDamageResonance", "hullExplosiveDamageResonance"):
|
||||
fit.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if id == 48: # Leviathan Effect Generator : Shield HP bonus
|
||||
fit.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
|
||||
if id == 49: # Leviathan Effect Generator : EM resistance bonus
|
||||
for attr in ("armorEmDamageResonance", "shieldEmDamageResonance", "hullEmDamageResonance"):
|
||||
fit.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if id == 50: # Leviathan Effect Generator : Kinetic resistance penalty
|
||||
for attr in ("armorKineticDamageResonance", "shieldKineticDamageResonance", "hullKineticDamageResonance"):
|
||||
fit.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if id == 51: # Avatar Effect Generator : Velocity penalty
|
||||
fit.ship.boostItemAttr("maxVelocity", value, stackingPenalties=True)
|
||||
|
||||
if id == 52: # Erebus Effect Generator : Shield RR penalty
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Emission Systems"), "shieldBonus", value, stackingPenalties=True)
|
||||
|
||||
if id == 53: # Leviathan Effect Generator : Armor RR penalty
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "armorDamageAmount", value, stackingPenalties=True)
|
||||
|
||||
if id == 54: # Ragnarok Effect Generator : Laser and Hybrid Optimal penalty
|
||||
groups = ("Energy Weapon", "Hybrid Weapon")
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value, stackingPenalties=True)
|
||||
|
||||
for x in xrange(1, 4):
|
||||
if module.getModifiedChargeAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedChargeAttr("warfareBuff{}Multiplier".format(x))
|
||||
id = module.getModifiedChargeAttr("warfareBuff{}ID".format(x))
|
||||
for x in xrange(1, 5):
|
||||
if module.getModifiedItemAttr("warfareBuff{}ID".format(x)):
|
||||
value = module.getModifiedItemAttr("warfareBuff{}Value".format(x))
|
||||
id = module.getModifiedItemAttr("warfareBuff{}ID".format(x))
|
||||
|
||||
if id:
|
||||
if 'commandRun' not in context:
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
elif kwargs['warfareBuffID'] is not None and kwargs['warfareBuffID'] == id:
|
||||
runEffect(kwargs['warfareBuffID'], value)
|
||||
fit.addCommandBonus(id, value, module, kwargs['effect'])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Missile Launcher Torpedo (22 of 22)
|
||||
# Items from market group: Ship Equipment > Turrets & Bays (428 of 854)
|
||||
# Items from market group: Ship Equipment > Turrets & Bays (428 of 859)
|
||||
# Module: Interdiction Sphere Launcher I
|
||||
type = "overheat"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# projectileWeaponDamageMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Gyrostabilizer (12 of 12)
|
||||
# Modules from group: Gyrostabilizer (13 of 13)
|
||||
# Modules named like: QA Multiship Module Players (4 of 4)
|
||||
# Module: QA Damage Module
|
||||
type = "passive"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# projectileWeaponSpeedMultiply
|
||||
#
|
||||
# Used by:
|
||||
# Modules from group: Gyrostabilizer (12 of 12)
|
||||
# Modules from group: Gyrostabilizer (13 of 13)
|
||||
type = "passive"
|
||||
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
# Ship: Rabisu
|
||||
type = "passive"
|
||||
def handler(fit, src, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "falloffEffectiveness", src.getModifiedItemAttr("roleBonusRepairRange"), stackingPenalties=True)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "maxRange", src.getModifiedItemAttr("roleBonusRepairRange"), stackingPenalties=True)
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "falloffEffectiveness", src.getModifiedItemAttr("roleBonusRepairRange"))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "maxRange", src.getModifiedItemAttr("roleBonusRepairRange"))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# setBonusAsklepian
|
||||
#
|
||||
# Used by:
|
||||
# Implants named like: Asklepian Omega (3 of 3)
|
||||
# Implants named like: Grade Asklepian (16 of 16)
|
||||
# Implants named like: grade Asklepian Omega (2 of 2)
|
||||
runTime = "early"
|
||||
type = "passive"
|
||||
|
||||
|
||||
10
eos/effects/shipbonuscommanddestroyerrole1defenderbonus.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# shipBonusCommandDestroyerRole1DefenderBonus
|
||||
#
|
||||
# Used by:
|
||||
# Ships from group: Command Destroyer (4 of 4)
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Defender Missiles"),
|
||||
"moduleReactivationDelay", ship.getModifiedItemAttr("shipBonusRole1"))
|
||||
@@ -18,5 +18,5 @@ def handler(fit, src, context):
|
||||
fit.fighters.filteredItemBoost(lambda mod: mod.item.requiresSkill("Fighters"),
|
||||
"fighterAbilityMissilesDamageMultiplier",
|
||||
src.getModifiedItemAttr("damageMultiplierBonus") * lvl)
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.group.name == "Mining Drone", "miningDroneAmountPercent",
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill("Mining Drone Operation"), "miningDroneAmountPercent",
|
||||
src.getModifiedItemAttr("miningAmountBonus") * lvl)
|
||||
|
||||
10
eos/effects/skillmultiplierdefendermissilevelocity.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# skillMultiplierDefenderMissileVelocity
|
||||
#
|
||||
# Used by:
|
||||
# Skill: Defender Missiles
|
||||
type = "passive"
|
||||
|
||||
|
||||
def handler(fit, skill, context):
|
||||
fit.modules.filteredChargeBoost(lambda mod: mod.charge.requiresSkill("Defender Missiles"),
|
||||
"maxVelocity", skill.getModifiedItemAttr("missileVelocityBonus") * skill.level)
|
||||
@@ -6,5 +6,28 @@ type = "passive"
|
||||
|
||||
|
||||
def handler(fit, skill, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Burst Projectors",
|
||||
"duration", skill.getModifiedItemAttr("projECMDurationBonus") * skill.level)
|
||||
# We need to make sure that the attribute exists, otherwise we add attributes that don't belong. See #927
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Burst Projector Operation") and
|
||||
mod.item.getAttribute("duration"),
|
||||
"duration",
|
||||
skill.getModifiedItemAttr("projECMDurationBonus") * skill.level)
|
||||
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Burst Projector Operation") and
|
||||
mod.item.getAttribute("durationECMJammerBurstProjector"),
|
||||
"durationECMJammerBurstProjector",
|
||||
skill.getModifiedItemAttr("projECMDurationBonus") * skill.level)
|
||||
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Burst Projector Operation") and
|
||||
mod.item.getAttribute("durationTargetIlluminationBurstProjector"),
|
||||
"durationTargetIlluminationBurstProjector",
|
||||
skill.getModifiedItemAttr("projECMDurationBonus") * skill.level)
|
||||
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Burst Projector Operation") and
|
||||
mod.item.getAttribute("durationSensorDampeningBurstProjector"),
|
||||
"durationSensorDampeningBurstProjector",
|
||||
skill.getModifiedItemAttr("projECMDurationBonus") * skill.level)
|
||||
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Burst Projector Operation") and
|
||||
mod.item.getAttribute("durationWeaponDisruptionBurstProjector"),
|
||||
"durationWeaponDisruptionBurstProjector",
|
||||
skill.getModifiedItemAttr("projECMDurationBonus") * skill.level)
|
||||
|
||||
@@ -10,4 +10,4 @@ def handler(fit, container, context):
|
||||
and container.state >= State.ACTIVE) or hasattr(container, "amountActive")):
|
||||
amount = container.getModifiedItemAttr("energyNeutralizerAmount")
|
||||
time = container.getModifiedItemAttr("duration")
|
||||
fit.addDrain(time, amount, 0)
|
||||
fit.addDrain(container, time, amount, 0)
|
||||
|
||||
@@ -3,4 +3,5 @@ type = "passive"
|
||||
|
||||
|
||||
def handler(fit, src, context):
|
||||
fit.ship.increaseItemAttr("maxLockedTargets", src.getModifiedItemAttr("structureRigMaxTargetBonus"))
|
||||
fit.extraAttributes.increase("maxTargetsLockedFromSkills", src.getModifiedItemAttr("structureRigMaxTargetBonus"))
|
||||
|
||||
|
||||
@@ -4,9 +4,27 @@
|
||||
# Modules from group: Missile Launcher Heavy (12 of 12)
|
||||
# Modules from group: Missile Launcher Rocket (15 of 15)
|
||||
# Modules named like: Launcher (151 of 151)
|
||||
type = 'active'
|
||||
type = 'active', "projected"
|
||||
|
||||
|
||||
def handler(fit, module, context):
|
||||
def handler(fit, src, context):
|
||||
# Set reload time to 10 seconds
|
||||
module.reloadTime = 10000
|
||||
src.reloadTime = 10000
|
||||
|
||||
if "projected" in context:
|
||||
if src.item.group.name == 'Missile Launcher Bomb':
|
||||
# Bomb Launcher Cooldown Timer
|
||||
moduleReactivationDelay = src.getModifiedItemAttr("moduleReactivationDelay")
|
||||
|
||||
# Void and Focused Void Bombs
|
||||
neutAmount = src.getModifiedChargeAttr("energyNeutralizerAmount")
|
||||
|
||||
if moduleReactivationDelay and neutAmount:
|
||||
fit.addDrain(src, moduleReactivationDelay, neutAmount, 0)
|
||||
|
||||
# Lockbreaker Bombs
|
||||
ecmStrengthBonus = src.getModifiedChargeAttr("scan{0}StrengthBonus".format(fit.scanType))
|
||||
|
||||
if ecmStrengthBonus:
|
||||
strModifier = 1 - ecmStrengthBonus / fit.scanStrength
|
||||
fit.ecmProjectedStr *= strModifier
|
||||
|
||||
@@ -134,7 +134,6 @@ class Fit(object):
|
||||
self.__capRecharge = None
|
||||
self.__calculatedTargets = []
|
||||
self.factorReload = False
|
||||
self.fleet = None
|
||||
self.boostsFits = set()
|
||||
self.gangBoosts = None
|
||||
self.ecmProjectedStr = 1
|
||||
@@ -449,9 +448,7 @@ class Fit(object):
|
||||
# oh fuck this is so janky
|
||||
# @todo should we pass in min/max to this function, or is abs okay?
|
||||
# (abs is old method, ccp now provides the aggregate function in their data)
|
||||
print "Add command bonus: ", warfareBuffID, " - value: ", value
|
||||
|
||||
if warfareBuffID not in self.commandBonuses or abs(self.commandBonuses[warfareBuffID][0]) < abs(value):
|
||||
if warfareBuffID not in self.commandBonuses or abs(self.commandBonuses[warfareBuffID][1]) < abs(value):
|
||||
self.commandBonuses[warfareBuffID] = (runTime, value, module, effect)
|
||||
|
||||
def __runCommandBoosts(self, runTime="normal"):
|
||||
@@ -463,31 +460,176 @@ class Fit(object):
|
||||
if runTime != effect_runTime:
|
||||
continue
|
||||
|
||||
context = ("commandRun", thing.__class__.__name__.lower())
|
||||
if isinstance(thing, Module):
|
||||
# This should always be a gang effect, otherwise it wouldn't be added to commandBonuses
|
||||
# @todo: Check this
|
||||
if effect.isType("gang"):
|
||||
# todo: ensure that these are run with the module is active only
|
||||
context += ("commandRun",)
|
||||
self.register(thing)
|
||||
effect.handler(self, thing, context, warfareBuffID = warfareBuffID)
|
||||
# This should always be a gang effect, otherwise it wouldn't be added to commandBonuses
|
||||
# @todo: Check this
|
||||
if effect.isType("gang"):
|
||||
self.register(thing)
|
||||
|
||||
# if effect.isType("offline") or (effect.isType("passive") and thing.state >= State.ONLINE) or \
|
||||
# (effect.isType("active") and thing.state >= State.ACTIVE):
|
||||
# # Run effect, and get proper bonuses applied
|
||||
# try:
|
||||
# self.register(thing)
|
||||
# effect.handler(self, thing, context)
|
||||
# except:
|
||||
# pass
|
||||
else:
|
||||
# Run effect, and get proper bonuses applied
|
||||
try:
|
||||
self.register(thing)
|
||||
effect.handler(self, thing, context)
|
||||
except:
|
||||
pass
|
||||
if warfareBuffID == 10: # Shield Burst: Shield Harmonizing: Shield Resistance
|
||||
for damageType in ("Em", "Explosive", "Thermal", "Kinetic"):
|
||||
self.ship.boostItemAttr("shield%sDamageResonance" % damageType, value)
|
||||
|
||||
if warfareBuffID == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
|
||||
"Shield Emission Systems"), "capacitorNeed", value)
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
|
||||
"Shield Emission Systems"), "duration", value)
|
||||
|
||||
if warfareBuffID == 12: # Shield Burst: Shield Extension: Shield HP
|
||||
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 13: # Armor Burst: Armor Energizing: Armor Resistance
|
||||
for damageType in ("Em", "Thermal", "Explosive", "Kinetic"):
|
||||
self.ship.boostItemAttr("armor%sDamageResonance" % damageType, value)
|
||||
|
||||
if warfareBuffID == 14: # Armor Burst: Rapid Repair: Repair Duration/Capacitor
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill(
|
||||
"Remote Armor Repair Systems") or mod.item.requiresSkill("Repair Systems"),
|
||||
"capacitorNeed", value)
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill(
|
||||
"Remote Armor Repair Systems") or mod.item.requiresSkill("Repair Systems"), "duration",
|
||||
value)
|
||||
|
||||
if warfareBuffID == 15: # Armor Burst: Armor Reinforcement: Armor HP
|
||||
self.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 16: # Information Burst: Sensor Optimization: Scan Resolution
|
||||
self.ship.boostItemAttr("scanResolution", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 17: # Information Burst: Electronic Superiority: EWAR Range and Strength
|
||||
groups = ("ECM", "Sensor Dampener", "Weapon Disruptor", "Target Painter")
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value,
|
||||
stackingPenalties=True)
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups,
|
||||
"falloffEffectiveness", value, stackingPenalties=True)
|
||||
|
||||
for scanType in ("Magnetometric", "Radar", "Ladar", "Gravimetric"):
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.group.name == "ECM",
|
||||
"scan%sStrengthBonus" % scanType, value,
|
||||
stackingPenalties=True)
|
||||
|
||||
for attr in (
|
||||
"missileVelocityBonus", "explosionDelayBonus", "aoeVelocityBonus", "falloffBonus",
|
||||
"maxRangeBonus", "aoeCloudSizeBonus", "trackingSpeedBonus"):
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Weapon Disruptor",
|
||||
attr, value)
|
||||
|
||||
for attr in ("maxTargetRangeBonus", "scanResolutionBonus"):
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.group.name == "Sensor Dampener",
|
||||
attr, value)
|
||||
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.gorup.name == "Target Painter",
|
||||
"signatureRadiusBonus", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 18: # Information Burst: Electronic Hardening: Scan Strength
|
||||
for scanType in ("Gravimetric", "Radar", "Ladar", "Magnetometric"):
|
||||
self.ship.boostItemAttr("scan%sStrength" % scanType, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 19: # Information Burst: Electronic Hardening: RSD/RWD Resistance
|
||||
self.ship.boostItemAttr("sensorDampenerResistance", value)
|
||||
self.ship.boostItemAttr("weaponDisruptionResistance", value)
|
||||
|
||||
if warfareBuffID == 26: # Information Burst: Sensor Optimization: Targeting Range
|
||||
self.ship.boostItemAttr("maxTargetRange", value)
|
||||
|
||||
if warfareBuffID == 20: # Skirmish Burst: Evasive Maneuvers: Signature Radius
|
||||
self.ship.boostItemAttr("signatureRadius", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 21: # Skirmish Burst: Interdiction Maneuvers: Tackle Range
|
||||
groups = ("Stasis Web", "Warp Scrambler")
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value,
|
||||
stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 22: # Skirmish Burst: Rapid Deployment: AB/MWD Speed Increase
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Afterburner") or mod.item.requiresSkill(
|
||||
"High Speed Maneuvering"), "speedFactor", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 23: # Mining Burst: Mining Laser Field Enhancement: Mining/Survey Range
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
|
||||
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "maxRange",
|
||||
value, stackingPenalties=True)
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("CPU Management"),
|
||||
"surveyScanRange", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 24: # Mining Burst: Mining Laser Optimization: Mining Capacitor/Duration
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
|
||||
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"),
|
||||
"capacitorNeed", value, stackingPenalties=True)
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Mining") or mod.item.requiresSkill(
|
||||
"Ice Harvesting") or mod.item.requiresSkill("Gas Cloud Harvesting"), "duration",
|
||||
value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 25: # Mining Burst: Mining Equipment Preservation: Crystal Volatility
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Mining"),
|
||||
"crystalVolatilityChance", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 60: # Skirmish Burst: Evasive Maneuvers: Agility
|
||||
self.ship.boostItemAttr("agility", value, stackingPenalties=True)
|
||||
|
||||
# Titan effects
|
||||
|
||||
if warfareBuffID == 39: # Avatar Effect Generator : Capacitor Recharge bonus
|
||||
self.ship.boostItemAttr("rechargeRate", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 40: # Avatar Effect Generator : Kinetic resistance bonus
|
||||
for attr in ("armorKineticDamageResonance", "shieldKineticDamageResonance", "kineticDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 41: # Avatar Effect Generator : EM resistance penalty
|
||||
for attr in ("armorEmDamageResonance", "shieldEmDamageResonance", "emDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 42: # Erebus Effect Generator : Armor HP bonus
|
||||
self.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 43: # Erebus Effect Generator : Explosive resistance bonus
|
||||
for attr in ("armorExplosiveDamageResonance", "shieldExplosiveDamageResonance", "explosiveDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 44: # Erebus Effect Generator : Thermal resistance penalty
|
||||
for attr in ("armorThermalDamageResonance", "shieldThermalDamageResonance", "thermalDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 45: # Ragnarok Effect Generator : Signature Radius bonus
|
||||
self.ship.boostItemAttr("signatureRadius", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 46: # Ragnarok Effect Generator : Thermal resistance bonus
|
||||
for attr in ("armorThermalDamageResonance", "shieldThermalDamageResonance", "thermalDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 47: # Ragnarok Effect Generator : Explosive resistance penaly
|
||||
for attr in ("armorExplosiveDamageResonance", "shieldExplosiveDamageResonance", "explosiveDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 48: # Leviathan Effect Generator : Shield HP bonus
|
||||
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 49: # Leviathan Effect Generator : EM resistance bonus
|
||||
for attr in ("armorEmDamageResonance", "shieldEmDamageResonance", "emDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 50: # Leviathan Effect Generator : Kinetic resistance penalty
|
||||
for attr in ("armorKineticDamageResonance", "shieldKineticDamageResonance", "kineticDamageResonance"):
|
||||
self.ship.boostItemAttr(attr, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 51: # Avatar Effect Generator : Velocity penalty
|
||||
self.ship.boostItemAttr("maxVelocity", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 52: # Erebus Effect Generator : Shield RR penalty
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Shield Emission Systems"), "shieldBonus", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 53: # Leviathan Effect Generator : Armor RR penalty
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems"), "armorDamageAmount", value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 54: # Ragnarok Effect Generator : Laser and Hybrid Optimal penalty
|
||||
groups = ("Energy Weapon", "Hybrid Weapon")
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.group.name in groups, "maxRange", value, stackingPenalties=True)
|
||||
|
||||
del self.commandBonuses[warfareBuffID]
|
||||
|
||||
@@ -506,7 +648,6 @@ class Fit(object):
|
||||
# Don't inspect this, we genuinely want to reassign self
|
||||
# noinspection PyMethodFirstArgAssignment
|
||||
self = copy.deepcopy(self)
|
||||
self.fleet = copied.fleet
|
||||
logger.debug("Handling self projection - making shadow copy of fit. %r => %r", copied, self)
|
||||
# we delete the fit because when we copy a fit, flush() is
|
||||
# called to properly handle projection updates. However, we do
|
||||
@@ -514,31 +655,11 @@ class Fit(object):
|
||||
eos.db.saveddata_session.delete(self)
|
||||
|
||||
if self.commandFits and not withBoosters:
|
||||
print "Calculatate command fits and apply to fit"
|
||||
for fit in self.commandFits:
|
||||
if self == fit:
|
||||
print "nope"
|
||||
continue
|
||||
print "calculating ", fit
|
||||
|
||||
fit.calculateModifiedAttributes(self, True)
|
||||
#
|
||||
# for thing in chain(fit.modules, fit.implants, fit.character.skills, (fit.ship,)):
|
||||
# if thing.item is None:
|
||||
# continue
|
||||
# for effect in thing.item.effects.itervalues():
|
||||
# # And check if it actually has gang boosting effects
|
||||
# if effect.isType("gang"):
|
||||
# effect.handler(self, thing, ("commandRun"))
|
||||
|
||||
# if self.fleet is not None and withBoosters is True:
|
||||
# logger.debug("Fleet is set, gathering gang boosts")
|
||||
#
|
||||
# self.gangBoosts = self.fleet.recalculateLinear(withBoosters=withBoosters)
|
||||
#
|
||||
# timer.checkpoint("Done calculating gang boosts for %r"%self)
|
||||
|
||||
# elif self.fleet is None:
|
||||
# self.gangBoosts = None
|
||||
|
||||
# If we're not explicitly asked to project fit onto something,
|
||||
# set self as target fit
|
||||
@@ -625,7 +746,7 @@ class Fit(object):
|
||||
self.__calculated = True
|
||||
|
||||
# Only apply projected fits if fit it not projected itself.
|
||||
if not projected:
|
||||
if not projected and not withBoosters:
|
||||
for fit in self.projectedFits:
|
||||
if fit.getProjectionInfo(self.ID).active:
|
||||
fit.calculateModifiedAttributes(self, withBoosters=withBoosters, dirtyStorage=dirtyStorage)
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
# ===============================================================================
|
||||
# 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 copy import deepcopy
|
||||
from itertools import chain
|
||||
|
||||
from eos.types import Skill, Module, Ship
|
||||
|
||||
|
||||
class Fleet(object):
|
||||
def calculateModifiedAttributes(self):
|
||||
# Make sure ALL fits in the gang have been calculated
|
||||
for c in chain(self.wings, (self.leader,)):
|
||||
if c is not None:
|
||||
c.calculateModifiedAttributes()
|
||||
|
||||
leader = self.leader
|
||||
self.booster = booster = self.booster if self.booster is not None else leader
|
||||
self.broken = False
|
||||
self.store = store = Store()
|
||||
store.set(booster, "fleet")
|
||||
# Go all the way down for each subtree we have.
|
||||
for wing in self.wings:
|
||||
wing.calculateGangBonusses(store)
|
||||
|
||||
# Check skill requirements and wing amount to see if we break or not
|
||||
if len(self.wings) == 0 or leader is None or leader.character is None or leader.character.getSkill(
|
||||
"Fleet Command").level < len(self.wings):
|
||||
self.broken = True
|
||||
|
||||
# Now calculate our own if we aren't broken
|
||||
if not self.broken:
|
||||
# We only get our own bonuses *Sadface*
|
||||
store.apply(leader, "fleet")
|
||||
|
||||
def recalculateLinear(self, withBoosters=True, dirtyStorage=None):
|
||||
self.store = Store()
|
||||
self.linearBoosts = {}
|
||||
if withBoosters is True:
|
||||
if self.leader is not None and self.leader.character is not None and self.leader.character.getSkill(
|
||||
"Fleet Command").level >= 1:
|
||||
self.leader.boostsFits.add(self.wings[0].squads[0].members[0].ID)
|
||||
self.leader.calculateModifiedAttributes()
|
||||
self.store.set(self.leader, "squad", clearingUpdate=True)
|
||||
else:
|
||||
self.store = Store()
|
||||
if self.leader is not None:
|
||||
try:
|
||||
self.leader.boostsFits.remove(self.wings[0].squads[0].members[0].ID)
|
||||
except KeyError:
|
||||
pass
|
||||
self.wings[0].recalculateLinear(self.store, withBoosters=withBoosters, dirtyStorage=dirtyStorage)
|
||||
return self.linearBoosts
|
||||
|
||||
def count(self):
|
||||
total = 0
|
||||
for wing in self.wings:
|
||||
total += wing.count()
|
||||
|
||||
return total
|
||||
|
||||
def extend(self):
|
||||
self.wings.append(Wing())
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
copy = Fleet()
|
||||
copy.name = self.name
|
||||
copy.booster = deepcopy(self.booster)
|
||||
copy.leader = deepcopy(self.leader)
|
||||
for wing in self.wings:
|
||||
copy.wings.append(deepcopy(wing))
|
||||
|
||||
return copy
|
||||
|
||||
|
||||
class Wing(object):
|
||||
def calculateModifiedAttributes(self):
|
||||
for c in chain(self.squads, (self.leader,)):
|
||||
if c is not None:
|
||||
c.calculateModifiedAttributes()
|
||||
|
||||
def calculateGangBonusses(self, store):
|
||||
self.broken = False
|
||||
leader = self.leader
|
||||
self.booster = booster = self.booster if self.booster is not None else leader
|
||||
|
||||
store.set(booster, "wing")
|
||||
|
||||
# ALWAYS move down
|
||||
for squad in self.squads:
|
||||
squad.calculateGangBonusses(store)
|
||||
|
||||
# Check skill requirements and squad amount to see if we break or not
|
||||
if len(self.squads) == 0 or leader is None or leader.character is None or leader.character.getSkill(
|
||||
"Wing Command").level < len(self.squads):
|
||||
self.broken = True
|
||||
|
||||
# Check if we aren't broken, if we aren't, boost
|
||||
if not self.broken:
|
||||
store.apply(leader, "wing")
|
||||
else:
|
||||
# We broke, don't go up
|
||||
self.gang.broken = True
|
||||
|
||||
def recalculateLinear(self, store, withBoosters=True, dirtyStorage=None):
|
||||
if withBoosters is True:
|
||||
if self.leader is not None and self.leader.character is not None and self.leader.character.getSkill(
|
||||
"Wing Command").level >= 1:
|
||||
self.leader.boostsFits.add(self.squads[0].members[0].ID)
|
||||
self.leader.calculateModifiedAttributes()
|
||||
store.set(self.leader, "squad", clearingUpdate=False)
|
||||
else:
|
||||
store = Store()
|
||||
if self.gang.leader is not None:
|
||||
try:
|
||||
self.gang.leader.boostsFits.remove(self.squads[0].members[0].ID)
|
||||
except KeyError:
|
||||
pass
|
||||
if self.leader is not None:
|
||||
try:
|
||||
self.leader.boostsFits.remove(self.squads[0].members[0].ID)
|
||||
except KeyError:
|
||||
pass
|
||||
self.squads[0].recalculateLinear(store, withBoosters=withBoosters, dirtyStorage=dirtyStorage)
|
||||
|
||||
def count(self):
|
||||
total = 0 if self.leader is None else 1
|
||||
for squad in self.squads:
|
||||
total += squad.count()
|
||||
|
||||
return total
|
||||
|
||||
def extend(self):
|
||||
self.squads.append(Squad())
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
copy = Wing()
|
||||
copy.booster = deepcopy(self.booster)
|
||||
copy.leader = deepcopy(self.leader)
|
||||
for squad in self.squads:
|
||||
copy.squads.append(deepcopy(squad))
|
||||
|
||||
return copy
|
||||
|
||||
|
||||
class Squad(object):
|
||||
def calculateModifiedAttributes(self):
|
||||
for member in self.members:
|
||||
member.calculateModifiedAttributes()
|
||||
|
||||
def calculateGangBonusses(self, store):
|
||||
self.broken = False
|
||||
leader = self.leader
|
||||
self.booster = booster = self.booster if self.booster is not None else leader
|
||||
store.set(booster, "squad")
|
||||
|
||||
# Check skill requirements and squad size to see if we break or not
|
||||
if len(self.members) <= 0 or leader is None or leader.character is None or leader.character.getSkill(
|
||||
"Leadership").level * 2 < len(self.members):
|
||||
self.broken = True
|
||||
|
||||
if not self.broken:
|
||||
for member in self.members:
|
||||
store.apply(member, "squad")
|
||||
else:
|
||||
self.wing.broken = True
|
||||
|
||||
def recalculateLinear(self, store, withBoosters=True, dirtyStorage=None):
|
||||
if withBoosters is True:
|
||||
if self.leader is not None and self.leader.character is not None and self.leader.character.getSkill(
|
||||
"Leadership").level >= 1:
|
||||
self.leader.boostsFits.add(self.members[0].ID)
|
||||
self.leader.calculateModifiedAttributes(dirtyStorage=dirtyStorage)
|
||||
store.set(self.leader, "squad", clearingUpdate=False)
|
||||
else:
|
||||
store = Store()
|
||||
if self.leader is not None:
|
||||
try:
|
||||
self.leader.boostsFits.remove(self.members[0].ID)
|
||||
except KeyError:
|
||||
pass
|
||||
if self.wing.leader is not None:
|
||||
try:
|
||||
self.wing.leader.boostsFits.remove(self.members[0].ID)
|
||||
except KeyError:
|
||||
pass
|
||||
if self.wing.gang.leader is not None:
|
||||
try:
|
||||
self.wing.gang.leader.boostsFits.remove(self.members[0].ID)
|
||||
except KeyError:
|
||||
pass
|
||||
if getattr(self.wing.gang, "linearBoosts", None) is None:
|
||||
self.wing.gang.linearBoosts = {}
|
||||
dict = store.bonuses["squad"]
|
||||
for boostedAttr, boostInfoList in dict.iteritems():
|
||||
for boostInfo in boostInfoList:
|
||||
effect, thing = boostInfo
|
||||
# Get current boost value for given attribute, use 0 as fallback if
|
||||
# no boosts applied yet
|
||||
currBoostAmount = self.wing.gang.linearBoosts.get(boostedAttr, (0,))[0]
|
||||
# Attribute name which is used to get boost value
|
||||
newBoostAttr = effect.getattr("gangBonus") or "commandBonus"
|
||||
# Get boost amount for current boost
|
||||
newBoostAmount = thing.getModifiedItemAttr(newBoostAttr) or 0
|
||||
# Skill used to modify the gang bonus (for purposes of comparing old vs new)
|
||||
newBoostSkill = effect.getattr("gangBonusSkill")
|
||||
# If skill takes part in gang boosting, multiply by skill level
|
||||
if type(thing) == Skill:
|
||||
newBoostAmount *= thing.level
|
||||
# boost the gang bonus based on skill noted in effect file
|
||||
if newBoostSkill:
|
||||
newBoostAmount *= thing.parent.character.getSkill(newBoostSkill).level
|
||||
# If new boost is more powerful, replace older one with it
|
||||
if abs(newBoostAmount) > abs(currBoostAmount):
|
||||
self.wing.gang.linearBoosts[boostedAttr] = (newBoostAmount, boostInfo)
|
||||
|
||||
def count(self):
|
||||
return len(self.members)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
copy = Squad()
|
||||
copy.booster = deepcopy(self.booster)
|
||||
copy.leader = deepcopy(self.leader)
|
||||
for member in self.members:
|
||||
copy.members.append(deepcopy(member))
|
||||
|
||||
return copy
|
||||
|
||||
|
||||
class Store(object):
|
||||
def __init__(self):
|
||||
# Container for gang boosters and their respective bonuses, three-layered
|
||||
self.bonuses = {}
|
||||
for dictType in ("fleet", "wing", "squad"):
|
||||
self.bonuses[dictType] = {}
|
||||
# Container for boosted fits and corresponding boosts applied onto them
|
||||
self.boosts = {}
|
||||
|
||||
def set(self, fitBooster, layer, clearingUpdate=True):
|
||||
"""Add all gang boosts of given fit for given layer to boost store"""
|
||||
if fitBooster is None:
|
||||
return
|
||||
|
||||
# This dict contains all bonuses for specified layer
|
||||
dict = self.bonuses[layer]
|
||||
if clearingUpdate is True:
|
||||
# Clear existing bonuses
|
||||
dict.clear()
|
||||
|
||||
# Go through everything which can be used as gang booster
|
||||
for thing in chain(fitBooster.modules, fitBooster.implants, fitBooster.character.skills, (fitBooster.ship,)):
|
||||
if thing.item is None:
|
||||
continue
|
||||
for effect in thing.item.effects.itervalues():
|
||||
# And check if it actually has gang boosting effects
|
||||
if effect.isType("gang"):
|
||||
# Attribute which is boosted
|
||||
boostedAttr = effect.getattr("gangBoost")
|
||||
# List which contains all bonuses for given attribute for given layer
|
||||
l = dict.get(boostedAttr)
|
||||
# If there was no list, create it
|
||||
if l is None:
|
||||
l = dict[boostedAttr] = []
|
||||
# And append effect which is used to boost stuff and carrier of this effect
|
||||
l.append((effect, thing))
|
||||
|
||||
contextMap = {Skill: "skill",
|
||||
Ship: "ship",
|
||||
Module: "module"}
|
||||
|
||||
def apply(self, fitBoosted, layer):
|
||||
"""Applies all boosts onto given fit for given layer"""
|
||||
if fitBoosted is None:
|
||||
return
|
||||
# Boosts dict contains all bonuses applied onto given fit
|
||||
self.boosts[fitBoosted] = boosts = {}
|
||||
# Go through all bonuses for given layer, and find highest one per boosted attribute
|
||||
for currLayer in ("fleet", "wing", "squad"):
|
||||
# Dictionary with boosts for given layer
|
||||
dict = self.bonuses[currLayer]
|
||||
for boostedAttr, boostInfoList in dict.iteritems():
|
||||
for boostInfo in boostInfoList:
|
||||
effect, thing = boostInfo
|
||||
# Get current boost value for given attribute, use 0 as fallback if
|
||||
# no boosts applied yet
|
||||
currBoostAmount = boosts.get(boostedAttr, (0,))[0]
|
||||
# Attribute name which is used to get boost value
|
||||
newBoostAttr = effect.getattr("gangBonus") or "commandBonus"
|
||||
# Get boost amount for current boost
|
||||
newBoostAmount = thing.getModifiedItemAttr(newBoostAttr) or 0
|
||||
# Skill used to modify the gang bonus (for purposes of comparing old vs new)
|
||||
newBoostSkill = effect.getattr("gangBonusSkill")
|
||||
# If skill takes part in gang boosting, multiply by skill level
|
||||
if type(thing) == Skill:
|
||||
newBoostAmount *= thing.level
|
||||
# boost the gang bonus based on skill noted in effect file
|
||||
if newBoostSkill:
|
||||
newBoostAmount *= thing.parent.character.getSkill(newBoostSkill).level
|
||||
# If new boost is more powerful, replace older one with it
|
||||
if abs(newBoostAmount) > abs(currBoostAmount):
|
||||
boosts[boostedAttr] = (newBoostAmount, boostInfo)
|
||||
|
||||
# Don't look further down then current layer, wing commanders don't get squad bonuses and all that
|
||||
if layer == currLayer:
|
||||
break
|
||||
|
||||
self.modify(fitBoosted)
|
||||
|
||||
def getBoosts(self, fit):
|
||||
"""Return all boosts applied onto given fit"""
|
||||
return self.boosts.get(fit)
|
||||
|
||||
def modify(self, fitBoosted):
|
||||
# Get all boosts which should be applied onto current fit
|
||||
boosts = self.getBoosts(fitBoosted)
|
||||
# Now we got it all figured out, actually do the useful part of all this
|
||||
for name, info in boosts.iteritems():
|
||||
# Unpack all data required to run effect properly
|
||||
effect, thing = info[1]
|
||||
context = ("gang", self.contextMap[type(thing)])
|
||||
# Run effect, and get proper bonuses applied
|
||||
try:
|
||||
effect.handler(fitBoosted, thing, context)
|
||||
except:
|
||||
pass
|
||||
@@ -201,6 +201,11 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
else:
|
||||
return self.__chargeCycles
|
||||
|
||||
@property
|
||||
def modPosition(self):
|
||||
if self.owner:
|
||||
return self.owner.modules.index(self)
|
||||
|
||||
@property
|
||||
def hpBeforeReload(self):
|
||||
"""
|
||||
@@ -265,7 +270,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
flightTime = self.getModifiedChargeAttr("explosionDelay") / 1000.0
|
||||
mass = self.getModifiedChargeAttr("mass")
|
||||
agility = self.getModifiedChargeAttr("agility")
|
||||
if maxVelocity and flightTime and mass and agility:
|
||||
if maxVelocity and (flightTime or mass or agility):
|
||||
accelTime = min(flightTime, mass * agility / 1000000)
|
||||
# Average distance done during acceleration
|
||||
duringAcceleration = maxVelocity / 2 * accelTime
|
||||
@@ -655,10 +660,14 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
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 ((projected and effect.isType("projected")) or not projected)\
|
||||
and ((gang and effect.isType("gang")) or not gang):
|
||||
effect.handler(fit, self, context)
|
||||
try:
|
||||
effect.handler(fit, self, context, effect=effect)
|
||||
except:
|
||||
effect.handler(fit, self, context)
|
||||
|
||||
@property
|
||||
def cycleTime(self):
|
||||
|
||||
@@ -40,7 +40,6 @@ from eos.saveddata.implantSet import ImplantSet
|
||||
from eos.saveddata.booster import Booster
|
||||
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
|
||||
|
||||
|
||||
5
fun.py
Normal file
@@ -0,0 +1,5 @@
|
||||
problem 15
|
||||
|
||||
number of moves: XxY
|
||||
|
||||
each block added introduces two possible moves
|
||||
@@ -29,7 +29,6 @@ from gui.projectedView import ProjectedView
|
||||
from gui.commandView import CommandView
|
||||
from gui.notesView import NotesView
|
||||
from gui.pyfatogglepanel import TogglePanel
|
||||
from gui.gangView import GangView
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
import gui.chromeTabs
|
||||
|
||||
@@ -1 +1 @@
|
||||
__all__ = ["fittingView", "fleetView", "implantEditor"]
|
||||
__all__ = ["fittingView", "implantEditor"]
|
||||
|
||||
@@ -224,7 +224,7 @@ class FittingView(d.Display):
|
||||
|
||||
if row != -1 and row not in self.blanks:
|
||||
data = wx.PyTextDataObject()
|
||||
data.SetText("fitting:"+str(self.mods[row].position))
|
||||
data.SetText("fitting:"+str(self.mods[row].modPosition))
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
@@ -356,7 +356,7 @@ class FittingView(d.Display):
|
||||
if dstRow != -1 and dstRow not in self.blanks:
|
||||
sFit = service.Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
moduleChanged = sFit.changeModule(fitID, self.mods[dstRow].position, srcIdx)
|
||||
moduleChanged = sFit.changeModule(fitID, self.mods[dstRow].modPosition, srcIdx)
|
||||
if moduleChanged is None:
|
||||
# the new module doesn't fit in specified slot, try to simply append it
|
||||
wx.PostEvent(self.mainFrame, gui.marketBrowser.ItemSelected(itemID=srcIdx))
|
||||
@@ -371,7 +371,7 @@ class FittingView(d.Display):
|
||||
module = self.mods[dstRow]
|
||||
|
||||
sFit = service.Fit.getInstance()
|
||||
sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.position, srcIdx, mstate.CmdDown() and module.isEmpty)
|
||||
sFit.moveCargoToModule(self.mainFrame.getActiveFit(), module.modPosition, srcIdx, mstate.CmdDown() and module.isEmpty)
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
|
||||
|
||||
@@ -389,6 +389,7 @@ class FittingView(d.Display):
|
||||
dstRow, _ = self.HitTest((x, y))
|
||||
|
||||
if dstRow != -1 and dstRow not in self.blanks:
|
||||
|
||||
mod1 = fit.modules[srcIdx]
|
||||
mod2 = self.mods[dstRow]
|
||||
|
||||
@@ -397,9 +398,9 @@ class FittingView(d.Display):
|
||||
return
|
||||
|
||||
if clone and mod2.isEmpty:
|
||||
sFit.cloneModule(self.mainFrame.getActiveFit(), mod1.position, mod2.position)
|
||||
sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition)
|
||||
else:
|
||||
sFit.swapModules(self.mainFrame.getActiveFit(), mod1.position, mod2.position)
|
||||
sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition)
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
|
||||
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
import wx.gizmos
|
||||
import gui.fleetBrowser
|
||||
import service
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
|
||||
#Tab spawning handler
|
||||
class FleetSpawner(gui.multiSwitch.TabSpawner):
|
||||
def __init__(self, multiSwitch):
|
||||
self.multiSwitch = multiSwitch
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
mainFrame.Bind(gui.fleetBrowser.EVT_FLEET_SELECTED, self.fleetSelected)
|
||||
|
||||
def fleetSelected(self, event):
|
||||
if self.multiSwitch.GetPageCount() == 0:
|
||||
self.multiSwitch.AddPage(wx.Panel(self.multiSwitch, size = (0,0)), "Empty Tab")
|
||||
|
||||
view = FleetView(self.multiSwitch)
|
||||
self.multiSwitch.ReplaceActivePage(view)
|
||||
view.populate(event.fleetID)
|
||||
view.Show()
|
||||
|
||||
FleetSpawner.register()
|
||||
|
||||
class FleetView(wx.gizmos.TreeListCtrl):
|
||||
def __init__(self, parent, size = (0,0)):
|
||||
wx.gizmos.TreeListCtrl.__init__(self, parent, size = size)
|
||||
|
||||
self.tabManager = parent
|
||||
|
||||
self.fleetId = None
|
||||
self.fleetImg = BitmapLoader.getImage("53_16", "icons")
|
||||
|
||||
self.imageList = wx.ImageList(16, 16)
|
||||
self.SetImageList(self.imageList)
|
||||
|
||||
for col in ("", "Fit", "Shiptype", "Character", "Bonusses"):
|
||||
self.AddColumn(col)
|
||||
|
||||
self.SetMainColumn(1)
|
||||
self.icons = {}
|
||||
self.addImage = self.imageList.Add(BitmapLoader.getBitmap("add_small", "gui"))
|
||||
for icon in ("fb", "fc", "sb", "sc", "wb", "wc"):
|
||||
self.icons[icon] = self.imageList.Add(BitmapLoader.getBitmap("fleet_%s_small" % icon, "gui"))
|
||||
|
||||
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.checkNew)
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
self.mainFrame.Bind(gui.fleetBrowser.EVT_FLEET_RENAMED, self.fleetRenamed)
|
||||
self.mainFrame.Bind(gui.fleetBrowser.EVT_FLEET_REMOVED, self.fleetRemoved)
|
||||
|
||||
def Destroy(self):
|
||||
self.mainFrame.Unbind(gui.fleetBrowser.EVT_FLEET_REMOVED, handler = self.fleetRemoved)
|
||||
self.mainFrame.Unbind(gui.fleetBrowser.EVT_FLEET_RENAMED, handler = self.fleetRenamed)
|
||||
wx.gizmos.TreeListCtrl.Destroy(self)
|
||||
|
||||
def fleetRenamed(self, event):
|
||||
if event.fleetID == self.fleetId:
|
||||
sFleet = service.Fleet.getInstance()
|
||||
f = sFleet.getFleetByID(event.fleetID)
|
||||
self.UpdateTab(f.name, self.fleetImg)
|
||||
|
||||
event.Skip()
|
||||
|
||||
def fleetRemoved(self, event):
|
||||
if event.fleetID == self.fleetId:
|
||||
self.tabManager.DeletePage(self.tabManager.GetPageIndex(self))
|
||||
|
||||
event.Skip()
|
||||
|
||||
def checkNew(self, event):
|
||||
data = self.GetPyData(event.Item)
|
||||
if data and isinstance(data, tuple) and data[0] == "add":
|
||||
layer = data[1]
|
||||
|
||||
|
||||
def UpdateTab(self, name, img):
|
||||
self.tabManager.SetPageTextIcon(self.tabManager.GetSelection(), name, img)
|
||||
|
||||
def populate(self, fleetID):
|
||||
sFleet = service.Fleet.getInstance()
|
||||
f = sFleet.getFleetByID(fleetID)
|
||||
self.fleetId = fleetID
|
||||
|
||||
self.UpdateTab( f.name, self.fleetImg)
|
||||
self.fleet = f
|
||||
self.DeleteAllItems()
|
||||
root = self.AddRoot("")
|
||||
|
||||
self.setEntry(root, f.leader, "fleet", f)
|
||||
for wing in f.wings:
|
||||
wingId = self.AppendItem(root, "")
|
||||
self.setEntry(wingId, wing.leader, "wing", wing)
|
||||
for squad in wing.squads:
|
||||
for member in squad.members:
|
||||
memberId = self.AppendItem(wingId, "")
|
||||
self.setEntry(memberId, member, "squad", squad)
|
||||
|
||||
self.addAdder(wingId, "squad")
|
||||
|
||||
self.addAdder(root, "wing")
|
||||
|
||||
self.ExpandAll(root)
|
||||
self.SetColumnWidth(0, 16)
|
||||
for i in xrange(1, 5):
|
||||
self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
|
||||
headerWidth = self.GetColumnWidth(i) + 5
|
||||
self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
|
||||
baseWidth = self.GetColumnWidth(i)
|
||||
if baseWidth < headerWidth:
|
||||
self.SetColumnWidth(i, headerWidth)
|
||||
else:
|
||||
self.SetColumnWidth(i, baseWidth)
|
||||
|
||||
|
||||
def addAdder(self, treeItemId, layer):
|
||||
id = self.AppendItem(treeItemId, "Add new %s" % layer.capitalize())
|
||||
self.SetPyData(id, ("add", layer))
|
||||
self.SetItemImage(id, self.addImage, 1)
|
||||
|
||||
def setEntry(self, treeItemId, fit, layer, info):
|
||||
self.SetPyData(treeItemId, info)
|
||||
if fit is None:
|
||||
self.SetItemText(treeItemId, "%s Commander" % layer.capitalize(), 1)
|
||||
else:
|
||||
fleet = self.fleet
|
||||
if fit == info.booster:
|
||||
self.SetItemImage(treeItemId, self.icons["%sb" % layer[0]], 0)
|
||||
elif fit == info.leader:
|
||||
self.SetItemImage(treeItemId, self.icons["%sc" % layer[0]], 1)
|
||||
|
||||
self.SetItemText(treeItemId, fit.name, 1)
|
||||
self.SetItemText(treeItemId, fit.ship.item.name, 2)
|
||||
self.SetItemText(treeItemId, fit.character.name, 3)
|
||||
boosts = fleet.store.getBoosts(fit)
|
||||
if boosts:
|
||||
bonusses = []
|
||||
for name, info in boosts.iteritems():
|
||||
bonusses.append("%s: %.2g" % (name, info[0]))
|
||||
|
||||
self.SetItemText(treeItemId, ", ".join(bonusses), 3)
|
||||
@@ -1,456 +0,0 @@
|
||||
import wx
|
||||
import copy
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
import gui.mainFrame
|
||||
from gui.PFListPane import PFListPane
|
||||
import service.fleet
|
||||
from gui.utils.drawUtils import GetPartialText
|
||||
|
||||
from wx.lib.buttons import GenBitmapButton
|
||||
|
||||
import gui.utils.colorUtils as colorUtils
|
||||
import gui.utils.drawUtils as drawUtils
|
||||
|
||||
import gui.sfBrowserItem as SFItem
|
||||
|
||||
FleetSelected, EVT_FLEET_SELECTED = wx.lib.newevent.NewEvent()
|
||||
FleetRenamed, EVT_FLEET_RENAMED = wx.lib.newevent.NewEvent()
|
||||
FleetRemoved, EVT_FLEET_REMOVED = wx.lib.newevent.NewEvent()
|
||||
|
||||
|
||||
FleetItemSelect, EVT_FLEET_ITEM_SELECT = wx.lib.newevent.NewEvent()
|
||||
FleetItemDelete, EVT_FLEET_ITEM_DELETE = wx.lib.newevent.NewEvent()
|
||||
FleetItemNew, EVT_FLEET_ITEM_NEW = wx.lib.newevent.NewEvent()
|
||||
FleetItemCopy, EVT_FLEET_ITEM_COPY = wx.lib.newevent.NewEvent()
|
||||
FleetItemRename, EVT_FLEET_ITEM_RENAME = wx.lib.newevent.NewEvent()
|
||||
|
||||
|
||||
|
||||
class FleetBrowser(wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent)
|
||||
|
||||
self.sFleet = service.fleet.Fleet.getInstance()
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.hpane = FleetBrowserHeader(self)
|
||||
mainSizer.Add(self.hpane, 0, wx.EXPAND)
|
||||
|
||||
self.m_sl2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
|
||||
mainSizer.Add( self.m_sl2, 0, wx.EXPAND, 0 )
|
||||
|
||||
self.fleetItemContainer = PFFleetItemContainer(self)
|
||||
|
||||
mainSizer.Add(self.fleetItemContainer, 1, wx.EXPAND)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.filter = ""
|
||||
self.fleetIDMustEditName = -1
|
||||
|
||||
self.Bind(wx.EVT_SIZE, self.SizeRefreshList)
|
||||
|
||||
self.Bind(EVT_FLEET_ITEM_NEW, self.AddNewFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_SELECT, self.SelectFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_DELETE, self.DeleteFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_COPY, self.CopyFleetItem)
|
||||
self.Bind(EVT_FLEET_ITEM_RENAME, self.RenameFleetItem)
|
||||
|
||||
self.PopulateFleetList()
|
||||
|
||||
def AddNewFleetItem(self, event):
|
||||
fleetName = event.fleetName
|
||||
newFleet = self.sFleet.addFleet()
|
||||
self.sFleet.renameFleet(newFleet, fleetName)
|
||||
|
||||
self.fleetIDMustEditName = newFleet.ID
|
||||
self.AddItem(newFleet.ID, newFleet.name, newFleet.count())
|
||||
|
||||
def SelectFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
self.fleetItemContainer.SelectWidgetByFleetID(fleetID)
|
||||
wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleetID))
|
||||
|
||||
def CopyFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
fleet = self.sFleet.copyFleetByID(fleetID)
|
||||
|
||||
fleetName = fleet.name + " Copy"
|
||||
self.sFleet.renameFleet(fleet,fleetName)
|
||||
|
||||
self.fleetIDMustEditName = fleet.ID
|
||||
self.AddItem(fleet.ID, fleet.name, fleet.count())
|
||||
|
||||
self.fleetItemContainer.SelectWidgetByFleetID(fleet.ID)
|
||||
wx.PostEvent(self.mainFrame, FleetSelected(fleetID=fleet.ID))
|
||||
|
||||
def RenameFleetItem(self, event):
|
||||
fleetID = event.fleetID
|
||||
fleet = self.sFleet.getFleetByID(fleetID)
|
||||
|
||||
newFleetName = event.fleetName
|
||||
|
||||
self.sFleet.renameFleet(fleet, newFleetName)
|
||||
wx.PostEvent(self.mainFrame, FleetRenamed(fleetID = fleet.ID))
|
||||
|
||||
def DeleteFleetItem(self, event):
|
||||
self.sFleet.deleteFleetByID(event.fleetID)
|
||||
self.PopulateFleetList()
|
||||
wx.PostEvent(self.mainFrame, FleetRemoved(fleetID = event.fleetID))
|
||||
|
||||
def AddItem (self, ID, name, count):
|
||||
self.fleetItemContainer.AddWidget(FleetItem(self, ID, name, count))
|
||||
widget = self.fleetItemContainer.GetWidgetByFleetID(ID)
|
||||
self.fleetItemContainer.RefreshList(True)
|
||||
self.fleetItemContainer.ScrollChildIntoView(widget)
|
||||
wx.PostEvent(self, FleetItemSelect(fleetID = ID))
|
||||
|
||||
def PopulateFleetList(self):
|
||||
self.Freeze()
|
||||
filter = self.filter
|
||||
self.fleetItemContainer.RemoveAllChildren()
|
||||
fleetList = self.sFleet.getFleetList()
|
||||
for fleetID, fleetName, fleetCount in fleetList:
|
||||
if fleetName.lower().find(filter.lower()) != -1:
|
||||
self.fleetItemContainer.AddWidget(FleetItem(self, fleetID, fleetName, fleetCount))
|
||||
self.fleetItemContainer.RefreshList()
|
||||
self.Thaw()
|
||||
|
||||
def SetFilter(self, filter):
|
||||
self.filter = filter
|
||||
|
||||
def SizeRefreshList(self, event):
|
||||
ewidth, eheight = event.GetSize()
|
||||
self.Layout()
|
||||
self.fleetItemContainer.Layout()
|
||||
self.fleetItemContainer.RefreshList(True)
|
||||
event.Skip()
|
||||
|
||||
|
||||
class FleetBrowserHeader (wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 24), style=wx.TAB_TRAVERSAL)
|
||||
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
self.newBmp = BitmapLoader.getBitmap("fit_add_small","gui")
|
||||
bmpSize = (16,16)
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
if 'wxMac' in wx.PlatformInfo:
|
||||
bgcolour = wx.Colour(0, 0, 0, 0)
|
||||
else:
|
||||
bgcolour = wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE )
|
||||
|
||||
self.fbNewFleet = PFGenBitmapButton( self, wx.ID_ANY, self.newBmp, wx.DefaultPosition, bmpSize, wx.BORDER_NONE )
|
||||
mainSizer.Add(self.fbNewFleet, 0, wx.LEFT | wx.TOP | wx.BOTTOM | wx.ALIGN_CENTER_VERTICAL , 5)
|
||||
self.fbNewFleet.SetBackgroundColour( bgcolour )
|
||||
|
||||
self.sl1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_VERTICAL )
|
||||
mainSizer.Add( self.sl1, 0, wx.EXPAND |wx.LEFT, 5 )
|
||||
|
||||
self.tcFilter = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.tcFilter, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.stStatus = wx.StaticText( self, wx.ID_ANY, u"", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stStatus.Wrap( -1 )
|
||||
mainSizer.Add( self.stStatus, 1, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.fbNewFleet.Bind(wx.EVT_ENTER_WINDOW, self.fbNewEnterWindow)
|
||||
self.fbNewFleet.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
|
||||
self.fbNewFleet.Bind(wx.EVT_BUTTON, self.OnNewFleetItem)
|
||||
|
||||
self.tcFilter.Bind(wx.EVT_TEXT, self.OnFilterText)
|
||||
|
||||
self.tcFilter.Bind(wx.EVT_ENTER_WINDOW, self.fbFilterEnterWindow)
|
||||
self.tcFilter.Bind(wx.EVT_LEAVE_WINDOW, self.fbHItemLeaveWindow)
|
||||
|
||||
def OnFilterText(self, event):
|
||||
filter = self.tcFilter.GetValue()
|
||||
self.Parent.SetFilter(filter)
|
||||
self.Parent.PopulateFleetList()
|
||||
event.Skip()
|
||||
|
||||
def OnNewFleetItem(self, event):
|
||||
wx.PostEvent(self.Parent, FleetItemNew(fleetName = "New Fleet"))
|
||||
|
||||
def fbNewEnterWindow(self, event):
|
||||
self.stStatus.SetLabel("New fleet")
|
||||
self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
|
||||
event.Skip()
|
||||
|
||||
def fbHItemLeaveWindow(self, event):
|
||||
self.stStatus.SetLabel("")
|
||||
self.Parent.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
|
||||
event.Skip()
|
||||
|
||||
def fbFilterEnterWindow(self, event):
|
||||
self.stStatus.SetLabel("Filter list")
|
||||
event.Skip()
|
||||
|
||||
|
||||
|
||||
class PFFleetItemContainer(PFListPane):
|
||||
def __init__(self,parent):
|
||||
PFListPane.__init__(self,parent)
|
||||
self.selectedWidget = -1
|
||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||
|
||||
def IsWidgetSelectedByContext(self, widget):
|
||||
if self.GetWidgetList()[widget].IsSelected():
|
||||
return True
|
||||
return False
|
||||
|
||||
def GetWidgetIndex(self, widgetWnd):
|
||||
return self.GetWidgetList().index(widgetWnd)
|
||||
|
||||
def GetWidgetByFleetID(self, fleetID):
|
||||
for widget in self.GetWidgetList():
|
||||
if widget.fleetID == fleetID:
|
||||
return widget
|
||||
return None
|
||||
|
||||
def SelectWidget(self, widgetWnd):
|
||||
wlist = self.GetWidgetList()
|
||||
if self.selectedWidget != -1:
|
||||
wlist[self.selectedWidget].SetSelected(False)
|
||||
wlist[self.selectedWidget].Refresh()
|
||||
windex = self.GetWidgetIndex(widgetWnd)
|
||||
wlist[windex].SetSelected(True)
|
||||
wlist[windex].Refresh()
|
||||
self.selectedWidget = windex
|
||||
|
||||
def SelectWidgetByFleetID(self, fleetID):
|
||||
widgetWnd = self.GetWidgetByFleetID(fleetID)
|
||||
if widgetWnd:
|
||||
self.SelectWidget(widgetWnd)
|
||||
|
||||
def RemoveWidget(self, child):
|
||||
child.Destroy()
|
||||
self.selectedWidget = -1
|
||||
self._wList.remove(child)
|
||||
|
||||
|
||||
def RemoveAllChildren(self):
|
||||
for widget in self._wList:
|
||||
widget.Destroy()
|
||||
|
||||
self.selectedWidget = -1
|
||||
self._wList = []
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
event.Skip()
|
||||
|
||||
class FleetItem(SFItem.SFBrowserItem):
|
||||
def __init__(self, parent, fleetID, fleetName, fleetCount,
|
||||
id=wx.ID_ANY, pos=wx.DefaultPosition,
|
||||
size=(0,40), style=0):
|
||||
SFItem.SFBrowserItem.__init__(self, parent, size = size)
|
||||
|
||||
self.fleetBrowser = self.Parent
|
||||
self.fleetID = fleetID
|
||||
self.fleetName = fleetName
|
||||
self.fleetCount = fleetCount
|
||||
|
||||
self.padding = 4
|
||||
|
||||
self.fontBig = wx.FontFromPixelSize((0,15),wx.SWISS, wx.NORMAL, wx.BOLD, False)
|
||||
self.fontNormal = wx.FontFromPixelSize((0,14),wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
||||
self.fontSmall = wx.FontFromPixelSize((0,12),wx.SWISS, wx.NORMAL, wx.NORMAL, False)
|
||||
|
||||
self.copyBmp = BitmapLoader.getBitmap("fit_add_small", "gui")
|
||||
self.renameBmp = BitmapLoader.getBitmap("fit_rename_small", "gui")
|
||||
self.deleteBmp = BitmapLoader.getBitmap("fit_delete_small","gui")
|
||||
self.acceptBmp = BitmapLoader.getBitmap("faccept_small", "gui")
|
||||
self.fleetBmp = BitmapLoader.getBitmap("fleet_item_big", "gui")
|
||||
|
||||
fleetImg = self.fleetBmp.ConvertToImage()
|
||||
fleetImg = fleetImg.Blur(2)
|
||||
|
||||
if not fleetImg.HasAlpha():
|
||||
fleetImg.InitAlpha()
|
||||
|
||||
fleetImg = fleetImg.AdjustChannels(1, 1, 1, 0.5)
|
||||
self.fleetEffBmp = wx.BitmapFromImage(fleetImg)
|
||||
|
||||
self.toolbar.AddButton(self.copyBmp, "Copy", self.CopyFleetCB)
|
||||
self.renameBtn = self.toolbar.AddButton(self.renameBmp, "Rename", self.RenameFleetCB)
|
||||
self.toolbar.AddButton(self.deleteBmp, "Delete", self.DeleteFleetCB)
|
||||
|
||||
self.editWidth = 150
|
||||
self.tcFleetName = wx.TextCtrl(self, wx.ID_ANY, "%s" % self.fleetName, wx.DefaultPosition, (self.editWidth,-1), wx.TE_PROCESS_ENTER)
|
||||
|
||||
if self.fleetBrowser.fleetIDMustEditName != self.fleetID:
|
||||
self.tcFleetName.Show(False)
|
||||
else:
|
||||
self.tcFleetName.SetFocus()
|
||||
self.tcFleetName.SelectAll()
|
||||
self.fleetBrowser.fleetIDMustEditName = -1
|
||||
self.renameBtn.SetBitmap(self.acceptBmp)
|
||||
self.selected = True
|
||||
|
||||
self.tcFleetName.Bind(wx.EVT_KILL_FOCUS, self.OnEditLostFocus)
|
||||
self.tcFleetName.Bind(wx.EVT_TEXT_ENTER, self.RenameFleet)
|
||||
self.tcFleetName.Bind(wx.EVT_KEY_DOWN, self.EditCheckEsc)
|
||||
|
||||
|
||||
self.animCount = 0
|
||||
|
||||
def MouseLeftUp(self, event):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
else:
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemSelect(fleetID = self.fleetID))
|
||||
|
||||
def CopyFleetCB(self):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
return
|
||||
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemCopy(fleetID = self.fleetID))
|
||||
|
||||
def RenameFleetCB(self):
|
||||
|
||||
if self.tcFleetName.IsShown():
|
||||
|
||||
self.RenameFleet(None)
|
||||
self.RestoreEditButton()
|
||||
|
||||
else:
|
||||
self.tcFleetName.SetValue(self.fleetName)
|
||||
self.tcFleetName.Show()
|
||||
|
||||
self.renameBtn.SetBitmap(self.acceptBmp)
|
||||
self.Refresh()
|
||||
|
||||
self.tcFleetName.SetFocus()
|
||||
self.tcFleetName.SelectAll()
|
||||
|
||||
self.Refresh()
|
||||
|
||||
def RenameFleet(self, event):
|
||||
|
||||
newFleetName = self.tcFleetName.GetValue()
|
||||
self.fleetName = newFleetName
|
||||
|
||||
self.tcFleetName.Show(False)
|
||||
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemRename(fleetID = self.fleetID, fleetName = self.fleetName))
|
||||
self.Refresh()
|
||||
|
||||
def DeleteFleetCB(self):
|
||||
if self.tcFleetName.IsShown():
|
||||
self.RestoreEditButton()
|
||||
return
|
||||
wx.PostEvent(self.fleetBrowser, FleetItemDelete(fleetID = self.fleetID))
|
||||
|
||||
def RestoreEditButton(self):
|
||||
self.tcFleetName.Show(False)
|
||||
self.renameBtn.SetBitmap(self.renameBmp)
|
||||
self.Refresh()
|
||||
|
||||
def OnEditLostFocus(self, event):
|
||||
self.RestoreEditButton()
|
||||
self.Refresh()
|
||||
|
||||
def EditCheckEsc(self, event):
|
||||
if event.GetKeyCode() == wx.WXK_ESCAPE:
|
||||
self.RestoreEditButton()
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def IsSelected(self):
|
||||
return self.selected
|
||||
|
||||
def UpdateElementsPos(self, mdc):
|
||||
rect = self.GetRect()
|
||||
|
||||
self.toolbarx = rect.width - self.toolbar.GetWidth() - self.padding
|
||||
self.toolbary = (rect.height - self.toolbar.GetHeight()) / 2
|
||||
|
||||
self.toolbarx = self.toolbarx + self.animCount
|
||||
|
||||
self.fleetBmpx = self.padding + (rect.height - self.fleetBmp.GetWidth()) / 2
|
||||
self.fleetBmpy = (rect.height - self.fleetBmp.GetHeight()) / 2
|
||||
|
||||
self.fleetBmpx -= self.animCount
|
||||
|
||||
self.textStartx = self.fleetBmpx + self.fleetBmp.GetWidth() + self.padding
|
||||
|
||||
self.fleetNamey = (rect.height - self.fleetBmp.GetHeight()) / 2
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
wtext, htext = mdc.GetTextExtent(self.fleetName)
|
||||
|
||||
self.fleetCounty = self.fleetNamey + htext
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
|
||||
wlabel,hlabel = mdc.GetTextExtent(self.toolbar.hoverLabel)
|
||||
|
||||
self.thoverx = self.toolbarx - self.padding - wlabel
|
||||
self.thovery = (rect.height - hlabel)/2
|
||||
self.thoverw = wlabel
|
||||
|
||||
def DrawItem(self, mdc):
|
||||
rect = self.GetRect()
|
||||
|
||||
windowColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
|
||||
textColor = colorUtils.GetSuitableColor(windowColor, 1)
|
||||
|
||||
mdc.SetTextForeground(textColor)
|
||||
|
||||
self.UpdateElementsPos(mdc)
|
||||
|
||||
self.toolbar.SetPosition((self.toolbarx, self.toolbary))
|
||||
mdc.DrawBitmap(self.fleetEffBmp, self.fleetBmpx + 3, self.fleetBmpy + 2)
|
||||
mdc.DrawBitmap(self.fleetBmp, self.fleetBmpx,self.fleetBmpy)
|
||||
|
||||
mdc.SetFont(self.fontNormal)
|
||||
|
||||
suffix = "%d ships" % self.fleetCount if self.fleetCount >1 else "%d ship" % self.fleetCount if self.fleetCount == 1 else "No ships"
|
||||
fleetCount = "Fleet size: %s" % suffix
|
||||
fleetCount = drawUtils.GetPartialText(mdc, fleetCount, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
|
||||
mdc.DrawText(fleetCount, self.textStartx, self.fleetCounty)
|
||||
|
||||
mdc.SetFont(self.fontSmall)
|
||||
mdc.DrawText(self.toolbar.hoverLabel, self.thoverx, self.thovery)
|
||||
|
||||
mdc.SetFont(self.fontBig)
|
||||
|
||||
pfname = drawUtils.GetPartialText(mdc, self.fleetName, self.toolbarx - self.textStartx - self.padding * 2 - self.thoverw)
|
||||
mdc.DrawText(pfname, self.textStartx, self.fleetNamey)
|
||||
|
||||
if self.tcFleetName.IsShown():
|
||||
self.AdjustControlSizePos(self.tcFleetName, self.textStartx, self.toolbarx - self.editWidth - self.padding)
|
||||
|
||||
def AdjustControlSizePos(self, editCtl, start, end):
|
||||
fnEditSize = editCtl.GetSize()
|
||||
wSize = self.GetSize()
|
||||
fnEditPosX = end
|
||||
fnEditPosY = (wSize.height - fnEditSize.height)/2
|
||||
if fnEditPosX < start:
|
||||
editCtl.SetSize((self.editWidth + fnEditPosX - start,-1))
|
||||
editCtl.SetPosition((start,fnEditPosY))
|
||||
else:
|
||||
editCtl.SetSize((self.editWidth,-1))
|
||||
editCtl.SetPosition((fnEditPosX,fnEditPosY))
|
||||
|
||||
|
||||
class PFGenBitmapButton(GenBitmapButton):
|
||||
def __init__(self, parent, id, bitmap, pos, size, style):
|
||||
GenBitmapButton.__init__(self, parent, id, bitmap, pos, size, style)
|
||||
self.bgcolor = wx.Brush(wx.WHITE)
|
||||
|
||||
def SetBackgroundColour(self, color):
|
||||
self.bgcolor = wx.Brush(color)
|
||||
|
||||
def GetBackgroundBrush(self, dc):
|
||||
return self.bgcolor
|
||||
412
gui/gangView.py
@@ -1,412 +0,0 @@
|
||||
#===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# 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/>.
|
||||
#===============================================================================
|
||||
import wx
|
||||
from wx.lib.scrolledpanel import ScrolledPanel
|
||||
|
||||
import service
|
||||
import gui.mainFrame
|
||||
import gui.shipBrowser
|
||||
import gui.globalEvents as GE
|
||||
|
||||
from gui import characterEditor as CharEditor
|
||||
|
||||
class GangView ( ScrolledPanel ):
|
||||
|
||||
def __init__( self, parent ):
|
||||
ScrolledPanel.__init__ ( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx.Size( 100,20 ), style = wx.TAB_TRAVERSAL | wx.HSCROLL | wx.VSCROLL )
|
||||
mainSizer = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
self.draggedFitID = None
|
||||
|
||||
help = '''Set fit as booster to display in dropdown, or drag fitting from\nship browser to this window, or right click fit and select booster role.'''
|
||||
helpSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
self.helpText = wx.StaticText( self, wx.ID_ANY, help, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
|
||||
helpSizer.Add( self.helpText, 1, wx.ALL, 5 )
|
||||
|
||||
self.options = ["Fleet", "Wing", "Squad"]
|
||||
|
||||
self.fleet = {}
|
||||
for id, option in enumerate(self.options):
|
||||
|
||||
# set content for each commander
|
||||
self.fleet[id] = {}
|
||||
self.fleet[id]['stLabel'] = wx.StaticText( self, wx.ID_ANY, self.options[id]+':', wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.fleet[id]['stText'] = wx.StaticText( self, wx.ID_ANY, 'None', wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.fleet[id]['chFit'] = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [] )
|
||||
self.fleet[id]['chChar'] = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [] )
|
||||
self.fleet[id]['fitSizer'] = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.FitDNDPopupMenu = self.buildBoostermenu()
|
||||
|
||||
contentFGSizer = wx.FlexGridSizer( 5, 3, 0, 0 )
|
||||
contentFGSizer.AddGrowableCol( 1 )
|
||||
contentFGSizer.SetFlexibleDirection( wx.BOTH )
|
||||
contentFGSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )
|
||||
|
||||
### Header
|
||||
self.stBooster = wx.StaticText( self, wx.ID_ANY, u"Booster", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stBooster.Wrap( -1 )
|
||||
self.stBooster.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
|
||||
contentFGSizer.Add( self.stBooster, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.stFits = wx.StaticText( self, wx.ID_ANY, u"Fits", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stFits.Wrap( -1 )
|
||||
self.stFits.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
|
||||
contentFGSizer.Add( self.stFits, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
|
||||
|
||||
self.stCharacters = wx.StaticText( self, wx.ID_ANY, u"Characters", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stCharacters.Wrap( -1 )
|
||||
self.stCharacters.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
|
||||
contentFGSizer.Add( self.stCharacters, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
|
||||
|
||||
self.m_staticline2 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
|
||||
contentFGSizer.Add( self.m_staticline2, 0, wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticline3 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
|
||||
contentFGSizer.Add( self.m_staticline3, 0, wx.EXPAND, 5 )
|
||||
|
||||
self.m_staticline4 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL )
|
||||
contentFGSizer.Add( self.m_staticline4, 0, wx.EXPAND, 5 )
|
||||
|
||||
### Content
|
||||
for id in self.fleet:
|
||||
# set various properties
|
||||
self.fleet[id]['stLabel'].Wrap( -1 )
|
||||
self.fleet[id]['stLabel'].SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
|
||||
self.fleet[id]['stText'].Wrap( -1 )
|
||||
|
||||
# bind text and choice events
|
||||
self.fleet[id]['stText'].Bind(wx.EVT_LEFT_DCLICK, self.RemoveBooster)
|
||||
self.fleet[id]['stText'].Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
|
||||
self.fleet[id]['stText'].Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
|
||||
self.fleet[id]['stText'].SetToolTip(wx.ToolTip("Double click to remove booster"))
|
||||
self.fleet[id]['chChar'].Bind(wx.EVT_CHOICE, self.CharChanged)
|
||||
self.fleet[id]['chFit'].Bind(wx.EVT_CHOICE, self.OnFitChoiceSelected)
|
||||
|
||||
# add fit text and choice to the fit sizer
|
||||
self.fleet[id]['fitSizer'].Add( self.fleet[id]['stText'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
|
||||
self.fleet[id]['fitSizer'].Add( self.fleet[id]['chFit'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 1 )
|
||||
|
||||
# add everything to the content sizer
|
||||
contentFGSizer.Add( self.fleet[id]['stLabel'], 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
|
||||
contentFGSizer.Add( self.fleet[id]['fitSizer'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 )
|
||||
contentFGSizer.Add( self.fleet[id]['chChar'], 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 )
|
||||
|
||||
mainSizer.Add( contentFGSizer, 1, wx.EXPAND, 0 )
|
||||
mainSizer.Add( helpSizer, 0, wx.EXPAND, 0 )
|
||||
|
||||
self.SetSizer( mainSizer )
|
||||
self.SetAutoLayout(True)
|
||||
self.SetupScrolling()
|
||||
|
||||
self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.RefreshCharacterList)
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitSelected)
|
||||
self.mainFrame.Bind(gui.shipBrowser.EVT_FIT_RENAMED, self.fitRenamed)
|
||||
self.mainFrame.Bind(gui.shipBrowser.BOOSTER_LIST_UPDATED, self.RefreshBoosterFits)
|
||||
|
||||
self.RefreshBoosterFits()
|
||||
self.RefreshCharacterList()
|
||||
|
||||
def buildBoostermenu(self):
|
||||
menu = wx.Menu()
|
||||
|
||||
for id, option in enumerate(self.options):
|
||||
item = menu.Append(-1, option)
|
||||
# We bind it to the mainFrame because it may be called from either this class or from FitItem via shipBrowser
|
||||
self.mainFrame.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item)
|
||||
return menu
|
||||
|
||||
def OnEnterWindow(self, event):
|
||||
obj = event.GetEventObject()
|
||||
obj.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
|
||||
event.Skip()
|
||||
|
||||
def OnLeaveWindow(self, event):
|
||||
obj = event.GetEventObject()
|
||||
obj.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
||||
event.Skip()
|
||||
|
||||
def CharChanged(self, event):
|
||||
''' Change booster character '''
|
||||
chBooster = event.GetEventObject()
|
||||
|
||||
type = -1
|
||||
for id in self.fleet:
|
||||
if chBooster == self.fleet[id]['chChar']: type = id
|
||||
|
||||
if type == -1:
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
sFit = service.Fit.getInstance()
|
||||
|
||||
fleetSrv = service.Fleet.getInstance()
|
||||
|
||||
activeFitID = self.mainFrame.getActiveFit()
|
||||
fit = sFit.getFit(activeFitID)
|
||||
|
||||
sChar = service.Character.getInstance()
|
||||
charList = sChar.getCharacterList()
|
||||
|
||||
if activeFitID:
|
||||
commanders = fleetSrv.loadLinearFleet(fit)
|
||||
if commanders is None:
|
||||
fleetCom, wingCom, squadCom = (None, None, None)
|
||||
else:
|
||||
fleetCom, wingCom, squadCom = commanders
|
||||
|
||||
if type == 0:
|
||||
if fleetCom:
|
||||
charID = chBooster.GetClientData(chBooster.GetSelection())
|
||||
sFit.changeChar(fleetCom.ID, charID)
|
||||
else:
|
||||
chBooster.SetSelection(0)
|
||||
|
||||
if type == 1:
|
||||
if wingCom:
|
||||
charID = chBooster.GetClientData(chBooster.GetSelection())
|
||||
sFit.changeChar(wingCom.ID, charID)
|
||||
else:
|
||||
chBooster.SetSelection(0)
|
||||
|
||||
if type == 2:
|
||||
if squadCom:
|
||||
charID = chBooster.GetClientData(chBooster.GetSelection())
|
||||
sFit.changeChar(squadCom.ID, charID)
|
||||
else:
|
||||
chBooster.SetSelection(0)
|
||||
|
||||
sFit.recalc(fit, withBoosters=True)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
|
||||
|
||||
else:
|
||||
chBooster.SetSelection(0)
|
||||
|
||||
def RemoveBooster(self, event):
|
||||
activeFitID = self.mainFrame.getActiveFit()
|
||||
if not activeFitID:
|
||||
return
|
||||
|
||||
location = event.GetEventObject()
|
||||
|
||||
for id in self.fleet:
|
||||
if location == self.fleet[id]['stText']: type = id
|
||||
|
||||
sFit = service.Fit.getInstance()
|
||||
boostee = sFit.getFit(activeFitID)
|
||||
booster = None
|
||||
|
||||
fleetSrv = service.Fleet.getInstance()
|
||||
|
||||
if type == 0: fleetSrv.setLinearFleetCom(boostee, booster)
|
||||
if type == 1: fleetSrv.setLinearWingCom(boostee, booster)
|
||||
if type == 2: fleetSrv.setLinearSquadCom(boostee, booster)
|
||||
|
||||
# Hide stText and, default fit selection, and enable it
|
||||
location.Hide()
|
||||
choice = self.fleet[type]['chFit']
|
||||
choice.SetSelection(0)
|
||||
choice.Show()
|
||||
|
||||
sFit.recalc(boostee, withBoosters=True)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
|
||||
|
||||
def fitRenamed(self, event):
|
||||
fleetSrv = service.Fleet.getInstance()
|
||||
activeFitID = self.mainFrame.getActiveFit()
|
||||
|
||||
if activeFitID:
|
||||
ev = event
|
||||
ev.fitID = activeFitID
|
||||
self.fitSelected(ev)
|
||||
|
||||
def fitSelected(self, event):
|
||||
''' Fires when active fit is selected and when booster is saved to fit. Update the UI to reflect changes '''
|
||||
fleetSrv = service.Fleet.getInstance()
|
||||
|
||||
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:
|
||||
commanders = fleetSrv.loadLinearFleet(fit)
|
||||
|
||||
for id in self.fleet:
|
||||
# try...except here as we're trying 2 different criteria and want to fall back on the same code
|
||||
try:
|
||||
commander = commanders[id]
|
||||
|
||||
if not activeFitID or commander is None:
|
||||
raise Exception()
|
||||
|
||||
self.fleet[id]['stText'].SetLabel(commander.ship.item.name + ": " + commander.name)
|
||||
self.fleet[id]['chChar'].SetStringSelection(commander.character.name if commander.character is not None else "All 0")
|
||||
self.fleet[id]['chChar'].Enable()
|
||||
self.fleet[id]['chFit'].Hide()
|
||||
self.fleet[id]['stText'].Show()
|
||||
except:
|
||||
#set defaults, disable char selection, and enable fit selection
|
||||
self.fleet[id]['stText'].SetLabel("None")
|
||||
self.fleet[id]['chChar'].SetStringSelection("All 0")
|
||||
self.fleet[id]['chChar'].Disable()
|
||||
self.fleet[id]['chFit'].SetSelection(0)
|
||||
self.fleet[id]['chFit'].Show()
|
||||
self.fleet[id]['stText'].Hide()
|
||||
|
||||
if activeFitID:
|
||||
self.Enable()
|
||||
else:
|
||||
self.Disable()
|
||||
|
||||
self.Layout()
|
||||
self.SendSizeEvent()
|
||||
|
||||
def AddCommander(self, fitID, type = None):
|
||||
''' Adds booster to a fit, then recalculates active fit '''
|
||||
if type is None:
|
||||
return
|
||||
|
||||
activeFitID = self.mainFrame.getActiveFit()
|
||||
if activeFitID:
|
||||
sFit = service.Fit.getInstance()
|
||||
|
||||
boostee = sFit.getFit(activeFitID)
|
||||
booster = sFit.getFit(fitID)
|
||||
|
||||
fleetSrv = service.Fleet.getInstance()
|
||||
|
||||
if type == 0: fleetSrv.setLinearFleetCom(boostee, booster)
|
||||
if type == 1: fleetSrv.setLinearWingCom(boostee, booster)
|
||||
if type == 2: fleetSrv.setLinearSquadCom(boostee, booster)
|
||||
|
||||
sFit.recalc(boostee)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
|
||||
|
||||
def RefreshBoosterFits(self, event = None):
|
||||
sFit = service.Fit.getInstance()
|
||||
sMkt = service.Market.getInstance()
|
||||
fitList = sFit.getBoosterFits()
|
||||
|
||||
for id in self.fleet:
|
||||
choice = self.fleet[id]['chFit']
|
||||
chCurrSelection = choice.GetSelection()
|
||||
chCurrData = -1
|
||||
if chCurrSelection != -1:
|
||||
chCurrData = choice.GetClientData(chCurrSelection)
|
||||
chCurrSelString = choice.GetString(chCurrSelection)
|
||||
choice.Clear()
|
||||
currSelFound = False
|
||||
choice.Append("None", -1)
|
||||
for fit in fitList:
|
||||
id,name,type = fit
|
||||
ship = sMkt.getItem(type)
|
||||
choice.Append(ship.name+': '+name, id)
|
||||
if chCurrData == id:
|
||||
currSelFound = True
|
||||
|
||||
if chCurrSelection == -1:
|
||||
choice.SetSelection(0)
|
||||
else:
|
||||
if currSelFound:
|
||||
choice.SetStringSelection(chCurrSelString)
|
||||
else:
|
||||
choice.SetSelection(0)
|
||||
|
||||
def RefreshCharacterList(self, event = None):
|
||||
sChar = service.Character.getInstance()
|
||||
charList = sChar.getCharacterList()
|
||||
for id in self.fleet:
|
||||
choice = self.fleet[id]['chChar']
|
||||
chCurrSelection = choice.GetSelection()
|
||||
chCurrData = -1
|
||||
if chCurrSelection != -1:
|
||||
chCurrData = choice.GetClientData(chCurrSelection)
|
||||
chCurrSelString = choice.GetString(chCurrSelection)
|
||||
choice.Clear()
|
||||
currSelFound = False
|
||||
for char in charList:
|
||||
choice.Append(char.name, char.ID)
|
||||
if chCurrData == char.ID:
|
||||
currSelFound = True
|
||||
|
||||
if chCurrSelection == -1:
|
||||
choice.SetSelection(1)
|
||||
else:
|
||||
if currSelFound:
|
||||
choice.SetStringSelection(chCurrSelString)
|
||||
else:
|
||||
choice.SetSelection(1)
|
||||
|
||||
def handleDrag(self, type, fitID):
|
||||
''' Handle dragging of fit to fleet interface '''
|
||||
#Those are drags coming from pyfa sources, NOT builtin wx drags
|
||||
self.draggedFitID = None
|
||||
if type == "fit":
|
||||
sFit = service.Fit.getInstance()
|
||||
fit = sFit.getFit(self.mainFrame.getActiveFit())
|
||||
|
||||
if fit and not fit.isStructure:
|
||||
self.draggedFitID = fitID
|
||||
|
||||
pos = wx.GetMousePosition()
|
||||
pos = self.ScreenToClient(pos)
|
||||
|
||||
self.PopupMenu(self.FitDNDPopupMenu, pos)
|
||||
|
||||
|
||||
def OnPopupItemSelected(self, event):
|
||||
''' Fired when booster popup item is selected '''
|
||||
# Get menu selection ID via self.options
|
||||
menuItem = event.EventObject.FindItemById(event.GetId())
|
||||
type = self.options.index(menuItem.GetText())
|
||||
|
||||
if self.draggedFitID:
|
||||
sFit = service.Fit.getInstance()
|
||||
draggedFit = sFit.getFit(self.draggedFitID)
|
||||
|
||||
self.AddCommander(draggedFit.ID, type)
|
||||
self.mainFrame.additionsPane.select("Fleet")
|
||||
|
||||
def OnFitChoiceSelected(self, event):
|
||||
''' Fired when booster choice is selected '''
|
||||
sFit = service.Fit.getInstance()
|
||||
|
||||
# set type via choice box used
|
||||
chFit = event.GetEventObject()
|
||||
fitID = chFit.GetClientData(chFit.GetSelection())
|
||||
|
||||
type = -1
|
||||
for id in self.fleet:
|
||||
if chFit == self.fleet[id]['chFit']: type = id
|
||||
|
||||
if type == -1 or fitID == -1:
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
fit = sFit.getFit(fitID)
|
||||
|
||||
self.AddCommander(fit.ID, type)
|
||||
self.mainFrame.additionsPane.select("Fleet")
|
||||
@@ -55,7 +55,6 @@ from gui.preferenceDialog import PreferenceDialog
|
||||
from gui.graphFrame import GraphFrame
|
||||
from gui.copySelectDialog import CopySelectDialog
|
||||
from gui.utils.clipboard import toClipboard, fromClipboard
|
||||
from gui.fleetBrowser import FleetBrowser
|
||||
from gui.updateDialog import UpdateDialog
|
||||
from gui.builtinViews import *
|
||||
|
||||
@@ -158,12 +157,6 @@ class MainFrame(wx.Frame):
|
||||
self.shipBrowser = ShipBrowser(self.notebookBrowsers)
|
||||
self.notebookBrowsers.AddPage(self.shipBrowser, "Fittings", tabImage = shipBrowserImg, showClose = False)
|
||||
|
||||
#=======================================================================
|
||||
# DISABLED FOR RC2 RELEASE
|
||||
#self.fleetBrowser = FleetBrowser(self.notebookBrowsers)
|
||||
#self.notebookBrowsers.AddPage(self.fleetBrowser, "Fleets", showClose = False)
|
||||
#=======================================================================
|
||||
|
||||
self.notebookBrowsers.SetSelection(1)
|
||||
|
||||
self.browser_fitting_split.SplitVertically(self.notebookBrowsers, self.fitting_additions_split)
|
||||
|
||||
@@ -34,6 +34,7 @@ Stage3Selected, EVT_SB_STAGE3_SEL = wx.lib.newevent.NewEvent()
|
||||
SearchSelected, EVT_SB_SEARCH_SEL = wx.lib.newevent.NewEvent()
|
||||
ImportSelected, EVT_SB_IMPORT_SEL = wx.lib.newevent.NewEvent()
|
||||
|
||||
|
||||
class PFWidgetsContainer(PFListPane):
|
||||
def __init__(self,parent):
|
||||
PFListPane.__init__(self,parent)
|
||||
@@ -685,7 +686,8 @@ class ShipBrowser(wx.Panel):
|
||||
|
||||
# set map & cache of fittings per category
|
||||
for cat in self.categoryList:
|
||||
self.categoryFitCache[cat.ID] = sFit.groupHasFits(cat.ID)
|
||||
itemIDs = [x.ID for x in cat.items]
|
||||
self.categoryFitCache[cat.ID] = sFit.countFitsWithShip(itemIDs) > 1
|
||||
|
||||
for ship in self.categoryList:
|
||||
if self.filterShipsWithNoFits and not self.categoryFitCache[ship.ID]:
|
||||
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |