From af9a9c56988074b5a1637f3977c3253e4a2e5f0e Mon Sep 17 00:00:00 2001 From: blitzmann Date: Sun, 17 Apr 2016 13:28:12 -0400 Subject: [PATCH] More fighter work. Basic abilities now work correctly. --- eos/db/saveddata/fighter.py | 1 - eos/effects/fighterabilityattackm.py | 14 +++ eos/effects/fighterabilitymicrowarpdrive.py | 16 ++++ eos/effects/fighterabilitymissiles.py | 14 +++ eos/saveddata/fighter.py | 100 ++++++++------------ eos/saveddata/fighterAbility.py | 16 +++- gui/builtinViewColumns/baseName.py | 4 +- service/fit.py | 7 +- 8 files changed, 104 insertions(+), 68 deletions(-) create mode 100644 eos/effects/fighterabilityattackm.py create mode 100644 eos/effects/fighterabilitymicrowarpdrive.py create mode 100644 eos/effects/fighterabilitymissiles.py diff --git a/eos/db/saveddata/fighter.py b/eos/db/saveddata/fighter.py index c42eca7d2..3adb422bc 100644 --- a/eos/db/saveddata/fighter.py +++ b/eos/db/saveddata/fighter.py @@ -32,7 +32,6 @@ fighters_table = Table("fighters", saveddata_meta, Column("fitID", Integer, ForeignKey("fits.ID"), nullable = False, index = True), Column("itemID", Integer, nullable = False), Column("amount", Integer, nullable = False), - Column("amountActive", Integer, nullable = False), Column("projected", Boolean, default = False)) fighter_abilities_table = Table("fightersAbilities", saveddata_meta, diff --git a/eos/effects/fighterabilityattackm.py b/eos/effects/fighterabilityattackm.py new file mode 100644 index 000000000..dd41d77dc --- /dev/null +++ b/eos/effects/fighterabilityattackm.py @@ -0,0 +1,14 @@ +""" +Since fighter abilities do not have any sort of item entity in the EVE database, we must derive the abilities from the +effects, and thus this effect file contains some custom information useful only to fighters. +""" +# User-friendly name for the ability +displayName = "Turret Attack" + +# Attribute prefix that this ability targets +prefix = "fighterAbilityAttackMissile" + +type = "active" + +def handler(fit, src, context): + pass \ No newline at end of file diff --git a/eos/effects/fighterabilitymicrowarpdrive.py b/eos/effects/fighterabilitymicrowarpdrive.py new file mode 100644 index 000000000..79255a4db --- /dev/null +++ b/eos/effects/fighterabilitymicrowarpdrive.py @@ -0,0 +1,16 @@ +""" +Since fighter abilities do not have any sort of item entity in the EVE database, we must derive the abilities from the +effects, and thus this effect file contains some custom information useful only to fighters. +""" +# User-friendly name for the ability +displayName = "Microwarpdrive" + +# Is ability applied to the fighter squad as a whole, or per fighter? +grouped = True + +type = "active" +runTime = "late" +def handler(fit, module, context): + print module.getModifiedItemAttr("fighterAbilityMicroWarpDriveSpeedBonus") + module.boostItemAttr("maxVelocity", module.getModifiedItemAttr("fighterAbilityMicroWarpDriveSpeedBonus")) + module.boostItemAttr("signatureRadius", module.getModifiedItemAttr("fighterAbilityMicroWarpDriveSignatureRadiusBonus"), stackingPenalties = True) \ No newline at end of file diff --git a/eos/effects/fighterabilitymissiles.py b/eos/effects/fighterabilitymissiles.py new file mode 100644 index 000000000..16e7ee8b2 --- /dev/null +++ b/eos/effects/fighterabilitymissiles.py @@ -0,0 +1,14 @@ +""" +Since fighter abilities do not have any sort of item entity in the EVE database, we must derive the abilities from the +effects, and thus this effect file contains some custom information useful only to fighters. +""" +# User-friendly name for the ability +displayName = "Missile Attack" + +# Attribute prefix that this ability targets +prefix = "fighterAbilityMissiles" + +type = "active" + +def handler(fit, src, context): + pass \ No newline at end of file diff --git a/eos/saveddata/fighter.py b/eos/saveddata/fighter.py index 46fa447bf..dd67573fe 100644 --- a/eos/saveddata/fighter.py +++ b/eos/saveddata/fighter.py @@ -28,7 +28,7 @@ logger = logging.getLogger(__name__) class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): DAMAGE_TYPES = ("em", "kinetic", "explosive", "thermal") - MINING_ATTRIBUTES = ("miningAmount",) + DAMAGE_TYPES2 = ("EM", "Kin", "Exp", "Therm") def __init__(self, item): """Initialize a fighter from the program""" @@ -38,10 +38,12 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): raise ValueError("Passed item is not a Fighter") self.itemID = item.ID if item is not None else None - self.amount = 0 - self.amountActive = 0 self.projected = False + # -1 is a placeholder that represents max squadron size, which we may not know yet as ships may modify this with + # their effects. If user changes this, it is then overridden with user value. + self.amount = -1 + self.__abilities = self.__getAbilities() self.build() @@ -92,11 +94,18 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): print "getting list of abilities" return [FighterAbility(effect) for effect in self.item.effects.values()] + @property + def amountActive(self): + return self.getModifiedItemAttr("fighterSquadronMaxSize") if self.amount == -1 else self.amount + + @amountActive.setter + def amountActive(self, i): + self.amount = max(i, self.getModifiedItemAttr("fighterSquadronMaxSize")) + @property def abilities(self): return self.__abilities or [] - @property def itemModifiedAttributes(self): return self.__itemModifiedAttributes @@ -117,17 +126,6 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): def charge(self): return self.__charge - @property - def dealsDamage(self): - for attr in ("emDamage", "kineticDamage", "explosiveDamage", "thermalDamage"): - if attr in self.itemModifiedAttributes or attr in self.chargeModifiedAttributes: - return True - - @property - def mines(self): - if "miningAmount" in self.itemModifiedAttributes: - return True - @property def hasAmmo(self): return self.charge is not None @@ -137,42 +135,26 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): return self.damageStats() def damageStats(self, targetResists = None): - if self.__dps == None: + if self.__dps is None: self.__volley = 0 self.__dps = 0 - if self.dealsDamage is True and self.amountActive > 0: - if self.hasAmmo: - attr = "missileLaunchDuration" - getter = self.getModifiedChargeAttr - else: - attr = "speed" - getter = self.getModifiedItemAttr + for ability in self.abilities: + if ability.dealsDamage and ability.active and self.amountActive > 0: + cycleTime = self.getModifiedItemAttr("{}Duration".format(ability.attrPrefix)) - cycleTime = self.getModifiedItemAttr(attr) + volley = sum(map(lambda d2, d: + (self.getModifiedItemAttr("{}Damage{}".format(ability.attrPrefix, d2)) or 0) * + (1-getattr(targetResists, "{}Amount".format(d), 0)), + self.DAMAGE_TYPES2, self.DAMAGE_TYPES)) - volley = sum(map(lambda d: (getter("%sDamage"%d) or 0) * (1-getattr(targetResists, "%sAmount"%d, 0)), self.DAMAGE_TYPES)) - volley *= self.amountActive - volley *= self.getModifiedItemAttr("damageMultiplier") or 1 - self.__volley = volley - self.__dps = volley / (cycleTime / 1000.0) + volley *= self.amountActive + print self.getModifiedItemAttr("{}DamageMultiplier".format(ability.attrPrefix)) + volley *= self.getModifiedItemAttr("{}DamageMultiplier".format(ability.attrPrefix)) or 1 + self.__volley += volley + self.__dps += volley / (cycleTime / 1000.0) return self.__dps, self.__volley - @property - def miningStats(self): - if self.__miningyield == None: - if self.mines is True and self.amountActive > 0: - attr = "duration" - getter = self.getModifiedItemAttr - - cycleTime = self.getModifiedItemAttr(attr) - volley = sum(map(lambda d: getter(d), self.MINING_ATTRIBUTES)) * self.amountActive - self.__miningyield = volley / (cycleTime / 1000.0) - else: - self.__miningyield = 0 - - return self.__miningyield - @property def maxRange(self): attrs = ("shieldTransferRange", "powerTransferRange", @@ -202,8 +184,8 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): map = {"ID": lambda val: isinstance(val, int), "itemID" : lambda val: isinstance(val, int), "chargeID" : lambda val: isinstance(val, int), - "amount" : lambda val: isinstance(val, int) and val >= 0, - "amountActive" : lambda val: isinstance(val, int) and val <= self.amount and val >= 0} + "amount" : lambda val: isinstance(val, int) and val >= -1, + } if map[key](val) == False: raise ValueError(str(val) + " is not a valid value for " + key) else: return val @@ -238,24 +220,22 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut): context = ("fighter",) projected = False - for effect in self.item.effects.itervalues(): - if effect.runTime == runTime and \ - ((projected == True and effect.isType("projected")) or \ - projected == False and effect.isType("passive")): - i = 0 - while i != self.amountActive: - effect.handler(fit, self, context) - i += 1 - - if self.charge: - for effect in self.charge.effects.itervalues(): - if effect.runTime == runTime: - effect.handler(fit, self, ("fighterCharge",)) + for ability in self.abilities: + if ability.active: + effect = ability.effect + if effect.runTime == runTime and \ + ((projected and effect.isType("projected")) or not projected): + if ability.grouped: + effect.handler(fit, self, context) + else: + i = 0 + while i != self.amountActive: + effect.handler(fit, self, context) + i += 1 def __deepcopy__(self, memo): copy = Fighter(self.item) copy.amount = self.amount - copy.amountActive = self.amountActive return copy def fits(self, fit): diff --git a/eos/saveddata/fighterAbility.py b/eos/saveddata/fighterAbility.py index 3ed4536a7..0397e3215 100644 --- a/eos/saveddata/fighterAbility.py +++ b/eos/saveddata/fighterAbility.py @@ -53,4 +53,18 @@ class FighterAbility(object): @property def name(self): - return self.__effect.handlerName + return self.__effect.getattr('displayName') or self.__effect.handlerName + + @property + def attrPrefix(self): + return self.__effect.getattr('prefix') + + @property + def dealsDamage(self): + attr = "{}DamageMultiplier".format(self.attrPrefix) + return attr in self.fighter.itemModifiedAttributes + + @property + def grouped(self): + # is the ability applied per fighter (webs, returns False), or as a group (MWD, returned True) + return self.__effect.getattr('grouped') \ No newline at end of file diff --git a/gui/builtinViewColumns/baseName.py b/gui/builtinViewColumns/baseName.py index edb45044e..7231d923e 100644 --- a/gui/builtinViewColumns/baseName.py +++ b/gui/builtinViewColumns/baseName.py @@ -22,7 +22,7 @@ from gui.viewColumn import ViewColumn import gui.mainFrame import wx -from eos.types import Drone, Cargo, Fit, Module, Slot, Rack, Implant +from eos.types import Drone, Cargo, Fit, Module, Slot, Rack, Implant, Fighter import service class BaseName(ViewColumn): @@ -39,6 +39,8 @@ class BaseName(ViewColumn): def getText(self, stuff): if isinstance(stuff, Drone): return "%dx %s" % (stuff.amount, stuff.item.name) + if isinstance(stuff, Fighter): + return "%d/%d %s (dps: %.2f, volley: %.2f)" % (stuff.amountActive, stuff.getModifiedItemAttr("fighterSquadronMaxSize"), stuff.item.name, stuff.damageStats()[0], stuff.damageStats()[1]) elif isinstance(stuff, Cargo): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fit): diff --git a/service/fit.py b/service/fit.py index 3ee5995e7..a9d6e23a0 100644 --- a/service/fit.py +++ b/service/fit.py @@ -636,7 +636,7 @@ class Fit(object): fit.fighters.append(fighter) else: return False - fighter.amount += 1 + eos.db.commit() self.recalc(fit) return True @@ -646,10 +646,7 @@ class Fit(object): def removeFighter(self, fitID, i): fit = eos.db.getFit(fitID) f = fit.fighters[i] - f.amount -= 1 - - if f.amount == 0: - del fit.fighters[i] + fit.fighters.remove(f) eos.db.commit() self.recalc(fit)