import React from 'react'; import Page from './Page'; import { Ships } from 'coriolis-data/dist'; import cn from 'classnames'; import Ship from '../shipyard/Ship'; 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 */ function countInt(slot) { let crEligible = !slot.eligible || slot.eligible.cr; this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment this.intCount++; this.maxCargo += crEligible ? ModuleUtils.findInternal('cr', slot.maxClass, 'E').cargo : 0; } /** * 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) { let summary = { id: shipId, hpCount: 0, intCount: 0, maxCargo: 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, agility: shipData.properties.pitch + shipData.properties.yaw + shipData.properties.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 ship.optimizeMass({ th: ship.standard[1].maxClass + 'A', fsd: '2D', ft: '1C' }); // Optmize mass with Max Thrusters summary.topSpeed = ship.topSpeed; summary.topBoost = ship.topBoost; summary.baseArmour = ship.armour; return summary; } /** * The Shipyard summary page */ export default class ShipyardPage extends Page { static cachedShipSummaries = null; /** * Constructor * @param {Object} props React Component properties * @param {Object} context React Component context */ constructor(props, context) { super(props, context); if (!ShipyardPage.cachedShipSummaries) { ShipyardPage.cachedShipSummaries = []; for (let s in Ships) { ShipyardPage.cachedShipSummaries.push(shipSummary(s, Ships[s])); } } this.state = { title: 'Coriolis EDCD Edition - Shipyard', shipPredicate: 'name', shipDesc: true, shipSummaries: ShipyardPage.cachedShipSummaries }; } /** * Higlight the current ship in the table * @param {String} shipId Ship Id * @param {SyntheticEvent} event Event */ _highlightShip(shipId, event) { event.stopPropagation(); this.setState({ shipId }); } /** * Update state with the specified sort predicates * @param {String} shipPredicate Sort predicate - property name * @param {number} shipPredicateIndex Sort predicate - property index */ _sortShips(shipPredicate, shipPredicateIndex) { let shipDesc = this.state.shipDesc; if (typeof shipPredicateIndex == 'object') { shipPredicateIndex = undefined; } if (this.state.shipPredicate == shipPredicate && this.state.shipPredicateIndex == shipPredicateIndex) { shipDesc = !shipDesc; } this.setState({ shipPredicate, shipDesc, shipPredicateIndex }); }; /** * Generate the table row summary for the ship * @param {Object} s Ship summary * @param {Function} translate Translate function * @param {Object} u Localized unit map * @param {Function} fInt Localized integer formatter * @param {Function} fRound Localized round formatter * @return {React.Component} Table Row */ _shipRowElement(s, translate, u, fInt, fRound) { let noTouch = this.context.noTouch; return {s.manufacturer} {translate(SizeMap[s.class])} {fInt(s.agility)} {fInt(s.hardness)} {fInt(s.crew)} {fInt(s.speed)}{u['m/s']} {fInt(s.boost)}{u['m/s']} {fInt(s.baseArmour)} {fInt(s.baseShieldStrength)}{u.MJ} {fInt(s.topSpeed)}{u['m/s']} {fInt(s.topBoost)}{u['m/s']} {fRound(s.maxJumpRange)}{u.LY} {fInt(s.maxCargo)}{u.T} {s.standard[0]} {s.standard[1]} {s.standard[2]} {s.standard[3]} {s.standard[4]} {s.standard[5]} {s.hp[1]} {s.hp[2]} {s.hp[3]} {s.hp[4]} {s.hp[0]} {s.int[0]} {s.int[1]} {s.int[2]} {s.int[3]} {s.int[4]} {s.int[5]} {s.int[6]} {s.int[7]} {fInt(s.hullMass)}{u.T} {s.masslock} {fInt(s.retailCost)}{u.CR} ; } /** * Render the Page * @return {React.Component} The page contents */ renderPage() { let { sizeRatio, language, termtip, noTouch } = this.context; let { translate, formats, units } = language; let hide = this.context.tooltip.bind(null, null); let fInt = formats.int; let fRound = formats.round; let { shipSummaries, shipPredicate, shipPredicateIndex } = this.state; let sortShips = (predicate, index) => this._sortShips.bind(this, predicate, index); let filters = { // 'class': { 1: 1, 2: 1} }; shipSummaries = shipSummaries.filter(s => { for (let prop in filters) { if (!(s[prop] in filters[prop])) { return false; } } return true; }); // Sort shipsOverview shipSummaries.sort((a, b) => { let valA = a[shipPredicate], valB = b[shipPredicate]; if (shipPredicateIndex != undefined) { valA = valA[shipPredicateIndex]; valB = valB[shipPredicateIndex]; } if (!this.state.shipDesc) { let val = valA; valA = valB; valB = val; } if(valA == valB) { if (a.name > b.name) { return 1; } else { return -1; } } else if (valA > valB) { return 1; } else { return -1; } }); let i = 0; let shipRows = new Array(shipSummaries.length); let detailRows = new Array(shipSummaries.length); for (let s of shipSummaries) { detailRows[i] = this._shipRowElement(s, translate, units, fInt, fRound); shipRows[i] = ( {s.name} ); i++; } return (
{shipRows}
{translate('ship')}
{detailRows}
{translate('manufacturer')} {translate('size')} {translate('agility')} {translate('hardness')} {translate('crew')} {translate('base')} {translate('max')} {translate('core module classes')} {translate('hardpoints')} {translate('internal compartments')} {translate('hull')} {translate('MLF')} {translate('cost')}
{translate('speed')} {translate('boost')} {translate('armour')} {translate('shields')} {translate('speed')} {translate('boost')} {translate('jump')} {translate('cargo')} {'pp'} {'th'} {'fsd'} {'ls'} {'pd'} {'s'} {translate('S')} {translate('M')} {translate('L')} {translate('H')} {translate('U')} 1 2 3 4 5 6 7 8
); } }