Merge branch 'singularity'

This commit is contained in:
DarkPhoenix
2014-12-09 23:39:57 +03:00
46 changed files with 384 additions and 37 deletions

View File

@@ -40,6 +40,15 @@ gamedata_meta = MetaData()
gamedata_meta.bind = gamedata_engine
gamedata_session = sessionmaker(bind=gamedata_engine, autoflush=False, expire_on_commit=False)()
# This should be moved elsewhere, maybe as an actual query. Current, without try-except, it breaks when making a new
# game db because we haven't reached gamedata_meta.create_all()
try:
config.gamedata_version = gamedata_session.execute(
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'"
).fetchone()[0]
except:
config.gamedata_version = None
saveddata_connectionstring = config.saveddata_connectionstring
if saveddata_connectionstring is not None:
if callable(saveddata_connectionstring):
@@ -75,3 +84,4 @@ if config.saveddata_connectionstring == "sqlite:///:memory:":
def rollback():
with sd_lock:
saveddata_session.rollback()

View File

@@ -0,0 +1,13 @@
"""
Migration 3
- Adds mode column for fits (t3 dessy)
"""
import sqlalchemy
def upgrade(saveddata_engine):
try:
saveddata_engine.execute("SELECT mode FROM fits LIMIT 1")
except sqlalchemy.exc.DatabaseError:
saveddata_engine.execute("ALTER TABLE fits ADD COLUMN modeID INTEGER")

View File

@@ -40,7 +40,9 @@ fits_table = Table("fits", saveddata_meta,
Column("characterID", ForeignKey("characters.ID"), nullable = True),
Column("damagePatternID", ForeignKey("damagePatterns.ID"), nullable=True),
Column("booster", Boolean, nullable = False, index = True, default = 0),
Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True))
Column("targetResistsID", ForeignKey("targetResists.ID"), nullable=True),
Column("modeID", Integer, nullable=True),
)
projectedFits_table = Table("projectedFits", saveddata_meta,
Column("sourceID", ForeignKey("fits.ID"), primary_key = True),

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, ship, context):
level = fit.character.getSkill("ORE Freighter").level
fit.ship.boostItemAttr("shipMaintenanceBayCapacity", ship.getModifiedItemAttr("freighterBonusO1")*level)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, ship, context):
level = fit.character.getSkill("ORE Freighter").level
fit.ship.boostItemAttr("agility", ship.getModifiedItemAttr("freighterBonusO2")*level,
stackingPenalties = True)

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, module, context):
fit.ship.multiplyItemAttr("agility", 1/module.getModifiedItemAttr("modeAgilityPostDiv"),
stackingPenalties = True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,11 @@
type = "passive"
def handler(fit, module, context):
for resType in ("Em", "Explosive", "Kinetic"):
fit.ship.multiplyItemAttr("armor{0}DamageResonance".format(resType),
1/module.getModifiedItemAttr("mode{0}ResistancePostDiv".format(resType)),
stackingPenalties = True, penaltyGroup="postDiv")
# Thermal != Thermic
fit.ship.multiplyItemAttr("armorThermalDamageResonance",
1/module.getModifiedItemAttr("modeThermicResistancePostDiv"),
stackingPenalties = True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, module, context):
level = fit.character.getSkill("Minmatar Destroyer").level
fit.ship.multiplyItemAttr("signatureRadius", 1/module.getModifiedItemAttr("modeSignatureRadiusPostDiv"),
stackingPenalties = True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, module, context):
fit.ship.multiplyItemAttr("maxVelocity", 1/module.getModifiedItemAttr("modeVelocityPostDiv"),
stackingPenalties = True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, ship, context):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Astrometrics"),
"cpu", ship.getModifiedItemAttr("roleBonusTacticalDestroyer1"))

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, ship, context):
level = fit.character.getSkill("Amarr Tactical Destroyer").level
fit.modules.filteredItemBoost(lambda mod: True, "heatDamage",
ship.getModifiedItemAttr("shipBonusTacticalDestroyerAmarr3") * level)

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, module, context):
fit.ship.multiplyItemAttr("maxTargetRange", 1/module.getModifiedItemAttr("modeMaxTargetRangePostDiv"),
stackingPenalties = True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, module, context):
fit.ship.multiplyItemAttr("scanResolution", 1/module.getModifiedItemAttr("modeScanResPostDiv"),
stackingPenalties = True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,4 @@
type = "passive"
def handler(fit, module, context):
fit.ship.multiplyItemAttr("scanRadarStrength", 1/module.getModifiedItemAttr("modeRadarStrengthPostDiv"),
stackingPenalties = True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, module, context):
fit.modules.filteredItemMultiply(lambda mod: mod.item.requiresSkill("Small Energy Turret"),
"maxRange", 1/module.getModifiedItemAttr("modeMaxRangePostDiv"),
stackingPenalties=True, penaltyGroup="postDiv")

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, ship, context):
level = fit.character.getSkill("Amarr Tactical Destroyer").level
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Energy Turret"),
"capacitorNeed", ship.getModifiedItemAttr("shipBonusTacticalDestroyerAmarr2") * level)

View File

@@ -0,0 +1,5 @@
type = "passive"
def handler(fit, ship, context):
level = fit.character.getSkill("Amarr Tactical Destroyer").level
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Small Energy Turret"),
"damageMultiplier", ship.getModifiedItemAttr("shipBonusTacticalDestroyerAmarr1") * level)

View File

@@ -27,6 +27,7 @@ from copy import deepcopy
from math import sqrt, log, asinh
from eos.types import Drone, Cargo, Ship, Character, State, Slot, Module, Implant, Booster, Skill
from eos.saveddata.module import State
from eos.saveddata.mode import Mode
import time
try:
@@ -66,6 +67,7 @@ class Fit(object):
self.gangBoosts = None
self.timestamp = time.time()
self.ecmProjectedStr = 1
self.modeID = None
self.build()
@reconstructor
@@ -99,6 +101,10 @@ class Fit(object):
self.extraAttributes = ModifiedAttributeDict(self)
self.extraAttributes.original = self.EXTRA_ATTRIBUTES
self.ship = Ship(db.getItem(self.shipID)) if self.shipID is not None else None
if self.ship is not None:
self.mode = self.ship.checkModeItem(db.getItem(self.modeID) if self.modeID else None)
else:
self.mode = None
@property
def targetResists(self):
@@ -122,6 +128,15 @@ class Fit(object):
self.__ehp = None
self.__effectiveTank = None
@property
def mode(self):
return self._mode
@mode.setter
def mode(self, mode):
self._mode = mode
self.modeID = mode.item.ID if mode is not None else None
@property
def character(self):
return self.__character if self.__character is not None else Character.getAll0()
@@ -369,9 +384,9 @@ class Fit(object):
# Avoid adding projected drones and modules when fit is projected onto self
# TODO: remove this workaround when proper self-projection using virtual duplicate fits is implemented
if forceProjected is True:
c = chain((self.character, self.ship), self.drones, self.boosters, self.appliedImplants, self.modules)
c = chain((self.character, self.ship, self.mode), self.drones, self.boosters, self.appliedImplants, self.modules)
else:
c = chain((self.character, self.ship), self.drones, self.boosters, self.appliedImplants, self.modules,
c = chain((self.character, self.ship, self.mode), self.drones, self.boosters, self.appliedImplants, self.modules,
self.projectedDrones, self.projectedModules)
if self.gangBoosts is not None:
@@ -494,6 +509,10 @@ class Fit(object):
Slot.RIG: "rigSlots",
Slot.SUBSYSTEM: "maxSubSystems"}
if type == Slot.MODE:
# Mode slot doesn't really exist, return default 0
return 0
slotsUsed = self.getSlotsUsed(type, countDummies)
totalSlots = self.ship.getModifiedItemAttr(slots[type]) or 0
return int(totalSlots - slotsUsed)

65
eos/saveddata/mode.py Normal file
View File

@@ -0,0 +1,65 @@
#===============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of eos.
#
# eos is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# eos is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with eos. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
from eos.effectHandlerHelpers import HandledItem
class Mode(ItemAttrShortcut, HandledItem):
def __init__(self, item):
self.__item = item
self.__itemModifiedAttributes = ModifiedAttributeDict()
if not isinstance(item, int):
self.__buildOriginal()
def __fetchItemInfo(self):
import eos.db
self.__item = eos.db.getItem(self.__item)
self.__buildOriginal()
def __buildOriginal(self):
self.__itemModifiedAttributes.original = self.item.attributes
@property
def item(self):
if isinstance(self.__item, int):
self.__fetchItemInfo()
return self.__item
@property
def itemModifiedAttributes(self):
if isinstance(self.__item, int):
self.__fetchItemInfo()
return self.__itemModifiedAttributes
# @todo: rework to fit only on t3 dessy
def fits(self, fit):
raise NotImplementedError()
def clear(self):
self.itemModifiedAttributes.clear()
def calculateModifiedAttributes(self, fit, runTime, forceProjected = False):
if self.item:
for effect in self.item.effects.itervalues():
if effect.runTime == runTime:
effect.handler(fit, self, context = ("module",))

View File

@@ -36,6 +36,7 @@ class Slot(Enum):
HIGH = 3
RIG = 4
SUBSYSTEM = 5
MODE = 6 # not a real slot, need for pyfa display rack separation
class Hardpoint(Enum):
NONE = 0

View File

@@ -19,6 +19,7 @@
from eos.modifiedAttributeDict import ModifiedAttributeDict, ItemAttrShortcut
from eos.effectHandlerHelpers import HandledItem
from eos.saveddata.mode import Mode
class Ship(ItemAttrShortcut, HandledItem):
def __init__(self, item):
@@ -65,6 +66,52 @@ class Ship(ItemAttrShortcut, HandledItem):
if effect.runTime == runTime and effect.isType("passive"):
effect.handler(fit, self, ("ship",))
def checkModeItem(self, item):
"""
Checks if provided item is a valid mode.
If ship has modes, and current item is not valid, return forced mode
else if mode is valid, return Mode
else if ship does not have modes, return None
@todo: rename this
"""
items = self.getModeItems()
if items != None:
if item == None or item not in items:
# We have a tact dessy, but mode is None or not valid. Force new mode
return Mode(items[0])
elif item in items:
# We have a valid mode
return Mode(item)
return None
def getModes(self):
items = self.getModeItems()
return [Mode(item) for item in items] if items else None
def getModeItems(self):
"""
Returns a list of valid mode items for ship. Note that this returns the
valid Item objects, not the Mode objects. Returns None if not a
t3 dessy
"""
# @todo: is there a better way to determine this that isn't hardcoded groupIDs?
if self.item.groupID != 1305:
return None
modeGroupID = 1306
import eos.db
items = []
g = eos.db.getGroup(modeGroupID, eager=("items.icon", "items.attributes"))
for item in g.items:
if item.raceID == self.item.raceID:
items.append(item)
return items
def __deepcopy__(self, memo):
copy = Ship(self.item)
return copy

View File

@@ -32,6 +32,7 @@ from eos.saveddata.booster import SideEffect
from eos.saveddata.booster import Booster
from eos.saveddata.ship import Ship
from eos.saveddata.fit import Fit
from eos.saveddata.mode import Mode
from eos.saveddata.fleet import Fleet, Wing, Squad
from eos.saveddata.miscData import MiscData
import eos.db