Add destructible beacons to projected effects

This commit is contained in:
DarkPhoenix
2020-06-17 17:07:34 +03:00
parent c3f1824a84
commit 3094fd32fc
6 changed files with 210 additions and 123 deletions

View File

@@ -33,7 +33,7 @@ DB_PATH = os.path.join(ROOT_DIR, 'eve.db')
JSON_DIR = os.path.join(ROOT_DIR, 'staticdata')
if ROOT_DIR not in sys.path:
sys.path.insert(0, ROOT_DIR)
GAMEDATA_SCHEMA_VERSION = 3
GAMEDATA_SCHEMA_VERSION = 4
def db_needs_update():
@@ -122,7 +122,8 @@ def update_db():
if (
# Apparently people really want Civilian modules available
(row['typeName'].startswith('Civilian') and "Shuttle" not in row['typeName']) or
row['typeName'] == 'Capsule'
row['typeName'] == 'Capsule' or
row['groupID'] == 4033 # destructible effect beacons
):
row['published'] = True
# Nearly useless and clutter search results too much
@@ -142,8 +143,7 @@ def update_db():
1882,
1975,
1971,
# the "container" for the abyssal environments
1983)
1983) # the "container" for the abyssal environments
):
newData.append(row)

View File

@@ -60,6 +60,7 @@ class Effect10(BaseEffect):
targetAttack
Used by:
Celestials from group: Destructible Effect Beacon (6 of 6)
Drones from group: Combat Drone (75 of 75)
Modules from group: Energy Weapon (212 of 214)
"""
@@ -12419,6 +12420,8 @@ class Effect3992(BaseEffect):
Used by:
Celestials named like: Class Pulsar Effects (6 of 6)
Celestial: Republic Stellar Observatory
Celestial: State Stellar Observatory
"""
runTime = 'early'
@@ -13212,6 +13215,7 @@ class Effect4088(BaseEffect):
Used by:
Celestials named like: Class Cataclysmic Variable Effects (6 of 6)
Celestial: Dazh Liminality Locus
"""
runTime = 'early'
@@ -13230,6 +13234,7 @@ class Effect4089(BaseEffect):
Used by:
Celestials named like: Class Cataclysmic Variable Effects (6 of 6)
Celestial: Dazh Liminality Locus
"""
runTime = 'early'
@@ -23144,6 +23149,8 @@ class Effect5913(BaseEffect):
Used by:
Celestials named like: Class Wolf Rayet Effects (6 of 6)
Celestial: Federal Stellar Observatory
Celestial: Imperial Stellar Observatory
"""
runTime = 'early'
@@ -23160,6 +23167,7 @@ class Effect5914(BaseEffect):
Used by:
Celestials named like: Class Pulsar Effects (6 of 6)
Celestial: Imperial Stellar Observatory
"""
runTime = 'early'
@@ -23179,6 +23187,7 @@ class Effect5915(BaseEffect):
Used by:
Celestials named like: Class Pulsar Effects (6 of 6)
Celestial: Imperial Stellar Observatory
"""
runTime = 'early'
@@ -23306,6 +23315,7 @@ class Effect5922(BaseEffect):
Used by:
Celestials named like: Class Black Hole Effects (6 of 6)
Celestial: Republic Stellar Observatory
"""
runTime = 'early'
@@ -35838,6 +35848,7 @@ class Effect7193(BaseEffect):
systemMiningCycleTimeBonus
Used by:
Celestials named like: Stellar Observatory (4 of 4)
Celestials named like: Triglavian Invasion System Effects (3 of 3)
"""
@@ -35846,8 +35857,8 @@ class Effect7193(BaseEffect):
@staticmethod
def handler(fit, beacon, context, projectionRange, **kwargs):
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Mining'),
'duration', beacon.getModifiedItemAttr('miningDurationMultiplier'), **kwargs)
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Mining'), 'duration',
beacon.getModifiedItemAttr('miningDurationMultiplier'), **kwargs)
class Effect7202(BaseEffect):
@@ -36151,6 +36162,23 @@ class Effect7234(BaseEffect):
implant.getModifiedItemAttr('setBonusMimesis'), **kwargs)
class Effect7237(BaseEffect):
"""
systemWarpSpeed
Used by:
Celestial: Dazh Liminality Locus
"""
runTime = 'early'
type = ('projected', 'passive')
@staticmethod
def handler(fit, beacon, context, projectionRange, **kwargs):
fit.ship.boostItemAttr('warpSpeedMultiplier', beacon.getModifiedItemAttr('warpSpeedBonus'),
stackingPenalties=True, **kwargs)
class Effect7238(BaseEffect):
"""
shipBonusDreadnoughtPC1DamageMultMax
@@ -36423,6 +36451,58 @@ class Effect8029(BaseEffect):
attr, ship.getModifiedItemAttr('shipBonusRole7'), **kwargs)
class Effect8031(BaseEffect):
"""
systemMaxTargets
Used by:
Celestial: Dazh Liminality Locus
"""
runTime = 'early'
type = ('projected', 'passive')
@staticmethod
def handler(fit, beacon, context, projectionRange, **kwargs):
fit.ship.multiplyItemAttr('maxLockedTargets', beacon.getModifiedItemAttr('maxLockedTargetsMultiplier'), **kwargs)
class Effect8032(BaseEffect):
"""
systemWarpScrambleStrengthBonus
Used by:
Celestial: Federal Stellar Observatory
"""
runTime = 'early'
type = ('projected', 'passive')
@staticmethod
def handler(fit, beacon, context, projectionRange, **kwargs):
fit.modules.filteredItemIncrease(
lambda mod: mod.item.group.name == 'Warp Scrambler',
'warpScrambleStrength', beacon.getModifiedItemAttr('warpScrambleStrengthBonus'), **kwargs)
class Effect8033(BaseEffect):
"""
systemEcmRangeMultiplier
Used by:
Celestial: State Stellar Observatory
"""
runTime = 'early'
type = ('projected', 'passive')
@staticmethod
def handler(fit, beacon, context, projectionRange, **kwargs):
fit.modules.filteredItemMultiply(
lambda mod: mod.item.group.name == 'ECM', 'maxRange',
beacon.getModifiedItemAttr('ecmRangeBonus'), stackingPenalties=True, **kwargs)
class Effect8034(BaseEffect):
"""
smallUpwellWeaponDmgBonusRequiredSkill

View File

@@ -21,7 +21,7 @@ import datetime
import time
from copy import deepcopy
from itertools import chain
from math import log, sqrt
from math import floor, log, sqrt
from logbook import Logger
from sqlalchemy.orm import reconstructor, validates
@@ -39,6 +39,7 @@ from eos.saveddata.damagePattern import DamagePattern
from eos.saveddata.module import Module
from eos.saveddata.ship import Ship
from eos.saveddata.targetProfile import TargetProfile
from eos.utils.float import floatUnerr
from eos.utils.stats import DmgTypes, RRTypes
@@ -378,8 +379,9 @@ class Fit:
@property
def maxTargets(self):
return min(self.extraAttributes["maxTargetsLockedFromSkills"],
self.ship.getModifiedItemAttr("maxLockedTargets"))
maxTargets = min(self.extraAttributes["maxTargetsLockedFromSkills"],
self.ship.getModifiedItemAttr("maxLockedTargets"))
return floor(floatUnerr(maxTargets))
@property
def maxTargetRange(self):

View File

@@ -64,7 +64,9 @@ ProjectedSystem = {
class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
"""An instance of this class represents a module together with its charge and modified attributes"""
MINING_ATTRIBUTES = ("miningAmount",)
SYSTEM_GROUPS = ("Effect Beacon", "MassiveEnvironments", "Abyssal Hazards", "Non-Interactable Object")
SYSTEM_GROUPS = (
"Effect Beacon", "MassiveEnvironments", "Abyssal Hazards",
"Non-Interactable Object", "Destructible Effect Beacon")
def __init__(self, item, baseItem=None, mutaplasmid=None):
"""Initialize a module from the program"""
@@ -726,6 +728,9 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
return False
elif state == FittingModuleState.OVERHEATED and not self.item.isType("overheat"):
return False
# Some destructible effect beacons contain active effects, hardcap those at online state
elif state > FittingModuleState.ONLINE and self.slot == FittingSlot.SYSTEM:
return False
else:
return True
@@ -1051,7 +1056,10 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
elif click == "ctrl":
state = FittingModuleState.OFFLINE
else:
state = transitionMap[currState]
try:
state = transitionMap[currState]
except KeyError:
state = min(transitionMap)
# If passive module tries to transition into online and fails,
# put it to passive instead
if not mod.isValidState(state) and currState == FittingModuleState.ONLINE:

View File

@@ -1,4 +1,5 @@
import re
from collections import OrderedDict
from itertools import chain
# noinspection PyPackageRequirements
@@ -10,6 +11,28 @@ from gui.contextMenu import ContextMenuUnconditional
from service.market import Market
class Group:
def __init__(self):
self.groups = OrderedDict()
self.items = []
def sort(self):
self.groups = OrderedDict((k, self.groups[k]) for k in sorted(self.groups))
for group in self.groups.values():
group.sort()
self.items.sort(key=lambda e: e.short_name)
class Entry:
def __init__(self, item, name, short_name):
self.item = item
self.name = name
self.short_name = short_name
class AddEnvironmentEffect(ContextMenuUnconditional):
# CCP doesn't currently provide a mapping between the general Environment, and the specific environment effect
@@ -25,6 +48,7 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.idmap = {}
def display(self, callingWindow, srcContext):
return srcContext == "projected"
@@ -33,103 +57,70 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
return "Add Environmental Effect"
def getSubMenu(self, callingWindow, context, rootMenu, i, pitem):
msw = True if "wxMSW" in wx.PlatformInfo else False
data = self.getData()
msw = "wxMSW" in wx.PlatformInfo
# Wormholes
def addGroup(parentMenu, name):
id = ContextMenuUnconditional.nextID()
menuItem = wx.MenuItem(parentMenu, id, name)
parentMenu.Bind(wx.EVT_MENU, self.handleSelection, menuItem)
return menuItem
self.idmap = {}
sub = wx.Menu()
def addEffect(parentMenu, effect, name):
id = ContextMenuUnconditional.nextID()
self.idmap[id] = effect
menuItem = wx.MenuItem(parentMenu, id, name)
parentMenu.Bind(wx.EVT_MENU, self.handleSelection, menuItem)
return menuItem
wormhole_item = wx.MenuItem(sub, wx.ID_ANY, "Wormhole")
wormhole_menu = wx.Menu()
wormhole_item.SetSubMenu(wormhole_menu)
sub.Append(wormhole_item)
grouped_data, flat_data = self.getEffectBeacons()
self.buildMenu(grouped_data, flat_data, wormhole_menu, rootMenu, msw)
# Incursions
grouped_data, flat_data = self.getEffectBeacons(incursions=True)
self.buildMenu(grouped_data, flat_data, sub, rootMenu, msw)
# Abyssal Weather
abyssal_item = wx.MenuItem(sub, wx.ID_ANY, "Abyssal Weather")
abyssal_menu = wx.Menu()
abyssal_item.SetSubMenu(abyssal_menu)
sub.Append(abyssal_item)
grouped_data, flat_data = self.getAbyssalWeather()
self.buildMenu(grouped_data, flat_data, abyssal_menu, rootMenu, msw)
# Localized Weather
local_item = wx.MenuItem(sub, wx.ID_ANY, "Localized")
local_menu = wx.Menu()
local_item.SetSubMenu(local_menu)
sub.Append(local_item)
grouped_data, flat_data = self.getLocalizedEnvironments()
self.buildMenu(grouped_data, flat_data, local_menu, rootMenu, msw)
def makeMenu(data, parentMenu):
menu = wx.Menu()
for group_name in data.groups:
menuItem = addGroup(rootMenu if msw else parentMenu, group_name)
subMenu = makeMenu(data.groups[group_name], menu)
menuItem.SetSubMenu(subMenu)
menu.Append(menuItem)
items = data.items
for entry in items:
menuItem = addEffect(rootMenu if msw else parentMenu, entry.item, entry.short_name)
menu.Append(menuItem)
menu.Bind(wx.EVT_MENU, self.handleSelection)
return menu
sub = makeMenu(data, rootMenu)
return sub
def handleSelection(self, event):
# Skip events ids that aren't mapped
swObj, swName = self.idmap.get(event.Id, (False, False))
if not swObj and not swName:
swObj = self.idmap.get(event.Id, False)
if not swObj:
event.Skip()
return
fitID = self.mainFrame.getActiveFit()
self.mainFrame.command.Submit(cmd.GuiAddProjectedModuleCommand(fitID, swObj.ID))
def buildMenu(self, grouped_data, flat_data, local_menu, rootMenu, msw):
def getData(self):
data = Group()
data.groups['Wormhole'] = self.getEffectBeacons(
'Black Hole', 'Cataclysmic Variable', 'Magnetar',
'Pulsar', 'Red Giant', 'Wolf Rayet')
data.groups['Sansha Incursion'] = self.getEffectBeacons('Sansha Incursion')
data.groups['Triglavian Invasion'] = self.getEffectBeacons('Triglavian Invasion')
data.groups['Triglavian Invasion'].groups['Destructible Beacons'] = self.getDestructibleBeacons()
data.groups['Abyssal Weather'] = self.getAbyssalWeather()
return data
def processFlat(data, root, sub):
for swData in sorted(data, key=lambda tpl: tpl[2]):
wxid = ContextMenuUnconditional.nextID()
swObj, swName, swClass = swData
self.idmap[wxid] = (swObj, swName)
subItem = wx.MenuItem(sub, wxid, swClass)
if msw:
root.Bind(wx.EVT_MENU, self.handleSelection, subItem)
else:
sub.Bind(wx.EVT_MENU, self.handleSelection, subItem)
sub.Append(subItem)
for swType in sorted(grouped_data):
subItem = wx.MenuItem(local_menu, wx.ID_ANY, swType)
grandSub = wx.Menu()
subItem.SetSubMenu(grandSub)
local_menu.Append(subItem)
processFlat(grouped_data[swType], rootMenu, grandSub)
processFlat(flat_data, rootMenu, local_menu)
def getEffectBeacons(self, incursions=False):
def getEffectBeacons(self, *groups):
"""
Get dictionary with wormhole system-wide effects
"""
compacted = len(groups) <= 1
sMkt = Market.getInstance()
# todo: rework this
# Container for system-wide effects
grouped = {}
# Expressions for matching when detecting effects we're looking for
if incursions:
validgroups = ("Sansha Incursion",
"Triglavian Invasion")
else:
validgroups = ("Black Hole",
"Cataclysmic Variable",
"Magnetar",
"Pulsar",
"Red Giant",
"Wolf Rayet")
data = Group()
# Stuff we don't want to see in names
garbages = ("System Effects", "Effects")
@@ -140,7 +131,7 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
# Cycle through them
for beacon in sMkt.getItemsByGroup(grp):
# Check if it belongs to any valid group
for group in validgroups:
for group in groups:
# Check beginning of the name only
if re.search(group, beacon.name):
# Get full beacon name
@@ -159,22 +150,25 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
groupname = re.sub(garbage, "", groupname)
groupname = re.sub(" {2,}", " ", groupname).strip()
# Add stuff to dictionary
if groupname not in grouped:
grouped[groupname] = set()
grouped[groupname].add((beacon, beaconname, shortname))
if compacted:
container = data.items
else:
container = data.groups.setdefault(groupname, Group()).items
container.append(Entry(beacon, beaconname, shortname))
# Break loop on 1st result
break
return grouped, ()
data.sort()
return data
def getAbyssalWeather(self):
sMkt = Market.getInstance()
environments = {x.ID: x for x in sMkt.getGroup("Abyssal Environment").items}
items = chain(sMkt.getGroup("MassiveEnvironments").items, sMkt.getGroup("Non-Interactable Object").items)
items = chain(
sMkt.getGroup("MassiveEnvironments").items,
sMkt.getGroup("Non-Interactable Object").items)
grouped = {}
flat = set()
data = Group()
for beacon in items:
if not beacon.isType('projected'):
@@ -185,38 +179,40 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
if type is None:
continue
if type.name not in grouped:
grouped[type.name] = set()
subdata = data.groups.setdefault(type.name, Group())
display_name = "{} {}".format(type.name, beacon.name[-1:])
grouped[type.name].add((beacon, display_name, display_name))
subdata.items.append(Entry(beacon, display_name, display_name))
data.sort()
# Localized abyssal hazards
items = sMkt.getGroup("Abyssal Hazards").items
if items:
subdata = data.groups.setdefault('Localized', Group())
for beacon in sMkt.getGroup("Abyssal Hazards").items:
if not beacon.isType('projected'):
continue
# Localized effects, currently, have a name like "(size) (type) Cloud"
# Until this inevitably changes, do a simple split
name_parts = beacon.name.split(" ")
key = name_parts[1].strip()
subsubdata = subdata.groups.setdefault(key, Group())
subsubdata.items.append(Entry(beacon, beacon.name, beacon.name))
subdata.sort()
# PVP weather
flat.add((sMkt.getItem(49766), 'PvP Weather', 'PvP Weather'))
data.items.append(Entry(sMkt.getItem(49766), 'PvP Weather', 'PvP Weather'))
return grouped, flat
return data
def getLocalizedEnvironments(self):
def getDestructibleBeacons(self):
data = Group()
sMkt = Market.getInstance()
grp = sMkt.getGroup("Abyssal Hazards")
grouped = dict()
for beacon in grp.items:
if not beacon.isType('projected'):
for item in sMkt.getItemsByGroup(sMkt.getGroup('Destructible Effect Beacon')):
if not item.isType('projected'):
continue
# Localized effects, currently, have a name like "(size) (type) Cloud"
# Until this inevitably changes, do a simple split
name_parts = beacon.name.split(" ")
key = name_parts[1].strip()
if key not in grouped:
grouped[key] = set()
grouped[key].add((beacon, beacon.name, beacon.name))
return grouped, ()
data.items.append(Entry(item, item.name, item.name))
data.sort()
return data
AddEnvironmentEffect.register()

View File

@@ -721,8 +721,9 @@ class Market:
groupItems = set(group.items)
if hasattr(group, 'addItems'):
groupItems.update(group.addItems)
items = set(
[item for item in groupItems if self.getPublicityByItem(item) and self.getGroupByItem(item) == group])
items = set([
item for item in groupItems
if self.getPublicityByItem(item) and self.getGroupByItem(item) == group])
return items
def getItemsByMarketGroup(self, mg, vars_=True):