Files
pyfa/eos/saveddata/damagePattern.py

264 lines
11 KiB
Python

# ===============================================================================
# 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/>.
# ===============================================================================
import re
import eos.db
BUILTINS = (
(-1, "Uniform", 25, 25, 25, 25),
(-2, "[Generic]EM", 1, 0, 0, 0),
(-3, "[Generic]Thermal", 0, 1, 0, 0),
(-4, "[Generic]Kinetic", 0, 0, 1, 0),
(-5, "[Generic]Explosive", 0, 0, 0, 1),
(-6, "[Bombs]Electron Bomb", 6400, 0, 0, 0),
(-7, "[Bombs]Scorch Bomb", 0, 6400, 0, 0),
(-8, "[Bombs]Concussion Bomb", 0, 0, 6400, 0),
(-9, "[Bombs]Shrapnel Bomb", 0, 0, 0, 6400),
(-10, "[Frequency Crystals][T2] Conflagration", 7.7, 7.7, 0, 0),
(-11, "[Frequency Crystals][T2] Scorch", 9, 2, 0, 0),
(-12, "[Frequency Crystals][T2] Gleam", 7, 7, 0, 0),
(-13, "[Frequency Crystals][T2] Aurora", 5, 3, 0, 0),
(-14, "[Frequency Crystals]Multifrequency", 7, 5, 0, 0),
(-15, "[Frequency Crystals]Gamma", 7, 4, 0, 0),
(-16, "[Frequency Crystals]Xray", 6, 4, 0, 0),
(-17, "[Frequency Crystals]Ultraviolet", 6, 3, 0, 0),
(-18, "[Frequency Crystals]Standard", 5, 3, 0, 0),
(-19, "[Frequency Crystals]Infrared", 5, 2, 0, 0),
(-20, "[Frequency Crystals]Microwave", 4, 2, 0, 0),
(-21, "[Frequency Crystals]Radio", 5, 0, 0, 0),
(-22, "[Hybrid Charges][T2] Void", 0, 7.7, 7.7, 0),
(-23, "[Hybrid Charges][T2] Null", 0, 6, 5, 0),
(-24, "[Hybrid Charges][T2] Javelin", 0, 8, 6, 0),
(-25, "[Hybrid Charges][T2] Spike", 0, 4, 4, 0),
(-26, "[Hybrid Charges]Antimatter", 0, 5, 7, 0),
(-27, "[Hybrid Charges]Plutonium", 0, 5, 6, 0),
(-28, "[Hybrid Charges]Uranium", 0, 4, 6, 0),
(-29, "[Hybrid Charges]Thorium", 0, 4, 5, 0),
(-30, "[Hybrid Charges]Lead", 0, 3, 5, 0),
(-31, "[Hybrid Charges]Iridium", 0, 3, 4, 0),
(-32, "[Hybrid Charges]Tungsten", 0, 2, 4, 0),
(-33, "[Hybrid Charges]Iron", 0, 2, 3, 0),
(-34, "[Missiles]Mjolnir", 1, 0, 0, 0),
(-35, "[Missiles]Inferno", 0, 1, 0, 0),
(-36, "[Missiles]Scourge", 0, 0, 1, 0),
(-37, "[Missiles]Nova", 0, 0, 0, 1),
(-38, "[Missiles][Structure] Standup Missile", 1, 1, 1, 1),
(-39, "[Projectile Ammo][T2] Hail", 0, 0, 3.3, 12.1),
(-40, "[Projectile Ammo][T2] Barrage", 0, 0, 5, 6),
(-41, "[Projectile Ammo][T2] Quake", 0, 0, 5, 9),
(-42, "[Projectile Ammo][T2] Tremor", 0, 0, 3, 5),
(-43, "[Projectile Ammo]EMP", 9, 0, 1, 2),
(-44, "[Projectile Ammo]Phased Plasma", 0, 10, 2, 0),
(-45, "[Projectile Ammo]Fusion", 0, 0, 2, 10),
(-46, "[Projectile Ammo]Depleted Uranium", 0, 3, 2, 3),
(-47, "[Projectile Ammo]Titanium Sabot", 0, 0, 6, 2),
(-48, "[Projectile Ammo]Proton", 3, 0, 2, 0),
(-49, "[Projectile Ammo]Carbonized Lead", 0, 0, 4, 1),
(-50, "[Projectile Ammo]Nuclear", 0, 0, 1, 4),
# Different sizes of plasma do different damage, the values here are
# average of proportions across sizes
(-51, "[Exotic Plasma][T2] Occult", 0, 55863, 0, 44137),
(-52, "[Exotic Plasma][T2] Mystic", 0, 66319, 0, 33681),
(-53, "[Exotic Plasma]Tetryon", 0, 69208, 0, 30792),
(-54, "[Exotic Plasma]Baryon", 0, 59737, 0, 40263),
(-55, "[Exotic Plasma]Meson", 0, 60519, 0, 39481),
(-56, "[NPC][Asteroid] Angel Cartel", 1838, 562, 2215, 3838),
(-57, "[NPC][Asteroid] Blood Raiders", 5067, 4214, 0, 0),
(-58, "[NPC][Asteroid] Guristas", 0, 1828, 7413, 0),
(-59, "[NPC][Asteroid] Rogue Drone", 394, 666, 1090, 1687),
(-60, "[NPC][Asteroid] Sanshas Nation", 5586, 4112, 0, 0),
(-61, "[NPC][Asteroid] Serpentis", 0, 5373, 4813, 0),
(-62, "[NPC][Deadspace] Angel Cartel", 369, 533, 1395, 3302),
(-63, "[NPC][Deadspace] Blood Raiders", 6040, 5052, 10, 15),
(-64, "[NPC][Deadspace] Guristas", 0, 1531, 9680, 0),
(-65, "[NPC][Deadspace] Rogue Drone", 276, 1071, 1069, 871),
(-66, "[NPC][Deadspace] Sanshas Nation", 3009, 2237, 0, 0),
(-67, "[NPC][Deadspace] Serpentis", 0, 3110, 1929, 0),
(-68, "[NPC][Mission] Amarr Empire", 4464, 3546, 97, 0),
(-69, "[NPC][Mission] Caldari State", 0, 2139, 4867, 0),
(-70, "[NPC][Mission] CONCORD", 336, 134, 212, 412),
(-71, "[NPC][Mission] Gallente Federation", 9, 3712, 2758, 0),
(-72, "[NPC][Mission] Khanid", 612, 483, 43, 6),
(-73, "[NPC][Mission] Minmatar Republic", 1024, 388, 1655, 4285),
(-74, "[NPC][Mission] Mordus Legion", 25, 262, 625, 0),
(-75, "[NPC][Mission] Thukker", 0, 52, 10, 79),
(-76, "[NPC][Burner] Cruor (Blood Raiders)", 90, 90, 0, 0),
(-77, "[NPC][Burner] Dramiel (Angel)", 55, 0, 20, 96),
(-78, "[NPC][Burner] Daredevil (Serpentis)", 0, 110, 154, 0),
(-79, "[NPC][Burner] Succubus (Sanshas Nation)", 135, 30, 0, 0),
(-80, "[NPC][Burner] Worm (Guristas)", 0, 0, 228, 0),
(-81, "[NPC][Burner] Enyo", 0, 147, 147, 0),
(-82, "[NPC][Burner] Hawk", 0, 0, 247, 0),
(-83, "[NPC][Burner] Jaguar", 36, 0, 50, 182),
(-84, "[NPC][Burner] Vengeance", 232, 0, 0, 0),
(-85, "[NPC][Burner] Ashimmu (Blood Raiders)", 260, 100, 0, 0),
(-86, "[NPC][Burner] Talos", 0, 413, 413, 0),
(-87, "[NPC][Burner] Sentinel", 0, 75, 0, 90),
(-88, "[NPC][Other] Sleepers", 1472, 1472, 1384, 1384),
(-89, "[NPC][Other] Sansha Incursion", 1682, 1347, 3678, 3678))
class DamagePattern:
DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive")
_builtins = None
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
def update(self, emAmount=25, thermalAmount=25, kineticAmount=25, explosiveAmount=25):
self.emAmount = emAmount
self.thermalAmount = thermalAmount
self.kineticAmount = kineticAmount
self.explosiveAmount = explosiveAmount
@classmethod
def getBuiltins(cls):
if cls._builtins is None:
cls._builtins = []
for id, name, em, therm, kin, explo in BUILTINS:
pattern = DamagePattern(emAmount=em, thermalAmount=therm, kineticAmount=kin, explosiveAmount=explo)
pattern.ID = id
pattern.name = name
cls._builtins.append(pattern)
return cls._builtins
def calculateEhp(self, fit):
ehp = {}
for (type, attr) in (('shield', 'shieldCapacity'), ('armor', 'armorHP'), ('hull', 'hp')):
rawCapacity = fit.ship.getModifiedItemAttr(attr)
ehp[type] = self.effectivify(fit, rawCapacity, type)
return ehp
def calculateEffectiveTank(self, fit, tankInfo):
typeMap = {
"passiveShield": "shield",
"shieldRepair": "shield",
"armorRepair": "armor",
"armorRepairPreSpool": "armor",
"armorRepairFullSpool": "armor",
"hullRepair": "hull"}
ereps = {}
for field in tankInfo:
if field in typeMap:
ereps[field] = self.effectivify(fit, tankInfo[field], typeMap[field])
return ereps
def effectivify(self, fit, amount, type):
type = type if type != "hull" else ""
totalDamage = sum((self.emAmount, self.thermalAmount, self.kineticAmount, self.explosiveAmount))
specificDivider = 0
for damageType in self.DAMAGE_TYPES:
# Compose an attribute name, then make sure the first letter is NOT capitalized
attrName = "%s%sDamageResonance" % (type, damageType.capitalize())
attrName = attrName[0].lower() + attrName[1:]
resonance = fit.ship.getModifiedItemAttr(attrName)
damage = getattr(self, "%sAmount" % damageType)
specificDivider += damage / float(totalDamage or 1) * resonance
return amount / (specificDivider or 1)
importMap = {
"em" : "em",
"therm": "thermal",
"kin" : "kinetic",
"exp" : "explosive"
}
@classmethod
def oneType(cls, damageType, amount=100):
pattern = DamagePattern()
pattern.update(amount if damageType == "em" else 0,
amount if damageType == "thermal" else 0,
amount if damageType == "kinetic" else 0,
amount if damageType == "explosive" else 0)
return pattern
@classmethod
def importPatterns(cls, text):
lines = re.split('[\n\r]+', text)
patterns = []
numPatterns = 0
# When we import damage profiles, we create new ones and update old ones. To do this, get a list of current
# patterns to allow lookup
lookup = {}
current = eos.db.getDamagePatternList()
for pattern in current:
lookup[pattern.name] = pattern
for line in lines:
try:
if line.strip()[0] == "#": # comments
continue
line = line.split('#', 1)[0] # allows for comments
type, data = line.rsplit('=', 1)
type, data = type.strip(), data.split(',')
except:
# Data isn't in correct format, continue to next line
continue
if type != "DamageProfile":
continue
numPatterns += 1
name, data = data[0], data[1:5]
fields = {}
for index, val in enumerate(data):
try:
fields["%sAmount" % cls.DAMAGE_TYPES[index]] = int(val)
except:
continue
if len(fields) == 4: # Avoid possible blank lines
if name.strip() in lookup:
pattern = lookup[name.strip()]
pattern.update(**fields)
eos.db.save(pattern)
else:
pattern = DamagePattern(**fields)
pattern.name = name.strip()
eos.db.save(pattern)
patterns.append(pattern)
eos.db.commit()
return patterns, numPatterns
EXPORT_FORMAT = "DamageProfile = %s,%d,%d,%d,%d\n"
@classmethod
def exportPatterns(cls, *patterns):
out = "# Exported from pyfa\n#\n"
out += "# Values are in following format:\n"
out += "# DamageProfile = [name],[EM amount],[Thermal amount],[Kinetic amount],[Explosive amount]\n\n"
for dp in patterns:
out += cls.EXPORT_FORMAT % (dp.name, dp.emAmount, dp.thermalAmount, dp.kineticAmount, dp.explosiveAmount)
return out.strip()
def __deepcopy__(self, memo):
p = DamagePattern(self.emAmount, self.thermalAmount, self.kineticAmount, self.explosiveAmount)
p.name = "%s copy" % self.name
return p