Merge branch 'ammo_graph' of github.com:pyfa-org/Pyfa into ammo_graph
This commit is contained in:
@@ -10689,6 +10689,7 @@ class Effect3526(BaseEffect):
|
||||
|
||||
Used by:
|
||||
Ships from group: Force Recon Ship (8 of 9)
|
||||
Ship: Venture
|
||||
Skill: Cynosural Field Theory
|
||||
"""
|
||||
|
||||
|
||||
@@ -318,10 +318,15 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
"energyDestabilizationRange", "empFieldRange",
|
||||
"ecmBurstRange", "warpScrambleRange", "cargoScanRange",
|
||||
"shipScanRange", "surveyScanRange")
|
||||
maxRange = None
|
||||
for attr in attrs:
|
||||
maxRange = self.getModifiedItemAttr(attr, None)
|
||||
if maxRange is not None:
|
||||
return maxRange
|
||||
break
|
||||
if maxRange is not None:
|
||||
if 'burst projector' in self.item.name.lower():
|
||||
maxRange -= self.owner.ship.getModifiedItemAttr("radius")
|
||||
return maxRange
|
||||
missileMaxRangeData = self.missileMaxRangeData
|
||||
if missileMaxRangeData is None:
|
||||
return None
|
||||
|
||||
@@ -27,7 +27,7 @@ import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from graphs.data.base import FitGraph
|
||||
from graphs.events import RESIST_MODE_CHANGED
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from service.const import GraphCacheCleanupReason
|
||||
from service.settings import GraphSettings
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import wx
|
||||
|
||||
|
||||
class AuxiliaryFrame(wx.Frame):
|
||||
class AuxiliaryMixin:
|
||||
|
||||
_instance = None
|
||||
|
||||
@@ -68,3 +68,11 @@ class AuxiliaryFrame(wx.Frame):
|
||||
|
||||
def OnSuppressedAction(self, event):
|
||||
return
|
||||
|
||||
|
||||
class AuxiliaryFrame(AuxiliaryMixin, wx.Frame):
|
||||
pass
|
||||
|
||||
|
||||
class AuxiliaryDialog(AuxiliaryMixin, wx.Dialog):
|
||||
pass
|
||||
@@ -89,7 +89,7 @@ class BitmapLoader:
|
||||
@classmethod
|
||||
def loadBitmap(cls, name, location):
|
||||
if cls.scaling_factor is None:
|
||||
cls.scaling_factor = int(wx.GetApp().GetTopWindow().GetContentScaleFactor())
|
||||
cls.scaling_factor = 1 if 'wxGTK' in wx.PlatformInfo else int(wx.GetApp().GetTopWindow().GetContentScaleFactor())
|
||||
scale = cls.scaling_factor
|
||||
|
||||
filename, img = cls.loadScaledBitmap(name, location, scale)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryDialog
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.ammo import Ammo
|
||||
from service.market import Market
|
||||
@@ -32,22 +32,34 @@ class GraphFitAmmoPicker(ContextMenuSingle):
|
||||
GraphFitAmmoPicker.register()
|
||||
|
||||
|
||||
class AmmoPickerFrame(AuxiliaryFrame):
|
||||
class AmmoPickerFrame(AuxiliaryDialog):
|
||||
|
||||
def __init__(self, parent, fit):
|
||||
super().__init__(parent, title='Choose Different Ammo', style=wx.DEFAULT_DIALOG_STYLE, resizeable=True)
|
||||
padding = 5
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
contents = AmmoPickerContents(self, fit)
|
||||
mainSizer.Add(contents, 1, wx.EXPAND | wx.ALL, padding)
|
||||
|
||||
buttonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL)
|
||||
if buttonSizer:
|
||||
mainSizer.Add(buttonSizer, 0, wx.EXPAND | wx.ALL, padding)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
contW, contH = contents.GetVirtualSize()
|
||||
bestW = min(1000, contW + padding * 2)
|
||||
bestH = min(700, contH + padding * 2)
|
||||
bestW = contW + padding * 2
|
||||
bestH = contH + padding * 2
|
||||
if buttonSizer:
|
||||
# Yeah right... whatever
|
||||
buttW, buttH = buttonSizer.GetSize()
|
||||
bestW = max(bestW, buttW + padding * 2)
|
||||
bestH += buttH + padding * 2
|
||||
bestW = min(1000, bestW)
|
||||
bestH = min(700, bestH)
|
||||
self.SetSize(bestW, bestH)
|
||||
self.SetMinSize(wx.Size(int(bestW * 0.7), int(bestH * 0.7)))
|
||||
self.CenterOnParent()
|
||||
@@ -62,11 +74,12 @@ class AmmoPickerFrame(AuxiliaryFrame):
|
||||
|
||||
class AmmoPickerContents(wx.ScrolledCanvas):
|
||||
|
||||
indent = 15
|
||||
|
||||
def __init__(self, parent, fit):
|
||||
wx.ScrolledCanvas.__init__(self, parent)
|
||||
self.SetScrollRate(0, 15)
|
||||
|
||||
indent = 15
|
||||
mods = self.getMods(fit)
|
||||
drones = self.getDrones(fit)
|
||||
fighters = self.getFighters(fit)
|
||||
@@ -75,68 +88,78 @@ class AmmoPickerContents(wx.ScrolledCanvas):
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
moduleSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(moduleSizer, 0, wx.ALL, 0)
|
||||
|
||||
self.droneSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(self.droneSizer, 0, wx.ALL, 0)
|
||||
|
||||
fighterSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
mainSizer.Add(fighterSizer, 0, wx.ALL, 0)
|
||||
|
||||
firstRadio = True
|
||||
currentRb = None
|
||||
|
||||
def addRadioButton(text):
|
||||
nonlocal firstRadio, currentRb
|
||||
if not firstRadio:
|
||||
rb = wx.RadioButton(self, wx.ID_ANY, text, style=wx.RB_GROUP)
|
||||
rb.SetValue(True)
|
||||
firstRadio = True
|
||||
else:
|
||||
rb = wx.RadioButton(self, wx.ID_ANY, text)
|
||||
rb.SetValue(False)
|
||||
rb.Bind(wx.EVT_RADIOBUTTON, self.rbSelected)
|
||||
currentRb = rb
|
||||
mainSizer.Add(rb, 0, wx.EXPAND | wx.ALL, 0)
|
||||
|
||||
def addCheckbox(text, indentLvl=0):
|
||||
cb = wx.CheckBox(self, -1, text)
|
||||
mainSizer.Add(cb, 0, wx.EXPAND | wx.LEFT, indent * indentLvl)
|
||||
if currentRb is not None:
|
||||
self.rbCheckboxMap.setdefault(currentRb, []).append(cb)
|
||||
|
||||
def addLabel(text, indentLvl=0):
|
||||
text = text[0].capitalize() + text[1:]
|
||||
label = wx.StaticText(self, wx.ID_ANY, text)
|
||||
mainSizer.Add(label, 0, wx.EXPAND | wx.LEFT, indent * indentLvl)
|
||||
if currentRb is not None:
|
||||
self.rbLabelMap.setdefault(currentRb, []).append(label)
|
||||
|
||||
for modInfo, modAmmo in mods:
|
||||
text = '\n'.join('{}x {}'.format(amount, item.name) for item, amount in modInfo)
|
||||
addRadioButton(text)
|
||||
modRb = self.addRadioButton(moduleSizer, text, firstRadio)
|
||||
firstRadio = False
|
||||
# Get actual module, as ammo getters need it
|
||||
mod = next((m for m in fit.modules if m.itemID == next(iter(modInfo))[0].ID), None)
|
||||
_, ammoTree = Ammo.getInstance().getModuleStructuredAmmo(mod)
|
||||
if len(ammoTree) == 1:
|
||||
for ammoCatName, ammos in ammoTree.items():
|
||||
for ammo in ammos:
|
||||
addCheckbox(ammo.name, indentLvl=1)
|
||||
self.addCheckbox(moduleSizer, ammo.name, modRb, indentLvl=1)
|
||||
else:
|
||||
for ammoCatName, ammos in ammoTree.items():
|
||||
if len(ammos) == 1:
|
||||
ammo = next(iter(ammos))
|
||||
addCheckbox(ammo.name, indentLvl=1)
|
||||
self.addCheckbox(moduleSizer, ammo.name, modRb, indentLvl=1)
|
||||
else:
|
||||
addLabel('{}:'.format(ammoCatName), indentLvl=1)
|
||||
self.addLabel(moduleSizer, '{}:'.format(ammoCatName), modRb, indentLvl=1)
|
||||
for ammo in ammos:
|
||||
addCheckbox(ammo.name, indentLvl=2)
|
||||
self.addCheckbox(moduleSizer, ammo.name, modRb, indentLvl=2)
|
||||
if drones:
|
||||
addRadioButton('Drones')
|
||||
droneRb = self.addRadioButton(self.droneSizer, 'Drones', firstRadio)
|
||||
from gui.builtinAdditionPanes.droneView import DroneView
|
||||
for drone in sorted(drones, key=DroneView.droneKey):
|
||||
addCheckbox('{}x {}'.format(drone.amount, drone.item.name), indentLvl=1)
|
||||
self.addCheckbox(self.droneSizer, '{}x {}'.format(drone.amount, drone.item.name), droneRb, indentLvl=1)
|
||||
addBtn = wx.Button(self, wx.ID_ANY, '+', style=wx.BU_EXACTFIT)
|
||||
addBtn.Bind(wx.EVT_BUTTON, self.OnDroneGroupAdd)
|
||||
mainSizer.Add(addBtn, 0, wx.LEFT, self.indent)
|
||||
if fighters:
|
||||
addRadioButton('Fighters')
|
||||
fighterRb = self.addRadioButton(fighterSizer, 'Fighters', firstRadio)
|
||||
from gui.builtinAdditionPanes.fighterView import FighterDisplay
|
||||
for fighter in sorted(fighters, key=FighterDisplay.fighterKey):
|
||||
addCheckbox('{}x {}'.format(fighter.amount, fighter.item.name), indentLvl=1)
|
||||
self.addCheckbox(fighterSizer, '{}x {}'.format(fighter.amount, fighter.item.name), fighterRb, indentLvl=1)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.refreshStatus()
|
||||
|
||||
def addRadioButton(self, sizer, text, firstRadio=False):
|
||||
if firstRadio:
|
||||
rb = wx.RadioButton(self, wx.ID_ANY, text, style=wx.RB_GROUP)
|
||||
rb.SetValue(True)
|
||||
else:
|
||||
rb = wx.RadioButton(self, wx.ID_ANY, text)
|
||||
rb.SetValue(False)
|
||||
rb.Bind(wx.EVT_RADIOBUTTON, self.rbSelected)
|
||||
sizer.Add(rb, 0, wx.EXPAND | wx.ALL, 0)
|
||||
return rb
|
||||
|
||||
def addCheckbox(self, sizer, text, currentRb, indentLvl=0):
|
||||
cb = wx.CheckBox(self, -1, text)
|
||||
sizer.Add(cb, 0, wx.EXPAND | wx.LEFT, self.indent * indentLvl)
|
||||
if currentRb is not None:
|
||||
self.rbCheckboxMap.setdefault(currentRb, []).append(cb)
|
||||
|
||||
def addLabel(self, sizer, text, currentRb, indentLvl=0):
|
||||
text = text[0].capitalize() + text[1:]
|
||||
label = wx.StaticText(self, wx.ID_ANY, text)
|
||||
sizer.Add(label, 0, wx.EXPAND | wx.LEFT, self.indent * indentLvl)
|
||||
if currentRb is not None:
|
||||
self.rbLabelMap.setdefault(currentRb, []).append(label)
|
||||
|
||||
def getMods(self, fit):
|
||||
sMkt = Market.getInstance()
|
||||
sAmmo = Ammo.getInstance()
|
||||
@@ -201,6 +224,12 @@ class AmmoPickerContents(wx.ScrolledCanvas):
|
||||
break
|
||||
return fighters
|
||||
|
||||
def OnDroneGroupAdd(self, event):
|
||||
event.Skip()
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
label = wx.StaticText()
|
||||
self.droneSizer.Add(sizer, 0, wx.EXPAND | wx.LEFT, self.indent)
|
||||
|
||||
def refreshStatus(self):
|
||||
for map in (self.rbLabelMap, self.rbCheckboxMap):
|
||||
for rb, items in map.items():
|
||||
|
||||
@@ -83,12 +83,12 @@ class MaxRange(ViewColumn):
|
||||
lines.append('Missile flight range')
|
||||
lowerRange, higherRange, higherChance = missileRangeData
|
||||
if roundToPrec(higherChance, 3) not in (0, 1):
|
||||
lines.append('{}% chance to fly {}'.format(
|
||||
lines.append('{}% chance to fly {}m'.format(
|
||||
formatAmount((1 - higherChance) * 100, prec=3, lowest=0, highest=0),
|
||||
formatAmount(lowerRange, prec=3, lowest=0, highest=3, unitName='m')))
|
||||
lines.append('{}% chance to fly {}'.format(
|
||||
formatAmount(lowerRange, prec=3, lowest=0, highest=3)))
|
||||
lines.append('{}% chance to fly {}m'.format(
|
||||
formatAmount(higherChance * 100, prec=3, lowest=0, highest=0),
|
||||
formatAmount(higherRange, prec=3, lowest=0, highest=3, unitName='m')))
|
||||
formatAmount(higherRange, prec=3, lowest=0, highest=3)))
|
||||
else:
|
||||
lines.append("Optimal + Falloff")
|
||||
return '\n'.join(lines)
|
||||
|
||||
@@ -34,7 +34,7 @@ from wx.lib.agw.floatspin import FloatSpin
|
||||
|
||||
import config
|
||||
import gui.globalEvents as GE
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor, TextEntryValidatedDialog
|
||||
from gui.builtinViews.implantEditor import BaseImplantEditorView
|
||||
@@ -428,6 +428,31 @@ class SkillTreeView(wx.Panel):
|
||||
# This cuases issues with GTK, see #1866
|
||||
# self.Layout()
|
||||
|
||||
# For level keyboard shortcuts
|
||||
self.ChangeLevelEvent, CHANGE_LEVEL_EVENT = wx.lib.newevent.NewEvent()
|
||||
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
||||
self.Bind(CHANGE_LEVEL_EVENT, self.changeLevel)
|
||||
|
||||
def kbEvent(self, event):
|
||||
keyLevelMap = {
|
||||
# Regular number keys
|
||||
48: 0, 49: 1, 50: 2, 51: 3, 52: 4, 53: 5,
|
||||
# Numpad keys
|
||||
wx.WXK_NUMPAD0: 0, wx.WXK_NUMPAD1: 1, wx.WXK_NUMPAD2: 2,
|
||||
wx.WXK_NUMPAD3: 3, wx.WXK_NUMPAD4: 4, wx.WXK_NUMPAD5: 5}
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode in keyLevelMap and event.GetModifiers() == wx.MOD_NONE:
|
||||
level = keyLevelMap[keycode]
|
||||
selection = self.skillTreeListCtrl.GetSelection()
|
||||
if selection:
|
||||
dataType, skillID = self.skillTreeListCtrl.GetItemData(selection)
|
||||
if dataType == 'skill':
|
||||
event = self.ChangeLevelEvent()
|
||||
event.SetId(self.idLevels[level])
|
||||
wx.PostEvent(self, event)
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def importSkills(self, evt):
|
||||
|
||||
with wx.MessageDialog(
|
||||
@@ -611,6 +636,8 @@ class SkillTreeView(wx.Panel):
|
||||
|
||||
sChar = Character.getInstance()
|
||||
char = self.charEditor.entityEditor.getActiveEntity()
|
||||
if char.name in ("All 0", "All 5"):
|
||||
return
|
||||
selection = self.skillTreeListCtrl.GetSelection()
|
||||
dataType, skillID = self.skillTreeListCtrl.GetItemData(selection)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.builtinShipBrowser.events import FitSelected
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import wx
|
||||
from logbook import Logger
|
||||
|
||||
import config
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from service.prereqsCheck import version_block
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from logbook import Logger
|
||||
import gui.globalEvents as GE
|
||||
from eos.db import getItem
|
||||
from eos.saveddata.cargo import Cargo
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.display import Display
|
||||
from service.esi import Esi
|
||||
from service.esiAccess import APIException
|
||||
|
||||
@@ -23,7 +23,7 @@ import wx
|
||||
import config
|
||||
import gui.mainFrame
|
||||
from eos.saveddata.module import Module
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinItemStatsViews.itemAffectedBy import ItemAffectedBy
|
||||
from gui.builtinItemStatsViews.itemAttributes import ItemParams
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor
|
||||
from gui.utils.clipboard import fromClipboard, toClipboard
|
||||
|
||||
@@ -10,7 +10,7 @@ import gui.builtinMarketBrowser.pfSearchBox as SBox
|
||||
import gui.display as d
|
||||
import gui.globalEvents as GE
|
||||
from eos.db.gamedata.queries import getAttributeInfo, getItem
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.marketBrowser import SearchBox
|
||||
from service.market import Market
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor
|
||||
from gui.builtinViews.implantEditor import BaseImplantEditorView
|
||||
from gui.utils.clipboard import fromClipboard, toClipboard
|
||||
|
||||
@@ -27,7 +27,7 @@ from logbook import Logger
|
||||
|
||||
import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
|
||||
from gui.utils.clipboard import toClipboard, fromClipboard
|
||||
|
||||
@@ -47,7 +47,7 @@ from service.port.muta import parseMutant
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
# 2017/04/05 NOTE: simple validation, for xml file
|
||||
RE_XML_START = r'<\?xml\s+version="1.0"\s*\?>'
|
||||
RE_XML_START = r'<\?xml\s+version="1.0"[^<>]*\?>'
|
||||
|
||||
|
||||
class Port:
|
||||
@@ -182,7 +182,8 @@ class Port:
|
||||
pyfalog.critical(e)
|
||||
# TypeError: not all arguments converted during string formatting
|
||||
# return False, "Unknown Error while processing {0}" % path
|
||||
return False, "Unknown error while processing %s\n\n Error: %s" % (path, e.message)
|
||||
return False, "Unknown error while processing {}\n\n Error: {} {}".format(
|
||||
path, type(e).__name__, getattr(e, 'message', ''))
|
||||
|
||||
return True, fit_list
|
||||
|
||||
@@ -321,4 +322,4 @@ class Port:
|
||||
|
||||
@staticmethod
|
||||
def exportFitStats(fit, callback=None):
|
||||
return exportFitStats(fit, callback=callback)
|
||||
return exportFitStats(fit, callback=callback)
|
||||
|
||||
@@ -82,9 +82,13 @@ def fetchItem(typeName, eagerCat=False):
|
||||
eager = 'group.category' if eagerCat else None
|
||||
try:
|
||||
item = sMkt.getItem(typeName, eager=eager)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pyfalog.warning('service.port.shared: unable to fetch item "{}"'.format(typeName))
|
||||
return None
|
||||
if item is None:
|
||||
return None
|
||||
if sMkt.getPublicityByItem(item):
|
||||
return item
|
||||
else:
|
||||
|
||||
@@ -215747,7 +215747,7 @@
|
||||
{
|
||||
"attributeID": 9,
|
||||
"typeID": 4308,
|
||||
"value": 2170.0
|
||||
"value": 2180.0
|
||||
},
|
||||
{
|
||||
"attributeID": 11,
|
||||
@@ -2361009,6 +2361009,11 @@
|
||||
"typeID": 32880,
|
||||
"value": 1.0
|
||||
},
|
||||
{
|
||||
"attributeID": 1296,
|
||||
"typeID": 32880,
|
||||
"value": -50.0
|
||||
},
|
||||
{
|
||||
"attributeID": 1547,
|
||||
"typeID": 32880,
|
||||
@@ -2890019,6 +2890024,11 @@
|
||||
"typeID": 52694,
|
||||
"value": 380.0
|
||||
},
|
||||
{
|
||||
"attributeID": 1302,
|
||||
"typeID": 52694,
|
||||
"value": 32880.0
|
||||
},
|
||||
{
|
||||
"attributeID": 1333,
|
||||
"typeID": 52694,
|
||||
|
||||
@@ -167469,6 +167469,11 @@
|
||||
"isDefault": false,
|
||||
"typeID": 32878
|
||||
},
|
||||
{
|
||||
"effectID": 3526,
|
||||
"isDefault": false,
|
||||
"typeID": 32880
|
||||
},
|
||||
{
|
||||
"effectID": 5058,
|
||||
"isDefault": false,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
[
|
||||
{
|
||||
"field_name": "client_build",
|
||||
"field_value": 1604553
|
||||
"field_value": 1610407
|
||||
},
|
||||
{
|
||||
"field_name": "dump_time",
|
||||
"field_value": 1573560935
|
||||
"field_value": 1574329773
|
||||
}
|
||||
]
|
||||
@@ -733,7 +733,7 @@
|
||||
"text": "reduction in Small Energy Turret activation cost"
|
||||
},
|
||||
{
|
||||
"number": "5%",
|
||||
"number": "10%",
|
||||
"text": "bonus to Small Energy Turret damage"
|
||||
}
|
||||
],
|
||||
@@ -10287,6 +10287,10 @@
|
||||
{
|
||||
"number": "2+",
|
||||
"text": "bonus to ship warp core strength"
|
||||
},
|
||||
{
|
||||
"number": "50%",
|
||||
"text": "reduction in Industrial Cynosural Field Generator liquid ozone consumption"
|
||||
}
|
||||
],
|
||||
"header": "Role Bonus:"
|
||||
@@ -10405,7 +10409,7 @@
|
||||
{
|
||||
"bonuses": [
|
||||
{
|
||||
"number": "10%",
|
||||
"number": "15%",
|
||||
"text": "bonus to Small Hybrid Turret damage"
|
||||
}
|
||||
],
|
||||
@@ -14922,7 +14926,7 @@
|
||||
"text": "reduction in Microwarpdrive signature radius penalty"
|
||||
},
|
||||
{
|
||||
"number": "5%",
|
||||
"number": "10%",
|
||||
"text": "bonus to Small Projectile Turret damage"
|
||||
}
|
||||
],
|
||||
@@ -18810,7 +18814,7 @@
|
||||
{
|
||||
"bonuses": [
|
||||
{
|
||||
"number": "5%",
|
||||
"number": "10%",
|
||||
"text": "bonus to Small Hybrid Turret damage"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1 +1 @@
|
||||
version: v2.14.2
|
||||
version: v2.14.3
|
||||
|
||||
Reference in New Issue
Block a user