various bits

This commit is contained in:
William Blythe
2018-10-23 09:40:13 +11:00
parent 5008c7cd74
commit da07790594
9 changed files with 1059 additions and 1195 deletions

966
d3.js vendored

File diff suppressed because it is too large Load Diff

2
d3.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -402,12 +402,12 @@ export default class Coriolis extends React.Component {
{this.state.tooltip} {this.state.tooltip}
<footer> <footer>
<div className="right cap"> <div className="right cap">
<a href="https://github.com/EDCD/coriolis" target="_blank" <a href="https://github.com/EDCD/coriolis" target="_blank" rel="noopener noreferrer"
title="Coriolis Github Project">{window.CORIOLIS_VERSION} - {window.CORIOLIS_DATE}</a> title="Coriolis Github Project">{window.CORIOLIS_VERSION} - {window.CORIOLIS_DATE}</a>
<br/> <br/>
<a <a
href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'} href={'https://github.com/EDCD/coriolis/compare/edcd:develop@{' + window.CORIOLIS_DATE + '}...edcd:develop'}
target="_blank" title={'Coriolis Commits since' + window.CORIOLIS_DATE}>Commits since last release target="_blank" rel="noopener noreferrer" title={'Coriolis Commits since' + window.CORIOLIS_DATE}>Commits since last release
({window.CORIOLIS_DATE})</a> ({window.CORIOLIS_DATE})</a>
</div> </div>
</footer> </footer>

39
src/app/components/Ad.jsx Normal file
View File

@@ -0,0 +1,39 @@
import React, { Component, PropTypes } from 'react';
export default class Ad extends Component {
static propTypes = {
client: PropTypes.string,
slot: PropTypes.string,
format: PropTypes.string,
wrapperDivStyle: PropTypes.object
};
constructor(props) {
super(props);
}
// This code is ran when the component mounts
componentDidMount() {
try {
(window.adsbygoogle = window.adsbygoogle || []).push({});
} catch (err) {
console.error(err);
}
}
// an outer div for styling purposes
// changed class to ClassName
// changed style from string to an object
render() {
return (
<div style={this.props.wrapperDivStyle}>
<ins
className="adsbygoogle"
style={{ display: 'block' }}
data-ad-client={this.props.client}
data-ad-slot={this.props.slot}
data-ad-format={this.props.format}
/>
</div>
);
}
}

View File

@@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import Page from './Page'; import Page from './Page';
import { CoriolisLogo, GitHub } from '../components/SvgIcons'; import { CoriolisLogo, GitHub } from '../components/SvgIcons';
import Ad from '../components/Ad';
/** /**
* About Page * About Page
*/ */
export default class AboutPage extends Page { export default class AboutPage extends Page {
/** /**
* Constructor * Constructor
* @param {Object} props React Component properties * @param {Object} props React Component properties
@@ -23,33 +23,121 @@ export default class AboutPage extends Page {
* @return {React.Component} The page contents * @return {React.Component} The page contents
*/ */
renderPage() { renderPage() {
return <div className={'page'} style={{ textAlign: 'left', maxWidth: 800, margin: '0 auto' }}> return (
<h1><CoriolisLogo style={{ marginRight: '0.4em' }} className='xl'/><span className='warning'>Coriolis EDCD Edition</span></h1> <div
className={'page'}
style={{ textAlign: 'left', maxWidth: 800, margin: '0 auto' }}
>
<h1>
<CoriolisLogo style={{ marginRight: '0.4em' }} className="xl" />
<span className="warning">Coriolis EDCD Edition</span>
</h1>
<p>This is a clone of the Coriolis project, whose original author is currently unable to maintain it. This clone is maintained by the <a href="http://edcd.github.io/">EDCD community</a>.</p> <p>
<p>To recover your builds, go to <a href='https://coriolis.io/' target='_blank'>https://coriolis.io/</a>, backup your builds (Settings / Backup), copy the text, return here and import (Settings / Import).</p> This is a clone of the Coriolis project, whose original author is
<p>The Coriolis project was inspired by <a href='http://www.edshipyard.com/' target='_blank'>E:D Shipyard</a> and, of course, <a href='http://www.elitedangerous.com' target='_blank'>Elite Dangerous</a>. The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development.</p> currently unable to maintain it. This clone is maintained by the{' '}
<p>Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments. A number of assets were sourced from <a href='http://edassets.org' target='_blank'>ED Assets</a></p> <a href="http://edcd.github.io/">EDCD community</a>.
</p>
<p>
To recover your builds, go to{' '}
<a href="https://coriolis.io/" target="_blank">
https://coriolis.io/
</a>
, backup your builds (Settings / Backup), copy the text, return here
and import (Settings / Import).
</p>
<p>
The Coriolis project was inspired by{' '}
<a href="http://www.edshipyard.com/" target="_blank">
E:D Shipyard
</a>{' '}
and, of course,{' '}
<a href="http://www.elitedangerous.com" target="_blank">
Elite Dangerous
</a>
. The ultimate goal of Coriolis is to provide rich features to support
in-game play and planning while engaging the E:D community to support
its development.
</p>
<p>
Coriolis was created using assets and imagery from Elite: Dangerous,
with the permission of Frontier Developments plc, for non-commercial
purposes. It is not endorsed by nor reflects the views or opinions of
Frontier Developments. A number of assets were sourced from{' '}
<a href="http://edassets.org" target="_blank">
ED Assets
</a>
</p>
<a style={{ display: 'block', textDecoration: 'none' }} href='https://github.com/EDCD/coriolis' target='_blank' title='Coriolis Github Project'> <a
<GitHub style={{ margin: '0.4em' }} className='l fg xl'/> style={{ display: 'block', textDecoration: 'none' }}
<h2 style={{ margin: 0, textDecoration: 'none' }}>Github</h2> href="https://github.com/EDCD/coriolis"
github.com/EDCD/coriolis target="_blank"
</a> title="Coriolis Github Project"
>
<GitHub style={{ margin: '0.4em' }} className="l fg xl" />
<h2 style={{ margin: 0, textDecoration: 'none' }}>Github</h2>
github.com/EDCD/coriolis
</a>
<p>Coriolis is an open source project. Checkout the list of upcoming features and to-do list on github. Any and all contributions and feedback are welcome. If you encounter any bugs please report them and provide as much detail as possible.</p> <p>
Coriolis is an open source project. Checkout the list of upcoming
features and to-do list on github. Any and all contributions and
feedback are welcome. If you encounter any bugs please report them and
provide as much detail as possible.
</p>
<h3>Chat</h3> <h3>Chat</h3>
<p>You can chat to us on our <a href='https://discord.gg/0uwCh6R62aPRjk9w' target='_blank'>EDCD Discord server</a>.</p> <p>
You can chat to us on our{' '}
<a href="https://discord.gg/0uwCh6R62aPRjk9w" target="_blank">
EDCD Discord server
</a>
.
</p>
<h3>Supporting Coriolis</h3> <h3>Supporting Coriolis</h3>
<p>Coriolis is an open source project, and I work on it in my free time. I have set up a patreon at <a href='https://www.patreon.com/coriolis_elite'>patreon.com/coriolis_elite</a>, which will be used to keep Coriolis up to date and the servers running.</p> <p>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top"> Coriolis is an open source project, and I work on it in my free time.
<input type="hidden" name="cmd" value="_s-xclick"/> I have set up a patreon at{' '}
<input type="hidden" name="hosted_button_id" value="SJBKT2SWEEU68" /> <a href="https://www.patreon.com/coriolis_elite">
<input type="image" src="https://www.paypalobjects.com/en_AU/i/btn/btn_donate_SM.gif" border="0" name="submit" alt="PayPal The safer, easier way to pay online!" /> patreon.com/coriolis_elite
<img alt="" border="0" src="https://www.paypalobjects.com/en_AU/i/scr/pixel.gif" width="1" height="1" /> </a>
, which will be used to keep Coriolis up to date and the servers
running.
</p>
<form
action="https://www.paypal.com/cgi-bin/webscr"
method="post"
target="_top"
>
<input type="hidden" name="cmd" value="_s-xclick" />
<input type="hidden" name="hosted_button_id" value="SJBKT2SWEEU68" />
<input
type="image"
src="https://www.paypalobjects.com/en_AU/i/btn/btn_donate_SM.gif"
border="0"
name="submit"
alt="PayPal The safer, easier way to pay online!"
/>
<img
alt=""
border="0"
src="https://www.paypalobjects.com/en_AU/i/scr/pixel.gif"
width="1"
height="1"
/>
</form> </form>
</div>; <Ad
client="ca-pub-3709458261881414"
slot="4156867783"
format="auto"
wrapperDivStyle={{
marginTop: '15px',
marginBottom: '20px'
}}
/>
</div>
);
} }
} }

View File

@@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import Page from './Page'; import Page from './Page';
/** /**
* 404 Page * 404 Page
*/ */
@@ -22,6 +21,7 @@ export default class NotFoundPage extends Page {
* @return {React.Component} The page contents * @return {React.Component} The page contents
*/ */
renderPage() { renderPage() {
return <div className='page' style={{ marginTop: 30 }}>Page <small>{this.context.route.path}</small> Not Found</div>; return <div className='page' style={{ marginTop: 30 }}>Page <small>{this.context.route.path}</small> Not Found
</div>;
} }
} }

View File

@@ -23,6 +23,7 @@ import {
} from '../components/SvgIcons'; } from '../components/SvgIcons';
import LZString from 'lz-string'; import LZString from 'lz-string';
import ShipSummaryTable from '../components/ShipSummaryTable'; import ShipSummaryTable from '../components/ShipSummaryTable';
import Ad from '../components/Ad';
import StandardSlotSection from '../components/StandardSlotSection'; import StandardSlotSection from '../components/StandardSlotSection';
import HardpointSlotSection from '../components/HardpointSlotSection'; import HardpointSlotSection from '../components/HardpointSlotSection';
import InternalSlotSection from '../components/InternalSlotSection'; import InternalSlotSection from '../components/InternalSlotSection';
@@ -53,7 +54,6 @@ function getTitle(shipName, buildName) {
* The Outfitting Page * The Outfitting Page
*/ */
export default class OutfittingPage extends Page { export default class OutfittingPage extends Page {
/** /**
* Constructor * Constructor
* @param {Object} props React Component properties * @param {Object} props React Component properties
@@ -85,22 +85,38 @@ export default class OutfittingPage extends Page {
let shipId = params.ship; let shipId = params.ship;
let code = params.code; let code = params.code;
let buildName = params.bn; let buildName = params.bn;
let data = Ships[shipId]; // Retrieve the basic ship properties, slots and defaults let data = Ships[shipId]; // Retrieve the basic ship properties, slots and defaults
let savedCode = Persist.getBuild(shipId, buildName); let savedCode = Persist.getBuild(shipId, buildName);
if (!data) { if (!data) {
return { error: { message: 'Ship not found: ' + shipId } }; return { error: { message: 'Ship not found: ' + shipId } };
} }
let ship = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance let ship = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance
if (code) { if (code) {
ship.buildFrom(code); // Populate modules from serialized 'code' URL param ship.buildFrom(code); // Populate modules from serialized 'code' URL param
} else { } else {
ship.buildWith(data.defaults); // Populate with default components ship.buildWith(data.defaults); // Populate with default components
} }
this._getTitle = getTitle.bind(this, data.properties.name); this._getTitle = getTitle.bind(this, data.properties.name);
// Obtain ship control from code // 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); const {
sys,
eng,
wep,
mcSys,
mcEng,
mcWep,
boost,
fuel,
cargo,
opponent,
opponentBuild,
opponentSys,
opponentEng,
opponentWep,
engagementRange
} = this._obtainControlFromCode(ship, code);
return { return {
error: null, error: null,
title: this._getTitle(buildName), title: this._getTitle(buildName),
@@ -139,7 +155,10 @@ export default class OutfittingPage extends Page {
}; };
if (Persist.hasBuild(this.state.shipId, stateChanges.newBuildName)) { if (Persist.hasBuild(this.state.shipId, stateChanges.newBuildName)) {
stateChanges.savedCode = Persist.getBuild(this.state.shipId, stateChanges.newBuildName); stateChanges.savedCode = Persist.getBuild(
this.state.shipId,
stateChanges.newBuildName
);
} else { } else {
stateChanges.savedCode = null; stateChanges.savedCode = null;
} }
@@ -165,7 +184,9 @@ export default class OutfittingPage extends Page {
* @returns {string} the code for this ship * @returns {string} the code for this ship
*/ */
_fullCode(ship, fuel, cargo) { _fullCode(ship, fuel, cargo) {
return `${ship.toString()}.${LZString.compressToBase64(this._controlCode(fuel, cargo))}`; return `${ship.toString()}.${LZString.compressToBase64(
this._controlCode(fuel, cargo)
)}`;
} }
/** /**
@@ -185,7 +206,11 @@ export default class OutfittingPage extends Page {
let boost = false; let boost = false;
let fuel = ship.fuelCapacity; let fuel = ship.fuelCapacity;
let cargo = ship.cargoCapacity; let cargo = ship.cargoCapacity;
let opponent = new Ship('eagle', Ships['eagle'].properties, Ships['eagle'].slots).buildWith(Ships['eagle'].defaults); let opponent = new Ship(
'eagle',
Ships['eagle'].properties,
Ships['eagle'].slots
).buildWith(Ships['eagle'].defaults);
let opponentSys = 2; let opponentSys = 2;
let opponentEng = 2; let opponentEng = 2;
let opponentWep = 2; let opponentWep = 2;
@@ -197,7 +222,9 @@ export default class OutfittingPage extends Page {
const parts = code.split('.'); const parts = code.split('.');
if (parts.length >= 5) { if (parts.length >= 5) {
// We have control information in the code // We have control information in the code
const control = LZString.decompressFromBase64(Utils.fromUrlSafe(parts[4])).split('/'); const control = LZString.decompressFromBase64(
Utils.fromUrlSafe(parts[4])
).split('/');
sys = parseFloat(control[0]) || sys; sys = parseFloat(control[0]) || sys;
eng = parseFloat(control[1]) || eng; eng = parseFloat(control[1]) || eng;
wep = parseFloat(control[2]) || wep; wep = parseFloat(control[2]) || wep;
@@ -206,7 +233,11 @@ export default class OutfittingPage extends Page {
cargo = parseInt(control[5]) || cargo; cargo = parseInt(control[5]) || cargo;
if (control[6]) { if (control[6]) {
const shipId = control[6]; const shipId = control[6];
opponent = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots); opponent = new Ship(
shipId,
Ships[shipId].properties,
Ships[shipId].slots
);
if (control[7] && Persist.getBuild(shipId, control[7])) { if (control[7] && Persist.getBuild(shipId, control[7])) {
// Ship is a particular build // Ship is a particular build
const opponentCode = Persist.getBuild(shipId, control[7]); const opponentCode = Persist.getBuild(shipId, control[7]);
@@ -216,7 +247,9 @@ export default class OutfittingPage extends Page {
// Obtain opponent's sys/eng/wep pips from their code // Obtain opponent's sys/eng/wep pips from their code
const opponentParts = opponentCode.split('.'); const opponentParts = opponentCode.split('.');
if (opponentParts.length >= 5) { if (opponentParts.length >= 5) {
const opponentControl = LZString.decompressFromBase64(Utils.fromUrlSafe(opponentParts[4])).split('/'); const opponentControl = LZString.decompressFromBase64(
Utils.fromUrlSafe(opponentParts[4])
).split('/');
opponentSys = parseFloat(opponentControl[0]) || opponentSys; opponentSys = parseFloat(opponentControl[0]) || opponentSys;
opponentEng = parseFloat(opponentControl[1]) || opponentEng; opponentEng = parseFloat(opponentControl[1]) || opponentEng;
opponentWep = parseFloat(opponentControl[2]) || opponentWep; opponentWep = parseFloat(opponentControl[2]) || opponentWep;
@@ -237,7 +270,23 @@ export default class OutfittingPage extends Page {
} }
} }
return { sys, eng, wep, mcSys, mcEng, mcWep, boost, fuel, cargo, opponent, opponentBuild, opponentSys, opponentEng, opponentWep, engagementRange }; return {
sys,
eng,
wep,
mcSys,
mcEng,
mcWep,
boost,
fuel,
cargo,
opponent,
opponentBuild,
opponentSys,
opponentEng,
opponentWep,
engagementRange
};
} }
/** /**
@@ -252,7 +301,9 @@ export default class OutfittingPage extends Page {
* @param {number} mcWep WEP pips from multi-crew * @param {number} mcWep WEP pips from multi-crew
*/ */
_pipsUpdated(sys, eng, wep, mcSys, mcEng, mcWep) { _pipsUpdated(sys, eng, wep, mcSys, mcEng, mcWep) {
this.setState({ sys, eng, wep, mcSys, mcEng, mcWep }, () => this._updateRouteOnControlChange()); this.setState({ sys, eng, wep, mcSys, mcEng, mcWep }, () =>
this._updateRouteOnControlChange()
);
} }
/** /**
@@ -260,7 +311,7 @@ export default class OutfittingPage extends Page {
* @param {boolean} boost true if boosting * @param {boolean} boost true if boosting
*/ */
_boostUpdated(boost) { _boostUpdated(boost) {
this.setState({ boost }, () => this._updateRouteOnControlChange()); this.setState({ boost }, () => this._updateRouteOnControlChange());
} }
/** /**
@@ -268,7 +319,7 @@ export default class OutfittingPage extends Page {
* @param {number} fuel the amount of fuel, in T * @param {number} fuel the amount of fuel, in T
*/ */
_fuelUpdated(fuel) { _fuelUpdated(fuel) {
this.setState({ fuel }, () => this._updateRouteOnControlChange()); this.setState({ fuel }, () => this._updateRouteOnControlChange());
} }
/** /**
@@ -276,7 +327,7 @@ export default class OutfittingPage extends Page {
* @param {number} cargo the amount of cargo, in T * @param {number} cargo the amount of cargo, in T
*/ */
_cargoUpdated(cargo) { _cargoUpdated(cargo) {
this.setState({ cargo }, () => this._updateRouteOnControlChange()); this.setState({ cargo }, () => this._updateRouteOnControlChange());
} }
/** /**
@@ -284,7 +335,9 @@ export default class OutfittingPage extends Page {
* @param {number} engagementRange the engagement range, in m * @param {number} engagementRange the engagement range, in m
*/ */
_engagementRangeUpdated(engagementRange) { _engagementRangeUpdated(engagementRange) {
this.setState({ engagementRange }, () => this._updateRouteOnControlChange()); this.setState({ engagementRange }, () =>
this._updateRouteOnControlChange()
);
} }
/** /**
@@ -293,7 +346,11 @@ export default class OutfittingPage extends Page {
* @param {string} opponentBuild the name of the opponent's build * @param {string} opponentBuild the name of the opponent's build
*/ */
_opponentUpdated(opponent, opponentBuild) { _opponentUpdated(opponent, opponentBuild) {
const opponentShip = new Ship(opponent, Ships[opponent].properties, Ships[opponent].slots); const opponentShip = new Ship(
opponent,
Ships[opponent].properties,
Ships[opponent].slots
);
let opponentSys = this.state.opponentSys; let opponentSys = this.state.opponentSys;
let opponentEng = this.state.opponentEng; let opponentEng = this.state.opponentEng;
let opponentWep = this.state.opponentWep; let opponentWep = this.state.opponentWep;
@@ -301,9 +358,13 @@ export default class OutfittingPage extends Page {
// Ship is a particular build // Ship is a particular build
opponentShip.buildFrom(Persist.getBuild(opponent, opponentBuild)); opponentShip.buildFrom(Persist.getBuild(opponent, opponentBuild));
// Set pips for opponent // Set pips for opponent
const opponentParts = Persist.getBuild(opponent, opponentBuild).split('.'); const opponentParts = Persist.getBuild(opponent, opponentBuild).split(
'.'
);
if (opponentParts.length >= 5) { if (opponentParts.length >= 5) {
const opponentControl = LZString.decompressFromBase64(Utils.fromUrlSafe(opponentParts[4])).split('/'); const opponentControl = LZString.decompressFromBase64(
Utils.fromUrlSafe(opponentParts[4])
).split('/');
opponentSys = parseFloat(opponentControl[0]); opponentSys = parseFloat(opponentControl[0]);
opponentEng = parseFloat(opponentControl[1]); opponentEng = parseFloat(opponentControl[1]);
opponentWep = parseFloat(opponentControl[2]); opponentWep = parseFloat(opponentControl[2]);
@@ -316,7 +377,16 @@ export default class OutfittingPage extends Page {
opponentWep = 2; opponentWep = 2;
} }
this.setState({ opponent: opponentShip, opponentBuild, opponentSys, opponentEng, opponentWep }, () => this._updateRouteOnControlChange()); this.setState(
{
opponent: opponentShip,
opponentBuild,
opponentSys,
opponentEng,
opponentWep
},
() => this._updateRouteOnControlChange()
);
} }
/** /**
@@ -326,8 +396,22 @@ export default class OutfittingPage extends Page {
* @returns {string} The control code * @returns {string} The control code
*/ */
_controlCode(fuel, cargo) { _controlCode(fuel, cargo) {
const { sys, eng, wep, mcSys, mcEng, mcWep, boost, opponent, opponentBuild, engagementRange } = this.state; const {
const code = `${sys}/${eng}/${wep}/${boost ? 1 : 0}/${fuel || this.state.fuel}/${cargo || this.state.cargo}/${opponent.id}/${opponentBuild ? opponentBuild : ''}/${engagementRange}/${mcSys}/${mcEng}/${mcWep}`; 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; return code;
} }
@@ -338,27 +422,44 @@ export default class OutfittingPage extends Page {
const { ship, buildName, newBuildName, shipId } = this.state; 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 // 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.toString();
Persist.saveBuild(shipId, newBuildName, code); Persist.saveBuild(shipId, newBuildName, code);
this._updateRoute(shipId, newBuildName, code); this._updateRoute(shipId, newBuildName, code);
let opponent, opponentBuild, opponentSys, opponentEng, opponentWep; let opponent, opponentBuild, opponentSys, opponentEng, opponentWep;
if (shipId === this.state.opponent.id && buildName === this.state.opponentBuild) { if (
shipId === this.state.opponent.id &&
buildName === this.state.opponentBuild
) {
// This is a save of our current opponent build; update it // This is a save of our current opponent build; update it
opponentBuild = newBuildName; opponentBuild = newBuildName;
opponent = new Ship(shipId, Ships[shipId].properties, Ships[shipId].slots).buildFrom(code); opponent = new Ship(
shipId,
Ships[shipId].properties,
Ships[shipId].slots
).buildFrom(code);
opponentSys = this.state.sys; opponentSys = this.state.sys;
opponentEng = this.state.eng; opponentEng = this.state.eng;
opponentWep = this.state.wep; opponentWep = this.state.wep;
} else { } else {
opponentBuild = this.state.opponentBuild; opponentBuild = this.state.opponentBuild;
opponent = this.state.opponent; opponent = this.state.opponent;
opponentSys = this.state.opponentSys; opponentSys = this.state.opponentSys;
opponentEng = this.state.opponentEng; opponentEng = this.state.opponentEng;
opponentWep = this.state.opponentWep; opponentWep = this.state.opponentWep;
} }
this.setState({ buildName: newBuildName, code, savedCode: code, opponent, opponentBuild, opponentSys, opponentEng, opponentWep, title: this._getTitle(newBuildName) }); this.setState({
buildName: newBuildName,
code,
savedCode: code,
opponent,
opponentBuild,
opponentSys,
opponentEng,
opponentWep,
title: this._getTitle(newBuildName)
});
} }
/** /**
@@ -370,7 +471,12 @@ export default class OutfittingPage extends Page {
Persist.deleteBuild(shipId, buildName); Persist.deleteBuild(shipId, buildName);
Persist.saveBuild(shipId, newBuildName, code); Persist.saveBuild(shipId, newBuildName, code);
this._updateRoute(shipId, newBuildName, code); this._updateRoute(shipId, newBuildName, code);
this.setState({ buildName: newBuildName, code, savedCode: code, opponentBuild: newBuildName }); this.setState({
buildName: newBuildName,
code,
savedCode: code,
opponentBuild: newBuildName
});
} }
} }
@@ -390,9 +496,7 @@ export default class OutfittingPage extends Page {
ship.buildWith(Ships[shipId].defaults); ship.buildWith(Ships[shipId].defaults);
// Reset controls // Reset controls
const code = ship.toString(); const code = ship.toString();
const { sys, eng, wep, mcSys, mcEng, mcWep, boost, fuel, cargo, opponent, opponentBuild, engagementRange } = this._obtainControlFromCode(ship, code); const {
// Update state, and refresh the ship
this.setState({
sys, sys,
eng, eng,
wep, wep,
@@ -405,7 +509,25 @@ export default class OutfittingPage extends Page {
opponent, opponent,
opponentBuild, opponentBuild,
engagementRange engagementRange
}, () => this._updateRoute(shipId, buildName, code)); } = this._obtainControlFromCode(ship, code);
// 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)
);
} }
/** /**
@@ -416,7 +538,10 @@ export default class OutfittingPage extends Page {
Persist.deleteBuild(shipId, buildName); Persist.deleteBuild(shipId, buildName);
let opponentBuild; let opponentBuild;
if (shipId === this.state.opponent.id && buildName === this.state.opponentBuild) { if (
shipId === this.state.opponent.id &&
buildName === this.state.opponentBuild
) {
// Our current opponent has been deleted; revert to stock // Our current opponent has been deleted; revert to stock
opponentBuild = null; opponentBuild = null;
} else { } else {
@@ -433,11 +558,13 @@ export default class OutfittingPage extends Page {
_exportBuild() { _exportBuild() {
let translate = this.context.language.translate; let translate = this.context.language.translate;
let { buildName, ship } = this.state; let { buildName, ship } = this.state;
this.context.showModal(<ModalExport this.context.showModal(
title={(buildName || ship.name) + ' ' + translate('export')} <ModalExport
description={translate('PHRASE_EXPORT_DESC')} title={(buildName || ship.name) + ' ' + translate('export')}
data={toDetailedBuild(buildName, ship, ship.toString())} description={translate('PHRASE_EXPORT_DESC')}
/>); data={toDetailedBuild(buildName, ship, ship.toString())}
/>
);
} }
/** /**
@@ -450,9 +577,7 @@ export default class OutfittingPage extends Page {
this.state.ship.buildFrom(code); this.state.ship.buildFrom(code);
// Obtain controls from the code // Obtain controls from the code
const { sys, eng, wep, mcSys, mcEng, mcWep, boost, fuel, cargo, opponent, opponentBuild, engagementRange } = this._obtainControlFromCode(ship, code); const {
// Update state, and refresh the route when complete
this.setState({
sys, sys,
eng, eng,
wep, wep,
@@ -465,7 +590,25 @@ export default class OutfittingPage extends Page {
opponent, opponent,
opponentBuild, opponentBuild,
engagementRange engagementRange
}, () => this._updateRoute(shipId, buildName, code)); } = 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)
);
} }
/** /**
@@ -481,8 +624,14 @@ export default class OutfittingPage extends Page {
} }
const code = this._fullCode(ship, fuel, cargo); const code = this._fullCode(ship, fuel, cargo);
// Only update the state if this really has been updated // Only update the state if this really has been updated
if (this.state.code != code || this.state.cargo != cargo || this.state.fuel != fuel) { if (
this.setState({ code, cargo, fuel }, () => this._updateRoute(shipId, buildName, code)); this.state.code != code ||
this.state.cargo != cargo ||
this.state.fuel != fuel
) {
this.setState({ code, cargo, fuel }, () =>
this._updateRoute(shipId, buildName, code)
);
} }
} }
@@ -502,7 +651,8 @@ export default class OutfittingPage extends Page {
* @param {Object} nextContext Incoming/Next conext * @param {Object} nextContext Incoming/Next conext
*/ */
componentWillReceiveProps(nextProps, nextContext) { componentWillReceiveProps(nextProps, nextContext) {
if (this.context.route !== nextContext.route) { // Only reinit state if the route has changed if (this.context.route !== nextContext.route) {
// Only reinit state if the route has changed
this.setState(this._initState(nextProps, nextContext)); this.setState(this._initState(nextProps, nextContext));
} }
} }
@@ -525,7 +675,7 @@ export default class OutfittingPage extends Page {
* Generates the short URL * Generates the short URL
*/ */
_genShortlink() { _genShortlink() {
this.context.showModal(<ModalPermalink url={window.location.href}/>); this.context.showModal(<ModalPermalink url={window.location.href} />);
} }
/** /**
@@ -542,7 +692,7 @@ export default class OutfittingPage extends Page {
data.ShipName = ship.id; data.ShipName = ship.id;
data.Ship = ship.id; data.Ship = ship.id;
console.log(data); console.log(data);
this.context.showModal(<ModalOrbis ship={data}/>); this.context.showModal(<ModalOrbis ship={data} />);
} }
/** /**
@@ -553,17 +703,23 @@ export default class OutfittingPage extends Page {
const shipId = Ships[ship.id].eddbID; const shipId = Ships[ship.id].eddbID;
// Provide unique list of non-PP module EDDB IDs // Provide unique list of non-PP module EDDB IDs
const modIds = ship.internal.concat(ship.bulkheads, ship.standard, ship.hardpoints).filter(slot => slot !== null && slot.m !== null && !slot.m.pp).map(slot => slot.m.eddbID).filter((v, i, a) => a.indexOf(v) === i); const modIds = ship.internal
.concat(ship.bulkheads, ship.standard, ship.hardpoints)
.filter(slot => slot !== null && slot.m !== null && !slot.m.pp)
.map(slot => slot.m.eddbID)
.filter((v, i, a) => a.indexOf(v) === i);
// Open up the relevant URL // Open up the relevant URL
window.open('https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(',')); window.open(
'https://eddb.io/station?s=' + shipId + '&m=' + modIds.join(',')
);
} }
/** /**
* Generates the shopping list * Generates the shopping list
*/ */
_genShoppingList() { _genShoppingList() {
this.context.showModal(<ModalShoppingList ship={this.state.ship}/>); this.context.showModal(<ModalShoppingList ship={this.state.ship} />);
} }
/** /**
@@ -573,8 +729,9 @@ export default class OutfittingPage extends Page {
_keyDown(e) { _keyDown(e) {
// .keyCode will eventually be replaced with .key // .keyCode will eventually be replaced with .key
switch (e.keyCode) { switch (e.keyCode) {
case 69: // 'e' case 69: // 'e'
if (e.ctrlKey || e.metaKey) { // CTRL/CMD + e if (e.ctrlKey || e.metaKey) {
// CTRL/CMD + e
e.preventDefault(); e.preventDefault();
this._exportBuild(); this._exportBuild();
} }
@@ -590,7 +747,28 @@ export default class OutfittingPage extends Page {
let state = this.state, let state = this.state,
{ language, termtip, tooltip, sizeRatio, onWindowResize } = this.context, { language, termtip, tooltip, sizeRatio, onWindowResize } = this.context,
{ translate, units, formats } = language, { translate, units, formats } = language,
{ ship, code, savedCode, buildName, newBuildName, sys, eng, wep, mcSys, mcEng, mcWep, boost, fuel, cargo, opponent, opponentBuild, opponentSys, opponentEng, opponentWep, engagementRange } = state, {
ship,
code,
savedCode,
buildName,
newBuildName,
sys,
eng,
wep,
mcSys,
mcEng,
mcWep,
boost,
fuel,
cargo,
opponent,
opponentBuild,
opponentSys,
opponentEng,
opponentWep,
engagementRange
} = state,
hide = tooltip.bind(null, null), hide = tooltip.bind(null, null),
menu = this.props.currentMenu, menu = this.props.currentMenu,
shipUpdated = this._shipUpdated, shipUpdated = this._shipUpdated,
@@ -608,11 +786,15 @@ export default class OutfittingPage extends Page {
const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`; const _pStr = `${ship.getPowerEnabledString()}${ship.getPowerPrioritiesString()}`;
const _mStr = ship.getModificationsString(); const _mStr = ship.getModificationsString();
const standardSlotMarker = `${ship.name}${_sStr}${_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 internalSlotMarker = `${ship.name}${_iStr}${_pStr}${_mStr}`;
const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`; const hardpointsSlotMarker = `${ship.name}${_hStr}${_pStr}${_mStr}`;
const boostMarker = `${ship.canBoost(cargo, fuel)}`; const boostMarker = `${ship.canBoost(cargo, fuel)}`;
const shipSummaryMarker = `${ship.name}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`; const shipSummaryMarker = `${
ship.name
}${_sStr}${_iStr}${_hStr}${_pStr}${_mStr}${ship.ladenMass}${cargo}${fuel}`;
const requirements = Ships[ship.id].requirements; const requirements = Ships[ship.id].requirements;
let requirementElements = []; let requirementElements = [];
@@ -624,94 +806,275 @@ export default class OutfittingPage extends Page {
*/ */
function renderRequirement(className, textKey, tooltipTextKey) { function renderRequirement(className, textKey, tooltipTextKey) {
if (textKey.startsWith('empire') || textKey.startsWith('federation')) { if (textKey.startsWith('empire') || textKey.startsWith('federation')) {
requirementElements.push(<div key={textKey} className={className} onMouseEnter={termtip.bind(null, tooltipTextKey)} onMouseLeave={hide}><a href={textKey.startsWith('empire') ? 'http://elite-dangerous.wikia.com/wiki/Empire/Ranks' : 'http://elite-dangerous.wikia.com/wiki/Federation/Ranks'} target="_blank" rel="noopener">{translate(textKey)}</a></div>); requirementElements.push(
<div
key={textKey}
className={className}
onMouseEnter={termtip.bind(null, tooltipTextKey)}
onMouseLeave={hide}
>
<a
href={
textKey.startsWith('empire') ?
'http://elite-dangerous.wikia.com/wiki/Empire/Ranks' :
'http://elite-dangerous.wikia.com/wiki/Federation/Ranks'
}
target="_blank"
rel="noopener"
>
{translate(textKey)}
</a>
</div>
);
} else { } else {
requirementElements.push(<div key={textKey} className={className} onMouseEnter={termtip.bind(null, tooltipTextKey)} onMouseLeave={hide}>{translate(textKey)}</div>); requirementElements.push(
<div
key={textKey}
className={className}
onMouseEnter={termtip.bind(null, tooltipTextKey)}
onMouseLeave={hide}
>
{translate(textKey)}
</div>
);
} }
} }
if (requirements) { if (requirements) {
requirements.federationRank && renderRequirement('federation', 'federation rank ' + requirements.federationRank, 'federation rank required'); requirements.federationRank &&
requirements.empireRank && renderRequirement('empire', 'empire rank ' + requirements.empireRank, 'empire rank required'); renderRequirement(
requirements.horizons && renderRequirement('horizons', 'horizons', 'horizons required'); 'federation',
requirements.horizonsEarlyAdoption && renderRequirement('horizons', 'horizons early adoption', 'horizons early adoption required'); '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 ( return (
<div id='outfit' className={'page'} style={{ fontSize: (sizeRatio * 0.9) + 'em' }}> <div
<div id='overview'> id="outfit"
className={'page'}
style={{ fontSize: sizeRatio * 0.9 + 'em' }}
>
<div id="overview">
<h1>{ship.name}</h1> <h1>{ship.name}</h1>
<div id='requirements'>{requirementElements}</div> <div id="requirements">{requirementElements}</div>
<div id='build'> <div id="build">
<input value={newBuildName || ''} onChange={this._buildNameChange} placeholder={translate('Enter Name')} maxLength={50} /> <input
<button onClick={canSave && this._saveBuild} disabled={!canSave} onMouseOver={termtip.bind(null, 'save')} onMouseOut={hide}> value={newBuildName || ''}
<FloppyDisk className='lg' /> onChange={this._buildNameChange}
placeholder={translate('Enter Name')}
maxLength={50}
/>
<button
onClick={canSave && this._saveBuild}
disabled={!canSave}
onMouseOver={termtip.bind(null, 'save')}
onMouseOut={hide}
>
<FloppyDisk className="lg" />
</button> </button>
<button onClick={canRename && this._renameBuild} disabled={!canRename} onMouseOver={termtip.bind(null, 'rename')} onMouseOut={hide}> <button
<span style={{ textTransform: 'none', fontSize: '1.8em' }}>a|</span> onClick={canRename && this._renameBuild}
disabled={!canRename}
onMouseOver={termtip.bind(null, 'rename')}
onMouseOut={hide}
>
<span style={{ textTransform: 'none', fontSize: '1.8em' }}>
a|
</span>
</button> </button>
<button onClick={canReload && this._reloadBuild} disabled={!canReload} onMouseOver={termtip.bind(null, 'reload')} onMouseOut={hide}> <button
<Reload className='lg'/> onClick={canReload && this._reloadBuild}
disabled={!canReload}
onMouseOver={termtip.bind(null, 'reload')}
onMouseOut={hide}
>
<Reload className="lg" />
</button> </button>
<button className={'danger'} onClick={savedCode && this._deleteBuild} disabled={!savedCode} onMouseOver={termtip.bind(null, 'delete')} onMouseOut={hide}> <button
<Bin className='lg'/> className={'danger'}
onClick={savedCode && this._deleteBuild}
disabled={!savedCode}
onMouseOver={termtip.bind(null, 'delete')}
onMouseOut={hide}
>
<Bin className="lg" />
</button> </button>
<button onClick={code && this._resetBuild} disabled={!code} onMouseOver={termtip.bind(null, 'reset')} onMouseOut={hide}> <button
<Switch className='lg'/> onClick={code && this._resetBuild}
disabled={!code}
onMouseOver={termtip.bind(null, 'reset')}
onMouseOut={hide}
>
<Switch className="lg" />
</button> </button>
<button onClick={buildName && this._exportBuild} disabled={!buildName} onMouseOver={termtip.bind(null, 'export')} onMouseOut={hide}> <button
<Download className='lg'/> onClick={buildName && this._exportBuild}
disabled={!buildName}
onMouseOver={termtip.bind(null, 'export')}
onMouseOut={hide}
>
<Download className="lg" />
</button> </button>
<button onClick={this._eddbShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')} onMouseOut={hide}> <button
<ShoppingIcon className='lg' /> onClick={this._eddbShoppingList}
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_LIST')}
onMouseOut={hide}
>
<ShoppingIcon className="lg" />
</button> </button>
<button onClick={this._genShortlink} onMouseOver={termtip.bind(null, 'shortlink')} onMouseOut={hide}> <button
<LinkIcon className='lg' /> onClick={this._genShortlink}
onMouseOver={termtip.bind(null, 'shortlink')}
onMouseOut={hide}
>
<LinkIcon className="lg" />
</button> </button>
<button onClick={this._genOrbis} onMouseOver={termtip.bind(null, 'PHASE_UPLOAD_ORBIS')} onMouseOut={hide}> <button
<OrbisIcon className='lg' /> onClick={this._genOrbis}
onMouseOver={termtip.bind(null, 'PHASE_UPLOAD_ORBIS')}
onMouseOut={hide}
>
<OrbisIcon className="lg" />
</button> </button>
<button onClick={this._genShoppingList} onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_MATS')} onMouseOut={hide}> <button
<MatIcon className='lg' /> onClick={this._genShoppingList}
onMouseOver={termtip.bind(null, 'PHRASE_SHOPPING_MATS')}
onMouseOut={hide}
>
<MatIcon className="lg" />
</button> </button>
</div> </div>
</div> </div>
{/* Main tables */} {/* Main tables */}
<ShipSummaryTable ship={ship} fuel={fuel} cargo={cargo} marker={shipSummaryMarker} pips={{ sys: this.state.sys, wep: this.state.wep, eng: this.state.eng }} /> <ShipSummaryTable
<StandardSlotSection ship={ship} fuel={fuel} cargo={cargo} code={standardSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> ship={ship}
<InternalSlotSection ship={ship} code={internalSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> fuel={fuel}
<HardpointSlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> cargo={cargo}
<UtilitySlotSection ship={ship} code={hardpointsSlotMarker} onChange={shipUpdated} onCargoChange={this._cargoUpdated} onFuelChange={this._fuelUpdated} currentMenu={menu} sectionMenuRefs={this._sectionMenuRefs}/> marker={shipSummaryMarker}
pips={{
sys: this.state.sys,
wep: this.state.wep,
eng: this.state.eng
}}
/>
<StandardSlotSection
ship={ship}
fuel={fuel}
cargo={cargo}
code={standardSlotMarker}
onChange={shipUpdated}
onCargoChange={this._cargoUpdated}
onFuelChange={this._fuelUpdated}
currentMenu={menu}
sectionMenuRefs={this._sectionMenuRefs}
/>
<InternalSlotSection
ship={ship}
code={internalSlotMarker}
onChange={shipUpdated}
onCargoChange={this._cargoUpdated}
onFuelChange={this._fuelUpdated}
currentMenu={menu}
sectionMenuRefs={this._sectionMenuRefs}
/>
<HardpointSlotSection
ship={ship}
code={hardpointsSlotMarker}
onChange={shipUpdated}
onCargoChange={this._cargoUpdated}
onFuelChange={this._fuelUpdated}
currentMenu={menu}
sectionMenuRefs={this._sectionMenuRefs}
/>
<UtilitySlotSection
ship={ship}
code={hardpointsSlotMarker}
onChange={shipUpdated}
onCargoChange={this._cargoUpdated}
onFuelChange={this._fuelUpdated}
currentMenu={menu}
sectionMenuRefs={this._sectionMenuRefs}
/>
{/* Control of ship and opponent */} {/* Control of ship and opponent */}
<div className='group quarter'> <div className="group quarter">
<div className='group half'> <div className="group half">
<h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>{translate('ship control')}</h2> <h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>
{translate('ship control')}
</h2>
</div> </div>
<div className='group half'> <div className="group half">
<Boost marker={boostMarker} ship={ship} boost={boost} onChange={this._boostUpdated} /> <Boost
marker={boostMarker}
ship={ship}
boost={boost}
onChange={this._boostUpdated}
/>
</div> </div>
</div> </div>
<div className='group quarter'> <div className="group quarter">
<Pips sys={sys} eng={eng} wep={wep} mcSys={mcSys} mcEng={mcEng} mcWep={mcWep} onChange={this._pipsUpdated} /> <Pips
sys={sys}
eng={eng}
wep={wep}
mcSys={mcSys}
mcEng={mcEng}
mcWep={mcWep}
onChange={this._pipsUpdated}
/>
</div> </div>
<div className='group quarter'> <div className="group quarter">
<Fuel fuelCapacity={ship.fuelCapacity} fuel={fuel} onChange={this._fuelUpdated}/> <Fuel
fuelCapacity={ship.fuelCapacity}
fuel={fuel}
onChange={this._fuelUpdated}
/>
</div> </div>
<div className='group quarter'> <div className="group quarter">
{ ship.cargoCapacity > 0 ? <Cargo cargoCapacity={ship.cargoCapacity} cargo={cargo} onChange={this._cargoUpdated}/> : null } {ship.cargoCapacity > 0 ? (
<Cargo
cargoCapacity={ship.cargoCapacity}
cargo={cargo}
onChange={this._cargoUpdated}
/>
) : null}
</div> </div>
<div className='group half'> <div className="group half">
<div className='group quarter'> <div className="group quarter">
<h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>{translate('opponent')}</h2> <h2 style={{ verticalAlign: 'middle', textAlign: 'left' }}>
{translate('opponent')}
</h2>
</div> </div>
<div className='group threequarters'> <div className="group threequarters">
<ShipPicker ship={opponent.id} build={opponentBuild} onChange={this._opponentUpdated}/> <ShipPicker
ship={opponent.id}
build={opponentBuild}
onChange={this._opponentUpdated}
/>
</div> </div>
</div> </div>
<div className='group half'> <div className="group half">
<EngagementRange ship={ship} engagementRange={engagementRange} onChange={this._engagementRangeUpdated}/> <EngagementRange
ship={ship}
engagementRange={engagementRange}
onChange={this._engagementRangeUpdated}
/>
</div> </div>
{/* Tabbed subpages */} {/* Tabbed subpages */}
@@ -733,6 +1096,15 @@ export default class OutfittingPage extends Page {
opponentEng={opponentEng} opponentEng={opponentEng}
opponentWep={opponentWep} opponentWep={opponentWep}
/> />
<Ad
client="ca-pub-3709458261881414"
slot="4156867783"
format="auto"
wrapperDivStyle={{
marginTop: '15px',
marginBottom: '20px'
}}
/>
</div> </div>
); );
} }

View File

@@ -6,6 +6,7 @@ import Ship from '../shipyard/Ship';
import * as ModuleUtils from '../shipyard/ModuleUtils'; import * as ModuleUtils from '../shipyard/ModuleUtils';
import { SizeMap } from '../shipyard/Constants'; import { SizeMap } from '../shipyard/Constants';
import Link from '../components/Link'; import Link from '../components/Link';
import Ad from '../components/Ad';
/** /**
* Counts the hardpoints by class/size * Counts the hardpoints by class/size
@@ -22,9 +23,11 @@ function countHp(slot) {
*/ */
function countInt(slot) { function countInt(slot) {
let crEligible = !slot.eligible || slot.eligible.cr; let crEligible = !slot.eligible || slot.eligible.cr;
this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment this.int[slot.maxClass - 1]++; // Subtract 1 since there is no Class 0 Internal compartment
this.intCount++; this.intCount++;
this.maxCargo += crEligible ? ModuleUtils.findInternal('cr', slot.maxClass, 'E').cargo : 0; this.maxCargo += crEligible ?
ModuleUtils.findInternal('cr', slot.maxClass, 'E').cargo :
0;
// if no eligiblity, then assume pce // if no eligiblity, then assume pce
let passSlotType = null; let passSlotType = null;
@@ -42,7 +45,9 @@ function countInt(slot) {
passSlotType = 'pcq'; passSlotType = 'pcq';
passSlotRating = 'B'; passSlotRating = 'B';
} }
let passengerBay = passSlotType ? ModuleUtils.findMaxInternal(passSlotType, slot.maxClass, passSlotRating) : null; let passengerBay = passSlotType ?
ModuleUtils.findMaxInternal(passSlotType, slot.maxClass, passSlotRating) :
null;
this.maxPassengers += passengerBay ? passengerBay.passengers : 0; this.maxPassengers += passengerBay ? passengerBay.passengers : 0;
} }
@@ -62,18 +67,21 @@ function shipSummary(shipId, shipData) {
hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge hp: [0, 0, 0, 0, 0], // Utility, Small, Medium, Large, Huge
int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8 int: [0, 0, 0, 0, 0, 0, 0, 0], // Sizes 1 - 8
standard: shipData.slots.standard, standard: shipData.slots.standard,
agility: shipData.properties.pitch + shipData.properties.yaw + shipData.properties.roll agility:
shipData.properties.pitch +
shipData.properties.yaw +
shipData.properties.roll
}; };
Object.assign(summary, shipData.properties); Object.assign(summary, shipData.properties);
let ship = new Ship(shipId, shipData.properties, shipData.slots); let ship = new Ship(shipId, shipData.properties, shipData.slots);
// Build Ship // Build Ship
ship.buildWith(shipData.defaults); // Populate with stock/default components ship.buildWith(shipData.defaults); // Populate with stock/default components
ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class ship.hardpoints.forEach(countHp.bind(summary)); // Count Hardpoints by class
ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class ship.internal.forEach(countInt.bind(summary)); // Count Internal Compartments by class
summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost summary.retailCost = ship.totalCost; // Record Stock/Default/retail cost
ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range ship.optimizeMass({ pd: '1D' }); // Optimize Mass with 1D PD for maximum possible jump range
summary.maxJumpRange = ship.unladenRange; // Record Jump Range summary.maxJumpRange = ship.unladenRange; // Record Jump Range
// Best thrusters // Best thrusters
let th; let th;
@@ -97,7 +105,6 @@ function shipSummary(shipId, shipData) {
* The Shipyard summary page * The Shipyard summary page
*/ */
export default class ShipyardPage extends Page { export default class ShipyardPage extends Page {
static cachedShipSummaries = null; static cachedShipSummaries = null;
/** /**
@@ -145,12 +152,15 @@ export default class ShipyardPage extends Page {
shipPredicateIndex = undefined; shipPredicateIndex = undefined;
} }
if (this.state.shipPredicate == shipPredicate && this.state.shipPredicateIndex == shipPredicateIndex) { if (
this.state.shipPredicate == shipPredicate &&
this.state.shipPredicateIndex == shipPredicateIndex
) {
shipDesc = !shipDesc; shipDesc = !shipDesc;
} }
this.setState({ shipPredicate, shipDesc, shipPredicateIndex }); this.setState({ shipPredicate, shipDesc, shipPredicateIndex });
}; }
/** /**
* Generate the table row summary for the ship * Generate the table row summary for the ship
@@ -165,50 +175,55 @@ export default class ShipyardPage extends Page {
_shipRowElement(s, translate, u, fInt, fRound, highlight) { _shipRowElement(s, translate, u, fInt, fRound, highlight) {
let noTouch = this.context.noTouch; let noTouch = this.context.noTouch;
return <tr return (
<tr
key={s.id} key={s.id}
style={{ height: '1.5em' }} style={{ height: '1.5em' }}
className={cn({ highlighted: noTouch && this.state.shipId === s.id, alt: highlight })} className={cn({
highlighted: noTouch && this.state.shipId === s.id,
alt: highlight
})}
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)} onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
> >
<td className='ri'>{s.manufacturer}</td> <td className="ri">{s.manufacturer}</td>
<td className='ri'>{fInt(s.retailCost)}</td> <td className="ri">{fInt(s.retailCost)}</td>
<td className='ri cap'>{translate(SizeMap[s.class])}</td> <td className="ri cap">{translate(SizeMap[s.class])}</td>
<td className='ri'>{fInt(s.crew)}</td> <td className="ri">{fInt(s.crew)}</td>
<td className='ri'>{s.masslock}</td> <td className="ri">{s.masslock}</td>
<td className='ri'>{fInt(s.agility)}</td> <td className="ri">{fInt(s.agility)}</td>
<td className='ri'>{fInt(s.hardness)}</td> <td className="ri">{fInt(s.hardness)}</td>
<td className='ri'>{fInt(s.hullMass)}</td> <td className="ri">{fInt(s.hullMass)}</td>
<td className='ri'>{fInt(s.speed)}</td> <td className="ri">{fInt(s.speed)}</td>
<td className='ri'>{fInt(s.boost)}</td> <td className="ri">{fInt(s.boost)}</td>
<td className='ri'>{fInt(s.baseArmour)}</td> <td className="ri">{fInt(s.baseArmour)}</td>
<td className='ri'>{fInt(s.baseShieldStrength)}</td> <td className="ri">{fInt(s.baseShieldStrength)}</td>
<td className='ri'>{fInt(s.topSpeed)}</td> <td className="ri">{fInt(s.topSpeed)}</td>
<td className='ri'>{fInt(s.topBoost)}</td> <td className="ri">{fInt(s.topBoost)}</td>
<td className='ri'>{fRound(s.maxJumpRange)}</td> <td className="ri">{fRound(s.maxJumpRange)}</td>
<td className='ri'>{fInt(s.maxCargo)}</td> <td className="ri">{fInt(s.maxCargo)}</td>
<td className='ri'>{fInt(s.maxPassengers)}</td> <td className="ri">{fInt(s.maxPassengers)}</td>
<td className='cn'>{s.standard[0]}</td> <td className="cn">{s.standard[0]}</td>
<td className='cn'>{s.standard[1]}</td> <td className="cn">{s.standard[1]}</td>
<td className='cn'>{s.standard[2]}</td> <td className="cn">{s.standard[2]}</td>
<td className='cn'>{s.standard[3]}</td> <td className="cn">{s.standard[3]}</td>
<td className='cn'>{s.standard[4]}</td> <td className="cn">{s.standard[4]}</td>
<td className='cn'>{s.standard[5]}</td> <td className="cn">{s.standard[5]}</td>
<td className='cn'>{s.standard[6]}</td> <td className="cn">{s.standard[6]}</td>
<td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td> <td className={cn({ disabled: !s.hp[1] })}>{s.hp[1]}</td>
<td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td> <td className={cn({ disabled: !s.hp[2] })}>{s.hp[2]}</td>
<td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td> <td className={cn({ disabled: !s.hp[3] })}>{s.hp[3]}</td>
<td className={cn({ disabled: !s.hp[4] })}>{s.hp[4]}</td> <td className={cn({ disabled: !s.hp[4] })}>{s.hp[4]}</td>
<td className={cn({ disabled: !s.hp[0] })}>{s.hp[0]}</td> <td className={cn({ disabled: !s.hp[0] })}>{s.hp[0]}</td>
<td className={cn({ disabled: !s.int[0] })}>{s.int[0]}</td> <td className={cn({ disabled: !s.int[0] })}>{s.int[0]}</td>
<td className={cn({ disabled: !s.int[1] })}>{s.int[1]}</td> <td className={cn({ disabled: !s.int[1] })}>{s.int[1]}</td>
<td className={cn({ disabled: !s.int[2] })}>{s.int[2]}</td> <td className={cn({ disabled: !s.int[2] })}>{s.int[2]}</td>
<td className={cn({ disabled: !s.int[3] })}>{s.int[3]}</td> <td className={cn({ disabled: !s.int[3] })}>{s.int[3]}</td>
<td className={cn({ disabled: !s.int[4] })}>{s.int[4]}</td> <td className={cn({ disabled: !s.int[4] })}>{s.int[4]}</td>
<td className={cn({ disabled: !s.int[5] })}>{s.int[5]}</td> <td className={cn({ disabled: !s.int[5] })}>{s.int[5]}</td>
<td className={cn({ disabled: !s.int[6] })}>{s.int[6]}</td> <td className={cn({ disabled: !s.int[6] })}>{s.int[6]}</td>
<td className={cn({ disabled: !s.int[7] })}>{s.int[7]}</td> <td className={cn({ disabled: !s.int[7] })}>{s.int[7]}</td>
</tr>; </tr>
);
} }
/** /**
@@ -222,7 +237,8 @@ export default class ShipyardPage extends Page {
let fInt = formats.int; let fInt = formats.int;
let fRound = formats.round; let fRound = formats.round;
let { shipSummaries, shipPredicate, shipPredicateIndex } = this.state; let { shipSummaries, shipPredicate, shipPredicateIndex } = this.state;
let sortShips = (predicate, index) => this._sortShips.bind(this, predicate, index); let sortShips = (predicate, index) =>
this._sortShips.bind(this, predicate, index);
let filters = { let filters = {
// 'class': { 1: 1, 2: 1} // 'class': { 1: 1, 2: 1}
@@ -239,7 +255,8 @@ export default class ShipyardPage extends Page {
// Sort shipsOverview // Sort shipsOverview
shipSummaries.sort((a, b) => { shipSummaries.sort((a, b) => {
let valA = a[shipPredicate], valB = b[shipPredicate]; let valA = a[shipPredicate],
valB = b[shipPredicate];
if (shipPredicateIndex != undefined) { if (shipPredicateIndex != undefined) {
valA = valA[shipPredicateIndex]; valA = valA[shipPredicateIndex];
@@ -252,7 +269,7 @@ export default class ShipyardPage extends Page {
valB = val; valB = val;
} }
if(valA == valB) { if (valA == valB) {
if (a.name > b.name) { if (a.name > b.name) {
return 1; return 1;
} else { } else {
@@ -274,42 +291,65 @@ export default class ShipyardPage extends Page {
for (let s of shipSummaries) { for (let s of shipSummaries) {
let shipSortValue = s[shipPredicate]; let shipSortValue = s[shipPredicate];
if(shipPredicateIndex != undefined) { if (shipPredicateIndex != undefined) {
shipSortValue = shipSortValue[shipPredicateIndex]; shipSortValue = shipSortValue[shipPredicateIndex];
} }
if(shipSortValue != lastShipSortValue) { if (shipSortValue != lastShipSortValue) {
backgroundHighlight = !backgroundHighlight; backgroundHighlight = !backgroundHighlight;
lastShipSortValue = shipSortValue; lastShipSortValue = shipSortValue;
} }
detailRows[i] = this._shipRowElement(s, translate, units, fInt, formats.f1, backgroundHighlight); detailRows[i] = this._shipRowElement(
s,
translate,
units,
fInt,
formats.f1,
backgroundHighlight
);
shipRows[i] = ( shipRows[i] = (
<tr <tr
key={i} key={i}
style={{ height: '1.5em' }} style={{ height: '1.5em' }}
className={cn({ highlighted: noTouch && this.state.shipId === s.id, alt: backgroundHighlight })} className={cn({
highlighted: noTouch && this.state.shipId === s.id,
alt: backgroundHighlight
})}
onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)} onMouseEnter={noTouch && this._highlightShip.bind(this, s.id)}
> >
<td className='le'><Link href={'/outfit/' + s.id}>{s.name}</Link></td> <td className="le">
<Link href={'/outfit/' + s.id}>{s.name}</Link>
</td>
</tr> </tr>
); );
i++; i++;
} }
return ( return (
<div className='page' style={{ fontSize: sizeRatio + 'em' }}> <div className="page" style={{ fontSize: sizeRatio + 'em' }}>
<div style={{ whiteSpace: 'nowrap', margin: '0 auto', fontSize: '0.8em', position: 'relative', display: 'inline-block', maxWidth: '100%' }}> <div
style={{
whiteSpace: 'nowrap',
margin: '0 auto',
fontSize: '0.8em',
position: 'relative',
display: 'inline-block',
maxWidth: '100%'
}}
>
<table style={{ width: '12em', position: 'absolute', zIndex: 1 }}> <table style={{ width: '12em', position: 'absolute', zIndex: 1 }}>
<thead> <thead>
<tr> <tr>
<th className='le rgt'>&nbsp;</th> <th className="le rgt">&nbsp;</th>
</tr> </tr>
<tr className='main'> <tr className="main">
<th className='sortable le rgt' onClick={sortShips('name')}>{translate('ship')}</th> <th className="sortable le rgt" onClick={sortShips('name')}>
{translate('ship')}
</th>
</tr> </tr>
<tr> <tr>
<th className='le rgt invisible'>{units['m/s']}</th> <th className="le rgt invisible">{units['m/s']}</th>
</tr> </tr>
</thead> </thead>
<tbody onMouseLeave={this._highlightShip.bind(this, null)}> <tbody onMouseLeave={this._highlightShip.bind(this, null)}>
@@ -317,80 +357,270 @@ export default class ShipyardPage extends Page {
</tbody> </tbody>
</table> </table>
<div style={{ overflowX: 'scroll', maxWidth: '100%' }}> <div style={{ overflowX: 'scroll', maxWidth: '100%' }}>
<table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }}> <table style={{ marginLeft: 'calc(12em - 1px)', zIndex: 0 }}>
<thead> <thead>
<tr className='main'> <tr className="main">
<th rowSpan={3} className='sortable' onClick={sortShips('manufacturer')}>{translate('manufacturer')}</th> <th
<th>&nbsp;</th> rowSpan={3}
<th rowSpan={3} className='sortable' onClick={sortShips('class')}>{translate('size')}</th> className="sortable"
<th rowSpan={3} className='sortable' onClick={sortShips('crew')}>{translate('crew')}</th> onClick={sortShips('manufacturer')}
<th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'mass lock factor')} onMouseLeave={hide} onClick={sortShips('masslock')} >{translate('MLF')}</th> >
<th rowSpan={3} className='sortable' onClick={sortShips('agility')}>{translate('agility')}</th> {translate('manufacturer')}
<th rowSpan={3} className='sortable' onMouseEnter={termtip.bind(null, 'hardness')} onMouseLeave={hide} onClick={sortShips('hardness')}>{translate('hrd')}</th> </th>
<th>&nbsp;</th> <th>&nbsp;</th>
<th colSpan={4}>{translate('base')}</th> <th
<th colSpan={5}>{translate('max')}</th> rowSpan={3}
<th className='lft' colSpan={7}></th> className="sortable"
<th className='lft' colSpan={5}></th> onClick={sortShips('class')}
<th className='lft' colSpan={8}></th> >
</tr> {translate('size')}
<tr> </th>
<th className='sortable lft' onClick={sortShips('retailCost')}>{translate('cost')}</th> <th
<th className='sortable lft' onClick={sortShips('hullMass')}>{translate('hull')}</th> rowSpan={3}
<th className='sortable lft' onClick={sortShips('speed')}>{translate('speed')}</th> className="sortable"
<th className='sortable' onClick={sortShips('boost')}>{translate('boost')}</th> onClick={sortShips('crew')}
<th className='sortable' onClick={sortShips('baseArmour')}>{translate('armour')}</th> >
<th className='sortable' onClick={sortShips('baseShieldStrength')}>{translate('shields')}</th> {translate('crew')}
</th>
<th
rowSpan={3}
className="sortable"
onMouseEnter={termtip.bind(null, 'mass lock factor')}
onMouseLeave={hide}
onClick={sortShips('masslock')}
>
{translate('MLF')}
</th>
<th
rowSpan={3}
className="sortable"
onClick={sortShips('agility')}
>
{translate('agility')}
</th>
<th
rowSpan={3}
className="sortable"
onMouseEnter={termtip.bind(null, 'hardness')}
onMouseLeave={hide}
onClick={sortShips('hardness')}
>
{translate('hrd')}
</th>
<th>&nbsp;</th>
<th colSpan={4}>{translate('base')}</th>
<th colSpan={5}>{translate('max')}</th>
<th className="lft" colSpan={7} />
<th className="lft" colSpan={5} />
<th className="lft" colSpan={8} />
</tr>
<tr>
<th
className="sortable lft"
onClick={sortShips('retailCost')}
>
{translate('cost')}
</th>
<th className="sortable lft" onClick={sortShips('hullMass')}>
{translate('hull')}
</th>
<th className="sortable lft" onClick={sortShips('speed')}>
{translate('speed')}
</th>
<th className="sortable" onClick={sortShips('boost')}>
{translate('boost')}
</th>
<th className="sortable" onClick={sortShips('baseArmour')}>
{translate('armour')}
</th>
<th
className="sortable"
onClick={sortShips('baseShieldStrength')}
>
{translate('shields')}
</th>
<th className='sortable lft' onClick={sortShips('topSpeed')}>{translate('speed')}</th> <th className="sortable lft" onClick={sortShips('topSpeed')}>
<th className='sortable' onClick={sortShips('topBoost')}>{translate('boost')}</th> {translate('speed')}
<th className='sortable' onClick={sortShips('maxJumpRange')}>{translate('jump')}</th> </th>
<th className='sortable' onClick={sortShips('maxCargo')}>{translate('cargo')}</th> <th className="sortable" onClick={sortShips('topBoost')}>
<th className='sortable' onClick={sortShips('maxPassengers')}>{translate('pax')}</th> {translate('boost')}
</th>
<th className="sortable" onClick={sortShips('maxJumpRange')}>
{translate('jump')}
</th>
<th className="sortable" onClick={sortShips('maxCargo')}>
{translate('cargo')}
</th>
<th className="sortable" onClick={sortShips('maxPassengers')}>
{translate('pax')}
</th>
<th className='lft' colSpan={7}>{translate('core module classes')}</th> <th className="lft" colSpan={7}>
<th colSpan={5} className='sortable lft' onClick={sortShips('hpCount')}>{translate('hardpoints')}</th> {translate('core module classes')}
<th colSpan={8} className='sortable lft' onClick={sortShips('intCount')}>{translate('internal compartments')}</th> </th>
</tr> <th
<tr> colSpan={5}
<th className='sortable lft' onClick={sortShips('retailCost')}>{units.CR}</th> className="sortable lft"
<th className='sortable lft' onClick={sortShips('hullMass')}>{units.T}</th> onClick={sortShips('hpCount')}
<th className='sortable lft' onClick={sortShips('speed')}>{units['m/s']}</th> >
<th className='sortable' onClick={sortShips('boost')}>{units['m/s']}</th> {translate('hardpoints')}
<th>&nbsp;</th> </th>
<th className='sortable' onClick={sortShips('baseShieldStrength')}>{units.MJ}</th> <th
<th className='sortable lft' onClick={sortShips('topSpeed')}>{units['m/s']}</th> colSpan={8}
<th className='sortable' onClick={sortShips('topBoost')}>{units['m/s']}</th> className="sortable lft"
<th className='sortable' onClick={sortShips('maxJumpRange')}>{units.LY}</th> onClick={sortShips('intCount')}
<th className='sortable' onClick={sortShips('maxCargo')}>{units.T}</th> >
<th>&nbsp;</th> {translate('internal compartments')}
<th className='sortable lft' onMouseEnter={termtip.bind(null, 'power plant')} onMouseLeave={hide} onClick={sortShips('standard', 0)}>{'pp'}</th> </th>
<th className='sortable' onMouseEnter={termtip.bind(null, 'thrusters')} onMouseLeave={hide} onClick={sortShips('standard', 1)}>{'th'}</th> </tr>
<th className='sortable' onMouseEnter={termtip.bind(null, 'frame shift drive')} onMouseLeave={hide} onClick={sortShips('standard', 2)}>{'fsd'}</th> <tr>
<th className='sortable' onMouseEnter={termtip.bind(null, 'life support')} onMouseLeave={hide} onClick={sortShips('standard', 3)}>{'ls'}</th> <th
<th className='sortable' onMouseEnter={termtip.bind(null, 'power distriubtor')} onMouseLeave={hide} onClick={sortShips('standard', 4)}>{'pd'}</th> className="sortable lft"
<th className='sortable' onMouseEnter={termtip.bind(null, 'sensors')} onMouseLeave={hide} onClick={sortShips('standard', 5)}>{'s'}</th> onClick={sortShips('retailCost')}
<th className='sortable' onMouseEnter={termtip.bind(null, 'fuel tank')} onMouseLeave={hide} onClick={sortShips('standard', 6)}>{'ft'}</th> >
<th className='sortable lft' onClick={sortShips('hp',1)}>{translate('S')}</th> {units.CR}
<th className='sortable' onClick={sortShips('hp', 2)}>{translate('M')}</th> </th>
<th className='sortable' onClick={sortShips('hp', 3)}>{translate('L')}</th> <th className="sortable lft" onClick={sortShips('hullMass')}>
<th className='sortable' onClick={sortShips('hp', 4)}>{translate('H')}</th> {units.T}
<th className='sortable' onClick={sortShips('hp', 0)}>{translate('U')}</th> </th>
<th className="sortable lft" onClick={sortShips('speed')}>
{units['m/s']}
</th>
<th className="sortable" onClick={sortShips('boost')}>
{units['m/s']}
</th>
<th>&nbsp;</th>
<th
className="sortable"
onClick={sortShips('baseShieldStrength')}
>
{units.MJ}
</th>
<th className="sortable lft" onClick={sortShips('topSpeed')}>
{units['m/s']}
</th>
<th className="sortable" onClick={sortShips('topBoost')}>
{units['m/s']}
</th>
<th className="sortable" onClick={sortShips('maxJumpRange')}>
{units.LY}
</th>
<th className="sortable" onClick={sortShips('maxCargo')}>
{units.T}
</th>
<th>&nbsp;</th>
<th
className="sortable lft"
onMouseEnter={termtip.bind(null, 'power plant')}
onMouseLeave={hide}
onClick={sortShips('standard', 0)}
>
{'pp'}
</th>
<th
className="sortable"
onMouseEnter={termtip.bind(null, 'thrusters')}
onMouseLeave={hide}
onClick={sortShips('standard', 1)}
>
{'th'}
</th>
<th
className="sortable"
onMouseEnter={termtip.bind(null, 'frame shift drive')}
onMouseLeave={hide}
onClick={sortShips('standard', 2)}
>
{'fsd'}
</th>
<th
className="sortable"
onMouseEnter={termtip.bind(null, 'life support')}
onMouseLeave={hide}
onClick={sortShips('standard', 3)}
>
{'ls'}
</th>
<th
className="sortable"
onMouseEnter={termtip.bind(null, 'power distriubtor')}
onMouseLeave={hide}
onClick={sortShips('standard', 4)}
>
{'pd'}
</th>
<th
className="sortable"
onMouseEnter={termtip.bind(null, 'sensors')}
onMouseLeave={hide}
onClick={sortShips('standard', 5)}
>
{'s'}
</th>
<th
className="sortable"
onMouseEnter={termtip.bind(null, 'fuel tank')}
onMouseLeave={hide}
onClick={sortShips('standard', 6)}
>
{'ft'}
</th>
<th className="sortable lft" onClick={sortShips('hp', 1)}>
{translate('S')}
</th>
<th className="sortable" onClick={sortShips('hp', 2)}>
{translate('M')}
</th>
<th className="sortable" onClick={sortShips('hp', 3)}>
{translate('L')}
</th>
<th className="sortable" onClick={sortShips('hp', 4)}>
{translate('H')}
</th>
<th className="sortable" onClick={sortShips('hp', 0)}>
{translate('U')}
</th>
<th className='sortable lft' onClick={sortShips('int', 0)} >1</th> <th className="sortable lft" onClick={sortShips('int', 0)}>
<th className='sortable' onClick={sortShips('int', 1)} >2</th> 1
<th className='sortable' onClick={sortShips('int', 2)} >3</th> </th>
<th className='sortable' onClick={sortShips('int', 3)} >4</th> <th className="sortable" onClick={sortShips('int', 1)}>
<th className='sortable' onClick={sortShips('int', 4)} >5</th> 2
<th className='sortable' onClick={sortShips('int', 5)} >6</th> </th>
<th className='sortable' onClick={sortShips('int', 6)} >7</th> <th className="sortable" onClick={sortShips('int', 2)}>
<th className='sortable' onClick={sortShips('int', 7)} >8</th> 3
</tr> </th>
</thead> <th className="sortable" onClick={sortShips('int', 3)}>
<tbody onMouseLeave={this._highlightShip.bind(this, null)}> 4
{detailRows} </th>
</tbody> <th className="sortable" onClick={sortShips('int', 4)}>
</table> 5
</th>
<th className="sortable" onClick={sortShips('int', 5)}>
6
</th>
<th className="sortable" onClick={sortShips('int', 6)}>
7
</th>
<th className="sortable" onClick={sortShips('int', 7)}>
8
</th>
</tr>
</thead>
<tbody onMouseLeave={this._highlightShip.bind(this, null)}>
{detailRows}
</tbody>
</table>
<Ad
client="ca-pub-3709458261881414"
slot="4156867783"
format="auto"
wrapperDivStyle={{
marginTop: '15px',
marginBottom: '20px'
}}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html manifest="/"> <html>
<head> <head>
<title>Coriolis EDCD Edition</title> <title>Coriolis EDCD Edition</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
@@ -31,10 +31,7 @@
</script> </script>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script> <script>
(adsbygoogle = window.adsbygoogle || []).push({ (adsbygoogle = window.adsbygoogle || []).push({});
google_ad_client: "ca-pub-3709458261881414",
enable_page_level_ads: true
});
</script> </script>
<% if (htmlWebpackPlugin.options.uaTracking) { %> <% if (htmlWebpackPlugin.options.uaTracking) { %>
<script> <script>