diff --git a/package.json b/package.json index f937daee..a28ebfe1 100644 --- a/package.json +++ b/package.json @@ -128,6 +128,7 @@ "coriolis-data": "../coriolis-data", "d3": "^5.7.0", "detect-browser": "^3.0.1", + "ed-forge": "github:EDCD/ed-forge", "fbemitter": "^2.1.1", "lodash": "^4.17.11", "lz-string": "^1.4.4", diff --git a/src/app/Coriolis.jsx b/src/app/Coriolis.jsx index 8b544b1f..1a058b02 100644 --- a/src/app/Coriolis.jsx +++ b/src/app/Coriolis.jsx @@ -5,16 +5,14 @@ import { register } from 'register-service-worker'; import { EventEmitter } from 'fbemitter'; import { getLanguage } from './i18n/Language'; import Persist from './stores/Persist'; +import { Ship } from 'ed-forge'; import Announcement from './components/Announcement'; import Header from './components/Header'; import Tooltip from './components/Tooltip'; -import ModalExport from './components/ModalExport'; import ModalHelp from './components/ModalHelp'; import ModalImport from './components/ModalImport'; import ModalPermalink from './components/ModalPermalink'; -import * as CompanionApiUtils from './utils/CompanionApiUtils'; -import * as JournalUtils from './utils/JournalUtils'; import AboutPage from './pages/AboutPage'; import NotFoundPage from './pages/NotFoundPage'; import OutfittingPage from './pages/OutfittingPage'; @@ -22,7 +20,6 @@ import ComparisonPage from './pages/ComparisonPage'; import ShipyardPage from './pages/ShipyardPage'; import ErrorDetails from './pages/ErrorDetails'; -const zlib = require('pako'); const request = require('superagent'); /** @@ -61,7 +58,6 @@ export default class Coriolis extends React.Component { this._onLanguageChange = this._onLanguageChange.bind(this); this._onSizeRatioChange = this._onSizeRatioChange.bind(this); this._keyDown = this._keyDown.bind(this); - this._importBuild = this._importBuild.bind(this); this.emitter = new EventEmitter(); this.state = { @@ -93,19 +89,10 @@ export default class Coriolis extends React.Component { _importBuild(r) { try { // Need to decode and gunzip the data, then build the ship - const data = zlib.inflate(new Buffer(r.params.data, 'base64'), { to: 'string' }); - const json = JSON.parse(data); - console.info('Ship import data: '); - console.info(json); - let ship; - if (json && json.modules) { - ship = CompanionApiUtils.shipFromJson(json); - } else if (json && json.Modules) { - ship = JournalUtils.shipFromLoadoutJSON(json); - } - r.params.ship = ship.id; - r.params.code = ship.toString(); - this._setPage(OutfittingPage, r) + let ship = new Ship(r.params.data); + r.params.ship = ship.getShipType(); + r.params.code = ship.compress(); + this._setPage(OutfittingPage, r); } catch (err) { this._onError('Failed to import ship', r.path, 0, 0, err); } diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx index 94cd0e23..26617159 100644 --- a/src/app/components/AvailableModulesMenu.jsx +++ b/src/app/components/AvailableModulesMenu.jsx @@ -122,7 +122,6 @@ const CATEGORIES = { */ export default class AvailableModulesMenu extends TranslatedComponent { static propTypes = { - modules: PropTypes.oneOfType([PropTypes.object, PropTypes.array]).isRequired, onSelect: PropTypes.func.isRequired, diffDetails: PropTypes.func, m: PropTypes.object, @@ -155,7 +154,7 @@ export default class AvailableModulesMenu extends TranslatedComponent { */ _initState(props, context) { let translate = context.language.translate; - let { m, warning, onSelect, modules, ship } = props; + let { m, warning, onSelect, ship } = props; let list, currentGroup; let buildGroup = this._buildGroup.bind( @@ -170,6 +169,7 @@ export default class AvailableModulesMenu extends TranslatedComponent { } ); let fuzzy = []; + let modules = m.getApplicableItems(); if (modules instanceof Array) { list = buildGroup(modules[0].grp, modules); } else { diff --git a/src/app/components/HardpointSlot.jsx b/src/app/components/HardpointSlot.jsx index 724d9fd5..c077bec1 100644 --- a/src/app/components/HardpointSlot.jsx +++ b/src/app/components/HardpointSlot.jsx @@ -21,7 +21,6 @@ import { blueprintTooltip } from '../utils/BlueprintFunctions'; * Hardpoint / Utility Slot */ export default class HardpointSlot extends Slot { - /** * Get the CSS class name for the slot. * @return {string} CSS Class name @@ -42,40 +41,38 @@ export default class HardpointSlot extends Slot { /** * Generate the slot contents * @param {Object} m Mounted Module - * @param {Boolean} enabled Slot enabled * @param {Function} translate Translate function * @param {Object} formats Localized Formats map * @param {Object} u Localized Units Map * @return {React.Component} Slot contents */ - _getSlotDetails(m, enabled, translate, formats, u) { + _getSlotDetails(m, translate, formats, u) { if (m) { let classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`; let { drag, drop } = this.props; let { termtip, tooltip } = this.context; - let validMods = Modifications.modules[m.grp].modifications || []; let showModuleResistances = Persist.showModuleResistances(); // Modifications tooltip shows blueprint and grade, if available let modTT = translate('modified'); if (m && m.blueprint && m.blueprint.name) { - modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; - if (m.blueprint.special && m.blueprint.special.id >= 0) { - modTT += ', ' + translate(m.blueprint.special.name); - } - modTT = ( -
-
{modTT}
- {blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], null, m.grp, m)} -
- ); + // modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; + // if (m.blueprint.special && m.blueprint.special.id >= 0) { + // modTT += ', ' + translate(m.blueprint.special.name); + // } + // modTT = ( + //
+ //
{modTT}
+ // {blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], m)} + //
+ // ); } - const className = cn('details', enabled ? '' : 'disabled'); + const className = cn('details', m.isEnabled() ? '' : 'disabled'); return
- {m.mount && m.mount == 'F' ? : ''} {m.mount && m.mount == 'G' ? : ''} @@ -91,13 +88,13 @@ export default class HardpointSlot extends Slot { onMouseOut={tooltip.bind(null, null)}> : ''} {classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? : null} + onMouseOut={tooltip.bind(null, null)}> : null} */}
-
{formats.round(m.getMass())}{u.T}
+
{formats.round(m.get('mass'))}{u.T}
- {m.getDps() ?
{translate('DPS')}: {formats.round1(m.getDps())} {m.getClip() ? ({formats.round1(m.getSDps())}) : null}
: null} {m.getDamage() ?
-
: null} +
: null} */}
; } else { return
{translate('empty')}
; } } - } diff --git a/src/app/components/HardpointSlotSection.jsx b/src/app/components/HardpointSlotSection.jsx index 6a5ecdfa..18b48e39 100644 --- a/src/app/components/HardpointSlotSection.jsx +++ b/src/app/components/HardpointSlotSection.jsx @@ -68,29 +68,23 @@ export default class HardpointSlotSection extends SlotSection { let { ship, currentMenu } = this.props; let { originSlot, targetSlot } = this.state; let slots = []; - let hardpoints = ship.hardpoints; - let availableModules = ship.getAvailableModules(); - for (let i = 0, l = hardpoints.length; i < l; i++) { - let h = hardpoints[i]; - if (h.maxClass) { - slots.push( availableModules.getHps(h.maxClass)} - onOpen={this._openMenu.bind(this, h)} - onSelect={this._selectModule.bind(this, h)} - onChange={this.props.onChange} - selected={currentMenu == h} - drag={this._drag.bind(this, h)} - dragOver={this._dragOverSlot.bind(this, h)} - drop={this._drop} - dropClass={this._dropClass(h, originSlot, targetSlot)} - ship={ship} - m={h.m} - enabled={h.enabled ? true : false} - />); - } + for (let h of ship.getHardpoints(undefined, true)) { + slots.push(); } return slots; diff --git a/src/app/components/InternalSlot.jsx b/src/app/components/InternalSlot.jsx index f1ac0a8b..ec3c9aa9 100644 --- a/src/app/components/InternalSlot.jsx +++ b/src/app/components/InternalSlot.jsx @@ -15,36 +15,39 @@ export default class InternalSlot extends Slot { /** * Generate the slot contents * @param {Object} m Mounted Module - * @param {Boolean} enabled Slot enabled * @param {Function} translate Translate function * @param {Object} formats Localized Formats map * @param {Object} u Localized Units Map * @return {React.Component} Slot contents */ - _getSlotDetails(m, enabled, translate, formats, u) { + _getSlotDetails(m, translate, formats, u) { if (m) { - let classRating = m.class + m.rating; + let classRating = String(m.getSize()) + m.getRating(); let { drag, drop, ship } = this.props; let { termtip, tooltip } = this.context; - let validMods = (Modifications.modules[m.grp] ? Modifications.modules[m.grp].modifications : []); + let validMods = m.getApplicableBlueprints(); let showModuleResistances = Persist.showModuleResistances(); // Modifications tooltip shows blueprint and grade, if available - let modTT = translate('modified'); - if (m && m.blueprint && m.blueprint.name) { - modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; - if (m.blueprint.special && m.blueprint.special.id >= 0) { - modTT += ', ' + translate(m.blueprint.special.name); - } - modTT = ( -
-
{modTT}
- {blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], null, m.grp, m)} -
- ); - } + // let modTT = translate('modified'); + // const blueprint = m.getBlueprint(); + // const experimental = m.getExperimental(); + // const grade = m.getGrade(); + // if (blueprint) { + // modTT = translate(blueprint) + ' ' + translate('grade') + ' ' + grade; + // if (experimental) { + // modTT += ', ' + translate(experimental); + // } + // modTT = ( + //
+ //
{modTT}
+ // {blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], m)} + //
+ // ); + // } - let mass = m.getMass() || m.cargo || m.fuel || 0; + let mass = m.get('mass') || m.get('cargo') || m.get('fuel') || 0; + const enabled = m.isEnabled(); const className = cn('details', enabled ? '' : 'disabled'); return
@@ -53,7 +56,7 @@ export default class InternalSlot extends Slot {
{formats.round(mass)}{u.T}
- { m.getOptMass() ?
{translate('optmass', 'sg')}: {formats.int(m.getOptMass())}{u.T}
: null } + {/* { m.getOptMass() ?
{translate('optmass', 'sg')}: {formats.int(m.getOptMass())}{u.T}
: null } { m.getMaxMass() ?
{translate('maxmass', 'sg')}: {formats.int(m.getMaxMass())}{u.T}
: null } { m.bins ?
{m.bins} {translate('bins')}
: null } { m.bays ?
{translate('bays')}: {m.bays}
: null } @@ -88,7 +91,7 @@ export default class InternalSlot extends Slot { { m.getHullReinforcement() ?
{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}
: null } { m.getProtection() ?
{translate('protection')}: {formats.rPct(m.getProtection())}
: null } { m.getIntegrity() ?
{translate('integrity')}: {formats.int(m.getIntegrity())}
: null } - { m && validMods.length > 0 ?
this.modButton = modButton }>
: null } + { m && validMods.length > 0 ?
this.modButton = modButton }>
: null } */}
; } else { diff --git a/src/app/components/InternalSlotSection.jsx b/src/app/components/InternalSlotSection.jsx index 2bdc7a4a..c1f4799b 100644 --- a/src/app/components/InternalSlotSection.jsx +++ b/src/app/components/InternalSlotSection.jsx @@ -9,7 +9,6 @@ import { canMount } from '../utils/SlotFunctions'; * Internal slot section */ export default class InternalSlotSection extends SlotSection { - /** * Constructor * @param {Object} props React Component properties @@ -221,29 +220,24 @@ export default class InternalSlotSection extends SlotSection { let slots = []; let { currentMenu, ship } = this.props; let { originSlot, targetSlot } = this.state; - let { internal, fuelCapacity } = ship; - let availableModules = ship.getAvailableModules(); - - for (let i = 0, l = internal.length; i < l; i++) { - let s = internal[i]; + let { fuelCapacity } = ship; + for (const slot of ship.getInternals(undefined, true)) { slots.push( availableModules.getInts(ship, s.maxClass, s.eligible)} - onOpen={this._openMenu.bind(this,s)} - onChange={this.props.onChange} - onSelect={this._selectModule.bind(this, s)} - selected={currentMenu == s} - eligible={s.eligible} - m={s.m} - drag={this._drag.bind(this, s)} - dragOver={this._dragOverSlot.bind(this, s)} + key={slot.object.Slot} + maxClass={slot.getSize()} + onOpen={this._openMenu.bind(this, slot)} + onChange={this.props.onChange} + onSelect={this._selectModule.bind(this, slot)} + selected={currentMenu == slot} + slot={slot} + drag={this._drag.bind(this, slot)} + dragOver={this._dragOverSlot.bind(this, slot)} drop={this._drop} - dropClass={this._dropClass(s, originSlot, targetSlot)} + dropClass={this._dropClass(slot, originSlot, targetSlot)} fuel={fuelCapacity} ship={ship} - enabled={s.enabled ? true : false} + enabled={slot.isEnabled()} />); } @@ -268,10 +262,9 @@ export default class InternalSlotSection extends SlotSection {
  • this.sectionRefArr['pce'] = smRef}>{translate('pce')}
  • this.sectionRefArr['pci'] = smRef}>{translate('pci')}
  • this.sectionRefArr['pcm'] = smRef}>{translate('pcm')}
  • - { ship.luxuryCabins ?
  • this.sectionRefArr['pcq'] = smRef}>{translate('pcq')}
  • : ''} + { ship.luxuryCabins ?
  • this.sectionRefArr['pcq'] = smRef}>{translate('pcq')}
  • : ''}
  • {translate('PHRASE_ALT_ALL')}
  • ; } - } diff --git a/src/app/components/ModificationsMenu.jsx b/src/app/components/ModificationsMenu.jsx index 8ca36326..76a6c7ce 100644 --- a/src/app/components/ModificationsMenu.jsx +++ b/src/app/components/ModificationsMenu.jsx @@ -85,7 +85,7 @@ export default class ModificationsMenu extends TranslatedComponent { }); const close = this._blueprintSelected.bind(this, blueprintName, grade); const key = blueprintName + ':' + grade; - const tooltipContent = blueprintTooltip(translate, blueprint.grades[grade], Modifications.modules[m.grp].blueprints[blueprintName].grades[grade].engineers, m.grp); + const tooltipContent = blueprintTooltip(translate, blueprint.grades[grade]); if (classes.indexOf('active') >= 0) this.selectedModId = key; blueprintGrades.unshift(
  • this.modItems[key] = modItem}>{grade}
  • ); } @@ -429,7 +429,7 @@ export default class ModificationsMenu extends TranslatedComponent { if (m.blueprint && m.blueprint.name && Modifications.modules[m.grp].blueprints[m.blueprint.fdname].grades[m.blueprint.grade]) { blueprintLabel = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; haveBlueprint = true; - blueprintTt = blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], Modifications.modules[m.grp].blueprints[m.blueprint.fdname].grades[m.blueprint.grade].engineers, m.grp); + blueprintTt = blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade]); blueprintCv = getPercent(m); } diff --git a/src/app/components/ShipSummaryTable.jsx b/src/app/components/ShipSummaryTable.jsx index a98ad465..f0837a9f 100644 --- a/src/app/components/ShipSummaryTable.jsx +++ b/src/app/components/ShipSummaryTable.jsx @@ -5,6 +5,12 @@ import cn from 'classnames'; import { Warning } from './SvgIcons'; import * as Calc from '../shipyard/Calculations'; +import { ShipProps } from 'ed-forge'; +const { + SPEED, JUMP_RANGE, TOTAL_RANGE, SHIELD_METRICS, ARMOUR_METRICS, MODULE_ARMOUR, + MODULE_PROTECTION +} = ShipProps; + /** * Ship Summary Table / Stats */ @@ -12,10 +18,7 @@ export default class ShipSummaryTable extends TranslatedComponent { static propTypes = { ship: PropTypes.object.isRequired, - cargo: PropTypes.number.isRequired, - fuel: PropTypes.number.isRequired, marker: PropTypes.string.isRequired, - pips: PropTypes.object.isRequired }; /** @@ -35,14 +38,14 @@ export default class ShipSummaryTable extends TranslatedComponent { * @return {React.Component} Summary table */ render() { - const { ship, cargo, fuel, pips } = this.props; + const { ship } = this.props; let { language, tooltip, termtip } = this.context; let translate = language.translate; let u = language.units; let formats = language.formats; let { time, int, round, f1, f2 } = formats; let hide = tooltip.bind(null, null); - const shieldGenerator = ship.findInternalByGroup('sg') || ship.findInternalByGroup('psg'); + const shieldGenerator = ship.getShieldGenerator(); const sgClassNames = cn({ warning: shieldGenerator && !ship.shield, muted: !shieldGenerator }); const sgTooltip = shieldGenerator ? 'TT_SUMMARY_SHIELDS' : 'TT_SUMMARY_SHIELDS_NONFUNCTIONAL'; const timeToDrain = Calc.timeToDrainWep(ship, 4); @@ -64,15 +67,19 @@ export default class ShipSummaryTable extends TranslatedComponent { this.state = { shieldColour }; + + let speed = ship.get(SPEED); + let jumpRange = ship.get(JUMP_RANGE); + return
    - + - + diff --git a/src/app/components/Slot.jsx b/src/app/components/Slot.jsx index 8c04dbab..a7acf9ce 100644 --- a/src/app/components/Slot.jsx +++ b/src/app/components/Slot.jsx @@ -6,22 +6,19 @@ import AvailableModulesMenu from './AvailableModulesMenu'; import ModificationsMenu from './ModificationsMenu'; import { diffDetails } from '../utils/SlotFunctions'; import { wrapCtxMenu } from '../utils/UtilityFunctions'; +import { Ship, Module } from 'ed-forge'; +import { REG_MILITARY_SLOT } from 'ed-forge/lib/data/slots'; /** * Abstract Slot */ export default class Slot extends TranslatedComponent { - static propTypes = { - availableModules: PropTypes.func.isRequired, onSelect: PropTypes.func.isRequired, onOpen: PropTypes.func.isRequired, - maxClass: PropTypes.number.isRequired, selected: PropTypes.bool, - m: PropTypes.object, - enabled: PropTypes.bool.isRequired, - ship: PropTypes.object.isRequired, - eligible: PropTypes.object, + slot: PropTypes.instanceOf(Module), + ship: PropTypes.instanceOf(Ship), warning: PropTypes.func, drag: PropTypes.func, drop: PropTypes.func, @@ -61,7 +58,7 @@ export default class Slot extends TranslatedComponent { * @return {string} label */ _getMaxClassLabel() { - return this.props.maxClass; + return this.props.slot.getSize(); } /** @@ -97,7 +94,7 @@ export default class Slot extends TranslatedComponent { render() { let language = this.context.language; let translate = language.translate; - let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props; + let { ship, slot, dropClass, dragOver, onOpen, onChange, selected, onSelect, warning } = this.props; let slotDetails, modificationsMarker, menu; if (!selected) { @@ -105,36 +102,37 @@ export default class Slot extends TranslatedComponent { this._modificationsSelected = false; } - if (m) { - slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes - modificationsMarker = JSON.stringify(m); + if (!slot.isEmpty()) { + slotDetails = this._getSlotDetails(slot, translate, language.formats, language.units); // Must be implemented by sub classes } else { - slotDetails =
    {translate(eligible ? 'emptyrestricted' : 'empty')}
    ; - modificationsMarker = ''; + slotDetails =
    + {translate( + slot.getSlot().match(REG_MILITARY_SLOT) ? 'emptyrestricted' : 'empty' + )} +
    ; } if (selected) { - if (this._modificationsSelected) { - menu = ; - } else { - menu = ; - } + // if (this._modificationsSelected) { + // menu = ; + // } else { + menu = ; + // } } // TODO: implement touch dragging @@ -143,14 +141,13 @@ export default class Slot extends TranslatedComponent {
    this.slotDiv = slotDiv}>
    {this._getMaxClassLabel(translate)}
    - {slotDetails} + {slotDetails}
    {menu}
    ); } - /** * Toggle the modifications flag when selecting the modifications icon */ diff --git a/src/app/components/SlotSection.jsx b/src/app/components/SlotSection.jsx index 55d1a7c0..05b66bc9 100644 --- a/src/app/components/SlotSection.jsx +++ b/src/app/components/SlotSection.jsx @@ -5,19 +5,17 @@ import { wrapCtxMenu } from '../utils/UtilityFunctions'; import { canMount } from '../utils/SlotFunctions'; import { Equalizer } from '../components/SvgIcons'; import cn from 'classnames'; +import { Ship } from 'ed-forge'; const browser = require('detect-browser'); /** * Abstract Slot Section */ export default class SlotSection extends TranslatedComponent { - static propTypes = { - ship: PropTypes.object.isRequired, + ship: PropTypes.instanceOf(Ship), onChange: PropTypes.func.isRequired, - onCargoChange: PropTypes.func.isRequired, - onFuelChange: PropTypes.func.isRequired, - code: PropTypes.string.isRequired, + // code: PropTypes.string.isRequired, togglePwr: PropTypes.func, sectionMenuRefs: PropTypes.object }; @@ -106,6 +104,7 @@ export default class SlotSection extends TranslatedComponent { this.sectionRefArr['ssHeadRef'].focus(); } } + /** * Open a menu * @param {string} menu Menu name @@ -126,7 +125,7 @@ export default class SlotSection extends TranslatedComponent { * @param {Object} m Selected module */ _selectModule(slot, m) { - this.props.ship.use(slot, m, false); + slot.setItem(m); this.props.onChange(); this._close(); } diff --git a/src/app/components/StandardSlot.jsx b/src/app/components/StandardSlot.jsx index 1e810982..9120316b 100644 --- a/src/app/components/StandardSlot.jsx +++ b/src/app/components/StandardSlot.jsx @@ -6,24 +6,22 @@ import TranslatedComponent from './TranslatedComponent'; import { diffDetails } from '../utils/SlotFunctions'; import AvailableModulesMenu from './AvailableModulesMenu'; import ModificationsMenu from './ModificationsMenu'; -import * as ModuleUtils from '../shipyard/ModuleUtils'; import { ListModifications, Modified } from './SvgIcons'; import { Modifications } from 'coriolis-data/dist'; import { stopCtxPropagation } from '../utils/UtilityFunctions'; import { blueprintTooltip } from '../utils/BlueprintFunctions'; +import { Ship, Module } from 'ed-forge'; /** * Standard Slot */ export default class StandardSlot extends TranslatedComponent { - static propTypes = { - slot: PropTypes.object, - modules: PropTypes.array.isRequired, + slot: PropTypes.instanceOf(Module), onSelect: PropTypes.func.isRequired, onOpen: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, - ship: PropTypes.object.isRequired, + ship: PropTypes.instanceOf(Ship), selected: PropTypes.bool, warning: PropTypes.func, }; @@ -59,33 +57,28 @@ export default class StandardSlot extends TranslatedComponent { render() { let { termtip, tooltip } = this.context; let { translate, formats, units } = this.context.language; - let { modules, slot, selected, warning, onSelect, onChange, ship } = this.props; - let m = slot.m; - let classRating = m.class + m.rating; + let { slot, selected, warning, onSelect, onChange, ship } = this.props; + let classRating = String(slot.getClass()) + (slot.getRating() || ''); let menu; - let validMods = m == null || !Modifications.modules[m.grp] ? [] : (Modifications.modules[m.grp].modifications || []); - if (m && m.name && m.name === 'Guardian Hybrid Power Plant') { - validMods = []; - } - if (m && m.name && m.name === 'Guardian Power Distributor') { - validMods = []; - } + let validMods = slot.getApplicableBlueprints(); let showModuleResistances = Persist.showModuleResistances(); - let mass = m.getMass() || m.cargo || m.fuel || 0; + let mass = slot.get('cargo') || slot.get('fuel') || slot.get('mass') || 0; // Modifications tooltip shows blueprint and grade, if available let modTT = translate('modified'); - if (m && m.blueprint && m.blueprint.name) { - modTT = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade; - if (m.blueprint.special && m.blueprint.special.id >= 0) { - modTT += ', ' + translate(m.blueprint.special.name); + const appliedBlueprint = slot.getBlueprint(); + const appliedExperimental = slot.getExperimental(); + if (appliedBlueprint) { + modTT = translate(appliedBlueprint) + ' ' + translate('grade') + ' ' + slot.getBlueprintGrade(); + if (appliedExperimental) { + modTT += ', ' + translate(appliedExperimental); } modTT = ( -
    -
    {modTT}
    - {blueprintTooltip(translate, m.blueprint.grades[m.blueprint.grade], null, m.grp, m)} -
    - ); +
    +
    {modTT}
    + {blueprintTooltip(translate, slot)} +
    + ); } if (!selected) { @@ -93,23 +86,19 @@ export default class StandardSlot extends TranslatedComponent { this._modificationsSelected = false; } - const modificationsMarker = JSON.stringify(m); - if (selected) { if (this._modificationsSelected) { menu = ; } else { menu = this.slotDiv = slotDiv }> -
    -
    {m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}
    +
    +
    {slot.getSize()}
    -
    {classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? : null }
    +
    {classRating} {translate(slot.getItem())}{appliedBlueprint ? : null }
    {formats.round(mass)}{units.T}
    -
    +
    - { m.getMinMass() ?
    {translate('minimum mass')}: {formats.int(m.getMinMass())}{units.T}
    : null } - { m.getOptMass() ?
    {translate('optimal mass')}: {formats.int(m.getOptMass())}{units.T}
    : null } - { m.getMaxMass() ?
    {translate('max mass')}: {formats.int(m.getMaxMass())}{units.T}
    : null } - { m.getOptMul() ?
    {translate('optimal multiplier')}: {formats.rPct(m.getOptMul())}
    : null } - { m.getRange() ?
    {translate('range', m.grp)}: {formats.f2(m.getRange())}{units.km}
    : null } - { m.time ?
    {translate('time')}: {formats.time(m.time)}
    : null } - { m.getThermalEfficiency() ?
    {translate('efficiency')}: {formats.f2(m.getThermalEfficiency())}
    : null } - { m.getPowerGeneration() > 0 ?
    {translate('pgen')}: {formats.f1(m.getPowerGeneration())}{units.MW}
    : null } - { m.getMaxFuelPerJump() ?
    {translate('max')} {translate('fuel')}: {formats.f1(m.getMaxFuelPerJump())}{units.T}
    : null } - { m.getWeaponsCapacity() ?
    {translate('WEP')}: {formats.f1(m.getWeaponsCapacity())}{units.MJ} / {formats.f1(m.getWeaponsRechargeRate())}{units.MW}
    : null } - { m.getSystemsCapacity() ?
    {translate('SYS')}: {formats.f1(m.getSystemsCapacity())}{units.MJ} / {formats.f1(m.getSystemsRechargeRate())}{units.MW}
    : null } - { m.getEnginesCapacity() ?
    {translate('ENG')}: {formats.f1(m.getEnginesCapacity())}{units.MJ} / {formats.f1(m.getEnginesRechargeRate())}{units.MW}
    : null } - { showModuleResistances && m.getExplosiveResistance() ?
    {translate('explres')}: {formats.pct(m.getExplosiveResistance())}
    : null } - { showModuleResistances && m.getKineticResistance() ?
    {translate('kinres')}: {formats.pct(m.getKineticResistance())}
    : null } - { showModuleResistances && m.getThermalResistance() ?
    {translate('thermres')}: {formats.pct(m.getThermalResistance())}
    : null } - { m.getIntegrity() ?
    {translate('integrity')}: {formats.int(m.getIntegrity())}
    : null } - { validMods.length > 0 ?
    this.modButton = modButton }>
    : null } + {/* { m.getMinMass() ?
    {translate('minimum mass')}: {formats.int(m.getMinMass())}{units.T}
    : null } + { m.getOptMass() ?
    {translate('optimal mass')}: {formats.int(m.getOptMass())}{units.T}
    : null } + { m.getMaxMass() ?
    {translate('max mass')}: {formats.int(m.getMaxMass())}{units.T}
    : null } + { m.getOptMul() ?
    {translate('optimal multiplier')}: {formats.rPct(m.getOptMul())}
    : null } + { m.getRange() ?
    {translate('range', m.grp)}: {formats.f2(m.getRange())}{units.km}
    : null } + { m.time ?
    {translate('time')}: {formats.time(m.time)}
    : null } + { m.getThermalEfficiency() ?
    {translate('efficiency')}: {formats.f2(m.getThermalEfficiency())}
    : null } + { m.getPowerGeneration() > 0 ?
    {translate('pgen')}: {formats.f1(m.getPowerGeneration())}{units.MW}
    : null } + { m.getMaxFuelPerJump() ?
    {translate('max')} {translate('fuel')}: {formats.f1(m.getMaxFuelPerJump())}{units.T}
    : null } + { m.getWeaponsCapacity() ?
    {translate('WEP')}: {formats.f1(m.getWeaponsCapacity())}{units.MJ} / {formats.f1(m.getWeaponsRechargeRate())}{units.MW}
    : null } + { m.getSystemsCapacity() ?
    {translate('SYS')}: {formats.f1(m.getSystemsCapacity())}{units.MJ} / {formats.f1(m.getSystemsRechargeRate())}{units.MW}
    : null } + { m.getEnginesCapacity() ?
    {translate('ENG')}: {formats.f1(m.getEnginesCapacity())}{units.MJ} / {formats.f1(m.getEnginesRechargeRate())}{units.MW}
    : null } + { showModuleResistances && m.getExplosiveResistance() ?
    {translate('explres')}: {formats.pct(m.getExplosiveResistance())}
    : null } + { showModuleResistances && m.getKineticResistance() ?
    {translate('kinres')}: {formats.pct(m.getKineticResistance())}
    : null } + { showModuleResistances && m.getThermalResistance() ?
    {translate('thermres')}: {formats.pct(m.getThermalResistance())}
    : null } + { m.getIntegrity() ?
    {translate('integrity')}: {formats.int(m.getIntegrity())}
    : null } */} + {/* { validMods.length > 0 ?
    this.modButton = modButton }>
    : null } */}
    diff --git a/src/app/components/StandardSlotSection.jsx b/src/app/components/StandardSlotSection.jsx index 7ed5cb55..e27e645a 100644 --- a/src/app/components/StandardSlotSection.jsx +++ b/src/app/components/StandardSlotSection.jsx @@ -5,12 +5,12 @@ import StandardSlot from './StandardSlot'; import Module from '../shipyard/Module'; import * as ShipRoles from '../shipyard/ShipRoles'; import { stopCtxPropagation } from '../utils/UtilityFunctions'; +import { ShipProps } from 'ed-forge'; /** * Standard Slot section */ export default class StandardSlotSection extends SlotSection { - /** * Constructor * @param {Object} props React Component properties @@ -39,8 +39,6 @@ export default class StandardSlotSection extends SlotSection { this.selectedRefId = 'maxjump'; this.props.ship.useLightestStandard(); this.props.onChange(); - this.props.onCargoChange(this.props.ship.cargoCapacity); - this.props.onFuelChange(this.props.ship.fuelCapacity); this._close(); } @@ -54,8 +52,6 @@ export default class StandardSlotSection extends SlotSection { if (bulkheadIndex === 2) this.selectedRefId = 'combat'; ShipRoles.multiPurpose(this.props.ship, shielded, bulkheadIndex); this.props.onChange(); - this.props.onCargoChange(this.props.ship.cargoCapacity); - this.props.onFuelChange(this.props.ship.fuelCapacity); this._close(); } @@ -67,8 +63,6 @@ export default class StandardSlotSection extends SlotSection { this.selectedRefId = 'trader'; ShipRoles.trader(this.props.ship, shielded); this.props.onChange(); - this.props.onCargoChange(this.props.ship.cargoCapacity); - this.props.onFuelChange(this.props.ship.fuelCapacity); this._close(); } @@ -80,8 +74,6 @@ export default class StandardSlotSection extends SlotSection { this.selectedRefId = 'miner'; ShipRoles.miner(this.props.ship, shielded); this.props.onChange(); - this.props.onCargoChange(this.props.ship.cargoCapacity); - this.props.onFuelChange(this.props.ship.fuelCapacity); this._close(); } @@ -94,8 +86,6 @@ export default class StandardSlotSection extends SlotSection { if (planetary) this.selectedRefId = 'planetary'; ShipRoles.explorer(this.props.ship, planetary); this.props.onChange(); - this.props.onCargoChange(this.props.ship.cargoCapacity); - this.props.onFuelChange(this.props.ship.fuelCapacity); this._close(); } @@ -106,8 +96,6 @@ export default class StandardSlotSection extends SlotSection { this.selectedRefId = 'racer'; ShipRoles.racer(this.props.ship); this.props.onChange(); - this.props.onCargoChange(this.props.ship.cargoCapacity); - this.props.onFuelChange(this.props.ship.fuelCapacity); this._close(); } @@ -134,105 +122,114 @@ export default class StandardSlotSection extends SlotSection { * @return {Array} Array of Slots */ _getSlots() { - let { ship, currentMenu, cargo, fuel } = this.props; + let { ship, currentMenu } = this.props; let slots = new Array(8); let open = this._openMenu; let select = this._selectModule; - let st = ship.standard; - let avail = ship.getAvailableModules().standard; - let bh = ship.bulkheads; + // let st = ship.standard; + // let avail = ship.getAvailableModules().standard; + // let bh = ship.bulkheads; + let armour = ship.getAlloys(); slots[0] = ; + const powerPlant = ship.getPowerPlant(); slots[1] = m instanceof Module ? m.getPowerGeneration() < ship.powerRetracted : m.pgen < ship.powerRetracted} + warning={m => ship.get(ShipProps.CONSUMED_RETR) < m.get('powercapacity')} />; + const thrusters = ship.getThrusters(); slots[2] = m instanceof Module ? m.getMaxMass() < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass) : m.maxmass < (ship.unladenMass + cargo + fuel - st[1].m.mass + m.mass)} + warning={m => m.get('enginemaximalmass') < ship.get(ShipProps.LADEN_MASS)} />; + const fsd = ship.getFSD(); slots[3] = ; + const lifeSupport = ship.getLifeSupport(); slots[4] = ; + const powerDistributor = ship.getPowerDistributor(); slots[5] = m instanceof Module ? m.getEnginesCapacity() <= ship.boostEnergy : m.engcap <= ship.boostEnergy} />; + const sensors = ship.getSensors(); slots[6] = ; + const fuelTank = ship.getCoreFuelTank(); slots[7] = m.fuel < st[2].m.maxfuel} // Show warning when fuel tank is smaller than FSD Max Fuel + // Show warning when fuel tank is smaller than FSD Max Fuel + warning= {m => m.get('fuel') < fsd.get('maxfuel')} />; return slots; @@ -261,5 +258,4 @@ export default class StandardSlotSection extends SlotSection {
    ; } - } diff --git a/src/app/components/UtilitySlotSection.jsx b/src/app/components/UtilitySlotSection.jsx index eeffee31..487af032 100644 --- a/src/app/components/UtilitySlotSection.jsx +++ b/src/app/components/UtilitySlotSection.jsx @@ -67,30 +67,24 @@ export default class UtilitySlotSection extends SlotSection { _getSlots() { let slots = []; let { ship, currentMenu } = this.props; - let hardpoints = ship.hardpoints; let { originSlot, targetSlot } = this.state; - let availableModules = ship.getAvailableModules(); - for (let i = 0, l = hardpoints.length; i < l; i++) { - let h = hardpoints[i]; - if (h.maxClass === 0) { - slots.push( availableModules.getHps(h.maxClass)} - onOpen={this._openMenu.bind(this,h)} - onSelect={this._selectModule.bind(this, h)} - onChange={this.props.onChange} - selected={currentMenu == h} - drag={this._drag.bind(this, h)} - dragOver={this._dragOverSlot.bind(this, h)} - drop={this._drop} - dropClass={this._dropClass(h, originSlot, targetSlot)} - ship={ship} - m={h.m} - enabled={h.enabled ? true : false} - />); - } + for (let h of ship.getUtilities(undefined, true)) { + slots.push(); } return slots; diff --git a/src/app/pages/OutfittingPage.jsx b/src/app/pages/OutfittingPage.jsx index 94c786b3..5c7cec3a 100644 --- a/src/app/pages/OutfittingPage.jsx +++ b/src/app/pages/OutfittingPage.jsx @@ -6,7 +6,7 @@ import Page from './Page'; import Router from '../Router'; import Persist from '../stores/Persist'; import * as Utils from '../utils/UtilityFunctions'; -import Ship from '../shipyard/Ship'; +import { Factory, Ship } from 'ed-forge'; import * as _ from 'lodash'; import { toDetailedBuild } from '../shipyard/Serializer'; import { outfitURL } from '../utils/UrlGenerators'; @@ -64,10 +64,6 @@ export default class OutfittingPage extends Page { this.state = this._initState(props, context); this._keyDown = this._keyDown.bind(this); this._exportBuild = this._exportBuild.bind(this); - this._pipsUpdated = this._pipsUpdated.bind(this); - this._boostUpdated = this._boostUpdated.bind(this); - this._cargoUpdated = this._cargoUpdated.bind(this); - this._fuelUpdated = this._fuelUpdated.bind(this); this._opponentUpdated = this._opponentUpdated.bind(this); this._engagementRangeUpdated = this._engagementRangeUpdated.bind(this); this._sectionMenuRefs = {}; @@ -82,40 +78,14 @@ export default class OutfittingPage extends Page { _initState(props, context) { let params = context.route.params; let shipId = params.ship; - let code = params.code; let buildName = params.bn; - let data = Ships[shipId]; // Retrieve the basic ship properties, slots and defaults let savedCode = Persist.getBuild(shipId, buildName); - if (!data) { - return { error: { message: 'Ship not found: ' + shipId } }; - } - let ship = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance - if (code) { - ship.buildFrom(code); // Populate modules from serialized 'code' URL param - } else { - ship.buildWith(data.defaults); // Populate with default components - } + let code = params.code || savedCode; + let ship = code ? new Ship(code) : Factory.newShip(shipId); // Create a new Ship instance + code = ship.compress(); - this._getTitle = getTitle.bind(this, data.properties.name); + this._getTitle = getTitle.bind(this, ship.getShipType()); - // Obtain ship control from code - const { - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - opponentSys, - opponentEng, - opponentWep, - engagementRange - } = this._obtainControlFromCode(ship, code); return { error: null, title: this._getTitle(buildName), @@ -126,21 +96,6 @@ export default class OutfittingPage extends Page { ship, code, savedCode, - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - opponentSys, - opponentEng, - opponentWep, - engagementRange }; } @@ -168,170 +123,13 @@ export default class OutfittingPage extends Page { /** * Update the control part of the route */ - _updateRouteOnControlChange() { + _updateRoute() { const { ship, shipId, buildName } = this.state; - const code = this._fullCode(ship); + const code = ship.compress(); this._updateRoute(shipId, buildName, code); this.setState({ code }); } - /** - * Provide a full code for this ship, including any additions due to the outfitting page - * @param {Object} ship the ship - * @param {number} fuel the fuel carried by the ship (if different from that in state) - * @param {number} cargo the cargo carried by the ship (if different from that in state) - * @returns {string} the code for this ship - */ - _fullCode(ship, fuel, cargo) { - return `${ship.toString()}.${LZString.compressToBase64( - this._controlCode(fuel, cargo) - )}`; - } - - /** - * Obtain the control information from the build code - * @param {Object} ship The ship - * @param {string} code The build code - * @returns {Object} The control information - */ - _obtainControlFromCode(ship, code) { - // Defaults - let sys = 2; - let eng = 2; - let wep = 2; - let mcSys = 0; - let mcEng = 0; - let mcWep = 0; - let boost = false; - let fuel = ship.fuelCapacity; - let cargo = ship.cargoCapacity; - let opponent = new Ship( - 'eagle', - Ships['eagle'].properties, - Ships['eagle'].slots - ).buildWith(Ships['eagle'].defaults); - let opponentSys = 2; - let opponentEng = 2; - let opponentWep = 2; - let opponentBuild; - let engagementRange = 1000; - - // Obtain updates from code, if available - if (code) { - const parts = code.split('.'); - if (parts.length >= 5) { - // We have control information in the code - const control = LZString.decompressFromBase64( - Utils.fromUrlSafe(parts[4]) - ).split('/'); - sys = parseFloat(control[0]); - eng = parseFloat(control[1]); - wep = parseFloat(control[2]); - if (sys + eng + wep > 6) { - sys = eng = wep = 2; - } - boost = control[3] == 1 ? true : false; - fuel = parseFloat(control[4]) || fuel; - cargo = parseInt(control[5]) || cargo; - if (control[6]) { - const shipId = control[6]; - opponent = new Ship( - shipId, - Ships[shipId].properties, - Ships[shipId].slots - ); - if (control[7] && Persist.getBuild(shipId, control[7])) { - // Ship is a particular build - const opponentCode = Persist.getBuild(shipId, control[7]); - opponent.buildFrom(opponentCode); - opponentBuild = control[7]; - if (opponentBuild) { - // Obtain opponent's sys/eng/wep pips from their code - const opponentParts = opponentCode.split('.'); - if (opponentParts.length >= 5) { - const opponentControl = LZString.decompressFromBase64( - Utils.fromUrlSafe(opponentParts[4]) - ).split('/'); - opponentSys = parseFloat(opponentControl[0]) || opponentSys; - opponentEng = parseFloat(opponentControl[1]) || opponentEng; - opponentWep = parseFloat(opponentControl[2]) || opponentWep; - } - } - } else { - // Ship is a stock build - opponent.buildWith(Ships[shipId].defaults); - } - } - engagementRange = parseInt(control[8]) || engagementRange; - - // Multi-crew pips were introduced later on so assign default values - // because those values might not be present. - mcSys = parseInt(control[9]) || mcSys; - mcEng = parseInt(control[10]) || mcEng; - mcWep = parseInt(control[11]) || mcWep; - } - } - - return { - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - opponentSys, - opponentEng, - opponentWep, - engagementRange - }; - } - - /** - * Triggered when pips have been updated. Multi-crew pips are already included - * in sys, eng and wep but mcSys, mcEng and mcWep make clear where each pip - * comes from. - * @param {number} sys SYS pips - * @param {number} eng ENG pips - * @param {number} wep WEP pips - * @param {number} mcSys SYS pips from multi-crew - * @param {number} mcEng ENG pips from multi-crew - * @param {number} mcWep WEP pips from multi-crew - */ - _pipsUpdated(sys, eng, wep, mcSys, mcEng, mcWep) { - this.setState({ sys, eng, wep, mcSys, mcEng, mcWep }, () => - this._updateRouteOnControlChange() - ); - } - - /** - * Triggered when boost has been updated - * @param {boolean} boost true if boosting - */ - _boostUpdated(boost) { - this.setState({ boost }, () => this._updateRouteOnControlChange()); - } - - /** - * Triggered when fuel has been updated - * @param {number} fuel the amount of fuel, in T - */ - _fuelUpdated(fuel) { - this.setState({ fuel }, () => this._updateRouteOnControlChange()); - } - - /** - * Triggered when cargo has been updated - * @param {number} cargo the amount of cargo, in T - */ - _cargoUpdated(cargo) { - this.setState({ cargo }, () => this._updateRouteOnControlChange()); - } - /** * Triggered when engagement range has been updated * @param {number} engagementRange the engagement range, in m @@ -387,36 +185,10 @@ export default class OutfittingPage extends Page { opponentEng, opponentWep }, - () => this._updateRouteOnControlChange() + () => this._updateRoute() ); } - /** - * Set the control code for this outfitting page - * @param {number} fuel the fuel carried by the ship (if different from that in state) - * @param {number} cargo the cargo carried by the ship (if different from that in state) - * @returns {string} The control code - */ - _controlCode(fuel, cargo) { - const { - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - opponent, - opponentBuild, - engagementRange - } = this.state; - const code = `${sys}/${eng}/${wep}/${boost ? 1 : 0}/${fuel || - this.state.fuel}/${cargo || this.state.cargo}/${opponent.id}/${ - opponentBuild ? opponentBuild : '' - }/${engagementRange}/${mcSys}/${mcEng}/${mcWep}`; - return code; - } - /** * Save the current build */ @@ -424,7 +196,7 @@ export default class OutfittingPage extends Page { const { ship, buildName, newBuildName, shipId } = this.state; // If this is a stock ship the code won't be set, so ensure that we have it - const code = this.state.code || ship.toString(); + const code = this.state.code || ship.compress(); Persist.saveBuild(shipId, newBuildName, code); this._updateRoute(shipId, newBuildName, code); @@ -497,39 +269,9 @@ export default class OutfittingPage extends Page { // Rebuild ship ship.buildWith(Ships[shipId].defaults); // Reset controls - const code = ship.toString(); - const { - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - engagementRange - } = this._obtainControlFromCode(ship, code); + const code = ship.compress(); // Update state, and refresh the ship - this.setState( - { - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - engagementRange - }, - () => this._updateRoute(shipId, buildName, code) - ); + this._updateRoute(shipId, buildName, code); } /** @@ -573,65 +315,22 @@ export default class OutfittingPage extends Page { * Called when the code for the ship has been updated, to synchronise the rest of the data */ _codeUpdated() { - const { code, ship, shipId, buildName } = this.state; + const { code, shipId, buildName } = this.state; - // Rebuild ship from the code - this.state.ship.buildFrom(code); - - // Obtain controls from the code - const { - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - engagementRange - } = this._obtainControlFromCode(ship, code); - // Update state, and refresh the route when complete - this.setState( - { - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - engagementRange - }, - () => this._updateRoute(shipId, buildName, code) - ); + this.setState({ + ship: new Ship(code), + }, () => this._updateRoute(shipId, buildName, code)); } /** * Called when the ship has been updated, to set the code and then update accordingly */ _shipUpdated() { - let { ship, shipId, buildName, cargo, fuel } = this.state; - if (cargo > ship.cargoCapacity) { - cargo = ship.cargoCapacity; - } - if (fuel > ship.fuelCapacity) { - fuel = ship.fuelCapacity; - } - const code = this._fullCode(ship, fuel, cargo); + let { ship, shipId, buildName } = this.state; + const code = ship.compress(); // Only update the state if this really has been updated - if ( - this.state.code != code || - this.state.cargo != cargo || - this.state.fuel != fuel - ) { - this.setState({ code, cargo, fuel }, () => + if (this.state.code != code) { + this.setState({ code }, () => this._updateRoute(shipId, buildName, code) ); } @@ -747,29 +446,20 @@ export default class OutfittingPage extends Page { */ renderPage() { let state = this.state, - { language, termtip, tooltip, sizeRatio, onWindowResize } = this.context, - { translate, units, formats } = language, + { language, termtip, tooltip, sizeRatio } = this.context, + { translate } = language, { ship, code, savedCode, buildName, newBuildName, - sys, - eng, - wep, - mcSys, - mcEng, - mcWep, - boost, - fuel, - cargo, - opponent, - opponentBuild, - opponentSys, - opponentEng, - opponentWep, - engagementRange + // opponent, + // opponentBuild, + // opponentSys, + // opponentEng, + // opponentWep, + // engagementRange } = state, hide = tooltip.bind(null, null), menu = this.props.currentMenu, @@ -782,88 +472,88 @@ export default class OutfittingPage extends Page { code = ship.name + (code || ''); // Markers are used to propagate state changes without requiring a deep comparison of the ship, as that takes a long time - const _sStr = ship.getStandardString(); - const _iStr = ship.getInternalString(); - const _hStr = ship.getHardpointsString(); - const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`; - const _mStr = ship.getModificationsString(); + // const _sStr = ship.getStandardString(); + // const _iStr = ship.getInternalString(); + // const _hStr = ship.getHardpointsString(); + // const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`; + // const _mStr = ship.getModificationsString(); - const standardSlotMarker = `${ship.name}${_sStr}${_pStr}${_mStr}${ - ship.ladenMass - }${cargo}${fuel}`; - const internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`; - const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`; - const boostMarker = `${ship.canBoost(cargo, fuel)}`; - const shipSummaryMarker = `${ - ship.name - }${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`; + // const standardSlotMarker = `${ship.name}${_sStr}${_pStr}${_mStr}${ + // ship.ladenMass + // }${cargo}${fuel}`; + // const internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`; + // const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`; + // const boostMarker = `${ship.canBoost(cargo, fuel)}`; + // const shipSummaryMarker = `${ + // ship.name + // }${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`; - const requirements = Ships[ship.id].requirements; - let requirementElements = []; - /** - * Render the requirements for a ship / etc - * @param {string} className Class names - * @param {string} textKey The key for translating - * @param {String} tooltipTextKey Tooltip key - */ - function renderRequirement(className, textKey, tooltipTextKey) { - if (textKey.startsWith('empire') || textKey.startsWith('federation')) { - requirementElements.push( - - ); - } else { - requirementElements.push( -
    - {translate(textKey)} -
    - ); - } - } + // const requirements = Ships[ship.id].requirements; + // let requirementElements = []; + // /** + // * Render the requirements for a ship / etc + // * @param {string} className Class names + // * @param {string} textKey The key for translating + // * @param {String} tooltipTextKey Tooltip key + // */ + // function renderRequirement(className, textKey, tooltipTextKey) { + // if (textKey.startsWith('empire') || textKey.startsWith('federation')) { + // requirementElements.push( + // + // ); + // } else { + // requirementElements.push( + //
    + // {translate(textKey)} + //
    + // ); + // } + // } - if (requirements) { - requirements.federationRank && - renderRequirement( - 'federation', - 'federation rank ' + requirements.federationRank, - 'federation rank required' - ); - requirements.empireRank && - renderRequirement( - 'empire', - 'empire rank ' + requirements.empireRank, - 'empire rank required' - ); - requirements.horizons && - renderRequirement('horizons', 'horizons', 'horizons required'); - requirements.horizonsEarlyAdoption && - renderRequirement( - 'horizons', - 'horizons early adoption', - 'horizons early adoption required' - ); - } + // if (requirements) { + // requirements.federationRank && + // renderRequirement( + // 'federation', + // 'federation rank ' + requirements.federationRank, + // 'federation rank required' + // ); + // requirements.empireRank && + // renderRequirement( + // 'empire', + // 'empire rank ' + requirements.empireRank, + // 'empire rank required' + // ); + // requirements.horizons && + // renderRequirement('horizons', 'horizons', 'horizons required'); + // requirements.horizonsEarlyAdoption && + // renderRequirement( + // 'horizons', + // 'horizons early adoption', + // 'horizons early adoption required' + // ); + // } return (
    -

    {ship.name}

    -
    {requirementElements}
    +

    {ship.getShipType()}

    + {/*
    {requirementElements}
    */}
    {/* Main tables */} - + /> */} {/* Control of ship and opponent */} -
    + {/*

    {translate('ship control')} @@ -1044,7 +725,6 @@ export default class OutfittingPage extends Page {
    @@ -1052,7 +732,6 @@ export default class OutfittingPage extends Page { {ship.cargoCapacity > 0 ? ( ) : null} @@ -1077,10 +756,10 @@ export default class OutfittingPage extends Page { engagementRange={engagementRange} onChange={this._engagementRangeUpdated} /> -

    +
    */} {/* Tabbed subpages */} - + /> */}
    ); } diff --git a/src/app/pages/ShipyardPage.jsx b/src/app/pages/ShipyardPage.jsx index 4f3a60c9..793a5365 100644 --- a/src/app/pages/ShipyardPage.jsx +++ b/src/app/pages/ShipyardPage.jsx @@ -1,21 +1,11 @@ import React from 'react'; import Page from './Page'; -import { Ships } from 'coriolis-data/dist'; import cn from 'classnames'; -import Ship from '../shipyard/Ship'; +import { Factory } from 'ed-forge'; import * as ModuleUtils from '../shipyard/ModuleUtils'; import { SizeMap } from '../shipyard/Constants'; import Link from '../components/Link'; -/** - * Counts the hardpoints by class/size - * @param {Object} slot Hardpoint Slot model - */ -function countHp(slot) { - this.hp[slot.maxClass]++; - this.hpCount++; -} - /** * Counts the internal slots and aggregated properties * @param {Object} slot Internal Slots @@ -53,50 +43,55 @@ function countInt(slot) { /** * Generate Ship summary and aggregated properties * @param {String} shipId Ship Id - * @param {Object} shipData Ship Default Data * @return {Object} Ship summary and aggregated properties */ -function shipSummary(shipId, shipData) { +function shipSummary(shipId) { + // Build Ship + let ship = Factory.newShip(shipId); + let summary = { id: shipId, hpCount: 0, intCount: 0, - beta: shipData.beta, maxCargo: 0, maxPassengers: 0, hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8 - standard: shipData.slots.standard, + standard: ship.readMeta('coreSizes'), agility: - shipData.properties.pitch + - shipData.properties.yaw + - shipData.properties.roll + ship.getBaseProperty('pitch') + + ship.getBaseProperty('yaw') + + ship.getBaseProperty('roll') }; - Object.assign(summary, shipData.properties); - let ship = new Ship(shipId, shipData.properties, shipData.slots); - // Build Ship - ship.buildWith(shipData.defaults); // Populate with stock/default components - ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class - ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class - summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost - ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range - summary.maxJumpRange = ship.unladenRange; // Record Jump Range + // Count Hardpoints by class + ship.getHardpoints(undefined, true).forEach(hardpoint => { + summary.hp[hardpoint.getSize()]++; + summary.hpCount++; + }); + // Count Internal Compartments by class + ship.getInternals(undefined, true).forEach(internal => { + summary.int[internal.getSize()]++; + summary.intCount++; + }); + summary.retailCost = ship.readMeta('retailCost'); // Record Stock/Default/retail cost + // ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range + summary.maxJumpRange = -1; // ship.unladenRange; // Record Jump Range // Best thrusters - let th; - if (ship.standard[1].maxClass === 3) { - th = 'tz'; - } else if (ship.standard[1].maxClass === 2) { - th = 'u0'; - } else { - th = ship.standard[1].maxClass + 'A'; - } + // let th; + // if (ship.standard[1].maxClass === 3) { + // th = 'tz'; + // } else if (ship.standard[1].maxClass === 2) { + // th = 'u0'; + // } else { + // th = ship.standard[1].maxClass + 'A'; + // } - ship.optimizeMass({ th, fsd: '2D', ft: '1C' }); // Optmize mass with Max Thrusters - summary.topSpeed = ship.topSpeed; - summary.topBoost = ship.topBoost; - summary.baseArmour = ship.armour; + // ship.optimizeMass({ th, fsd: '2D', ft: '1C' }); // Optmize mass with Max Thrusters + summary.topSpeed = -1; // ship.topSpeed; + summary.topBoost = -1; // ship.topBoost; + summary.baseArmour = -1; // ship.armour; return summary; } @@ -117,8 +112,8 @@ export default class ShipyardPage extends Page { if (!ShipyardPage.cachedShipSummaries) { ShipyardPage.cachedShipSummaries = []; - for (let s in Ships) { - ShipyardPage.cachedShipSummaries.push(shipSummary(s, Ships[s])); + for (let s of Factory.getAllShipTypes()) { + ShipyardPage.cachedShipSummaries.push(shipSummary(s)); } } @@ -335,7 +330,7 @@ export default class ShipyardPage extends Page { onClick={() => this._toggleCompare(s.id)} >
    ); diff --git a/src/app/utils/BlueprintFunctions.js b/src/app/utils/BlueprintFunctions.js index 8fbe2fb4..a44c1f4f 100644 --- a/src/app/utils/BlueprintFunctions.js +++ b/src/app/utils/BlueprintFunctions.js @@ -66,12 +66,10 @@ export function specialToolTip(translate, blueprint, grp, m, specialName) { * Generate a tooltip with details of a blueprint's effects * @param {Object} translate The translate object * @param {Object} blueprint The blueprint at the required grade - * @param {Array} engineers The engineers supplying this blueprint - * @param {string} grp The group of the module * @param {Object} m The module to compare with * @returns {Object} The react components */ -export function blueprintTooltip(translate, blueprint, engineers, grp, m) { +export function blueprintTooltip(translate, blueprint, m) { const effects = []; if (!blueprint || !blueprint.features) { return undefined; @@ -105,7 +103,7 @@ export function blueprintTooltip(translate, blueprint, engineers, grp, m) { const currentIsBeneficial = isValueBeneficial(feature, current); effects.push( - + @@ -115,7 +113,7 @@ export function blueprintTooltip(translate, blueprint, engineers, grp, m) { // We do not have a module, no value effects.push( - + @@ -144,7 +142,7 @@ export function blueprintTooltip(translate, blueprint, engineers, grp, m) { const currentIsBeneficial = isValueBeneficial(feature, current); effects.push( - + @@ -175,7 +173,7 @@ export function blueprintTooltip(translate, blueprint, engineers, grp, m) { const currentIsBeneficial = isValueBeneficial(feature, current); effects.push( - + @@ -200,17 +198,18 @@ export function blueprintTooltip(translate, blueprint, engineers, grp, m) { } } - let engineersList; - if (engineers) { - engineersList = []; - for (const engineer of engineers) { - engineersList.push( - - - - ); - } - } + let engineersList = []; + // TODO: + // if (engineers) { + // engineersList = []; + // for (const engineer of engineers) { + // engineersList.push( + // + // + // + // ); + // } + // } return (
    @@ -285,7 +284,7 @@ export function isValueBeneficial(feature, value) { * Is the change as shown beneficial? * @param {string} feature The name of the feature * @param {number} value The value of the feature as percentage change - * @returns True if the value is beneficial + * @returns {boolean} True if the value is beneficial */ export function isChangeValueBeneficial(feature, value) { let changeHigherBetter = STATS_FORMATTING[feature].higherbetter;
    {translate('speed')}{translate('speed')} {translate('boost')}{translate('jump range')}{translate('jump range')} {translate('shield')} {translate('integrity')} {translate('DPS')} - {s.name} {s.beta === true ? '(Beta)' : null} + {s.id} {s.beta === true ? '(Beta)' : null}
    {translate(feature, grp)}{translate(feature)} {lowerBound}{symbol} {current}{symbol} {upperBound}{symbol}
    {translate(feature, grp)}{translate(feature)} {lowerBound}{symbol} {upperBound}{symbol}
    {translate(feature, grp)}{translate(feature)}   {current}{symbol}  
    {translate(feature, grp)}{translate(feature)}   {current}{symbol}  
    {engineer}
    {engineer}