Compare commits

...

47 Commits

Author SHA1 Message Date
Cmdr McDonald
39e9a38068 Merge branch 'release/2.2.14' 2017-02-08 09:29:04 +00:00
Cmdr McDonald
73d5915b3a Package bump 2017-02-08 09:27:27 +00:00
Cmdr McDonald
b06d2d1f72 Merge branch 'feature/mods' into develop 2017-02-08 09:26:09 +00:00
Cmdr McDonald
6e71f5e6db Use ship name rather than model if possible 2017-02-08 09:24:13 +00:00
Cmdr McDonald
191e31ff18 Use new-style blueprint data; fix numeric special effect calculations 2017-02-05 15:38:04 +00:00
Cmdr McDonald
c655b65779 Ensure TTD is recalculated when EPS is recalculated 2017-02-02 23:40:24 +00:00
Cmdr McDonald
3e168a3e5f Merge branch 'release/2.2.13' into develop 2017-02-02 23:05:50 +00:00
Cmdr McDonald
ee52a4b716 Merge branch 'release/2.2.13' 2017-02-02 23:05:46 +00:00
Cmdr McDonald
a14974fef4 Bump package 2017-02-02 23:03:35 +00:00
Cmdr McDonald
2c0959d68b Merge branch 'feature/fixed' into develop 2017-02-02 23:01:08 +00:00
Cmdr McDonald
0221d05b04 Tweak recalculation of mass 2017-02-01 08:57:56 +00:00
Cmdr McDonald
975432b45a Lint 2017-02-01 08:33:16 +00:00
Cmdr McDonald
e78551f5d9 Ensure that ship mass is recalculated when appropriate - #67 2017-02-01 08:24:50 +00:00
Cmdr McDonald
b1daf6f799 Fix issue with auto loader not showing - #66 2017-02-01 07:45:44 +00:00
Cmdr McDonald
df03102c35 Added time to drain calculation and display 2017-01-30 21:31:55 +00:00
Cmdr McDonald
e7d1a0df63 Merge branch 'release/2.2.12' into develop 2017-01-29 08:27:28 +00:00
Cmdr McDonald
ca0c9675b3 Merge branch 'release/2.2.12' 2017-01-29 08:27:24 +00:00
Cmdr McDonald
491899fe49 Package bump 2017-01-29 08:27:17 +00:00
Cmdr McDonald
cc22a89ad6 Merge branch 'feature/specials' into develop 2017-01-29 08:26:34 +00:00
Cmdr McDonald
d389114189 Remove extraneous functions 2017-01-28 20:40:58 +00:00
Cmdr McDonald
9d0f7a166b Don't show both power generation and power draw in diffDetails 2017-01-27 22:23:36 +00:00
Cmdr McDonald
c344d56d48 Merge branch 'feature/specials' of https://github.com/EDCD/coriolis into feature/specials 2017-01-27 21:34:33 +00:00
Cmdr McDonald
eb5d0e868c Remove logging 2017-01-27 21:34:27 +00:00
Cmdr McDonald
c28f22a78b Add units for time 2017-01-27 21:34:27 +00:00
Cmdr McDonald
e2b22dd4ca Alter shortlink hotkey - for #58 2017-01-27 21:32:07 +00:00
Cmdr McDonald
f5ecccec48 Add weapon mods to damage dealt 2017-01-27 21:32:07 +00:00
Cmdr McDonald
7c8eee4707 Add package info 2017-01-27 21:32:07 +00:00
Cmdr McDonald
99e251fd4b Fix missing break in case 2017-01-27 21:32:07 +00:00
Cmdr McDonald
c1ddecfd3e Add specials 2017-01-27 21:32:07 +00:00
Cmdr McDonald
0ae59c5e48 Remove old reference to coriolis.io 2017-01-27 21:32:07 +00:00
Cmdr McDonald
eb76040b08 Remove logging 2017-01-27 21:31:05 +00:00
Cmdr McDonald
7698cb75e9 Add units for time 2017-01-27 21:30:15 +00:00
Cmdr McDonald
bd7139c703 Merge branch 'feature/specials' of https://github.com/EDCD/coriolis into feature/specials 2017-01-27 09:54:26 +00:00
Cmdr McDonald
c9b9404ba1 Alter shortlink hotkey - for #58 2017-01-27 09:54:17 +00:00
Cmdr McDonald
84ff013a9e Add weapon mods to damage dealt 2017-01-27 09:54:17 +00:00
Cmdr McDonald
d2bcf6cd71 Add package info 2017-01-27 09:54:17 +00:00
Cmdr McDonald
e52c6730f4 Fix missing break in case 2017-01-27 09:54:17 +00:00
Cmdr McDonald
e448b3cb0a Add specials 2017-01-27 09:54:17 +00:00
Cmdr McDonald
705f3158aa Remove old reference to coriolis.io 2017-01-27 09:54:17 +00:00
Cmdr McDonald
f4789717fe Alter shortlink hotkey - for #58 2017-01-27 09:54:08 +00:00
Cmdr McDonald
93e69f215b Add weapon mods to damage dealt 2017-01-27 09:46:32 +00:00
Cmdr McDonald
d04e662de4 Merge branch 'hotfix/2.2.11b' into develop 2017-01-27 08:14:37 +00:00
Cmdr McDonald
db376829f5 Add package info 2017-01-27 07:56:50 +00:00
Cmdr McDonald
79a31fd992 Fix missing break in case 2017-01-26 18:01:22 +00:00
Cmdr McDonald
094f3aa3e2 Add specials 2017-01-26 16:06:29 +00:00
Cmdr McDonald
41d51743d3 Remove old reference to coriolis.io 2017-01-26 14:38:23 +00:00
Cmdr McDonald
cf741d18ed Merge branch 'release/2.2.11' into develop 2017-01-25 19:46:52 +00:00
26 changed files with 436 additions and 257 deletions

View File

@@ -1,3 +1,31 @@
#2.2.14
* Ensure that jitter is shown correctly when the result of a special effect
* Use restyled blueprint information
* Use the ship name (if available) rather than the ship model for the window title
* Use coriolis-data 2.2.14:
* Alter blueprint structure to combine components and features
* Make hidden value of modifications its own attribute
* Fix incorrect ED ID for class 6 passenger cabins
#2.2.13
* Add 'time to drain' summary value. This is the time to drain the WEP capacitor if firing all enabled weapons
* Do not include utility slot DPS/EPS/HPS in summary information
* Ensure that auto loader special shows in the tooltip
* Ensure that ship mass is recalculated when appropriate
* Use coriolis-data 2.2.13:
* Add plasma slug special effect for plasma accelerator
* Tweak hull costs of ships
#2.2.12
* Tidy up old references to coriolis.io
* Add ability to add and remove special effects to weapon modifications
* Add weapon engineering information to Damage Dealt section
* Change shortcut for link from ctrl-l to ctrl-o to avoid clash with location bar
* Only show one of power generation or draw in tooltips, according to module
* Use coriolis-data 2.2.12:
* Add special effects for each blueprint
* Add IDs for most Powerplay modules
#2.2.11
* Add help system and initial help file
* Make absolute damage visible

View File

@@ -269,20 +269,19 @@
"topSpeed": 187.01,
"totalCost": 882362058,
"totalDpe": 142.68,
"totalDps": 103.8,
"totalEps": 22.71,
"totalHps": 677.29,
"totalDps": 101.13,
"totalEps": 18.71,
"totalExplDpe": 0,
"totalExplDps": 0,
"totalExplSDps": 0,
"totalAbsDpe": 3.57,
"totalAbsDps": 18.78,
"totalAbsSDps": 14.45,
"totalHps": 33.62,
"totalHps": 28.28,
"totalKinDpe": 117.48,
"totalKinDps": 24.94,
"totalKinSDps": 18.76,
"totalSDps": 91.84,
"totalKinDps": 22.27,
"totalKinSDps": 16.91,
"totalSDps": 89.99,
"totalThermDpe": 21.63,
"totalThermDps": 60.08,
"totalThermSDps": 58.64,
@@ -320,6 +319,7 @@
"shieldCells": 1840,
"shieldExplRes": 0.5,
"shieldKinRes": 0.4,
"shieldThermRes": -0.2
"shieldThermRes": -0.2,
"timeToDrain": 7.04
}
}

View File

@@ -238,7 +238,7 @@ describe('Import Modal', function() {
expect(modal.state.singleBuild).toBe(true);
clickProceed();
expect(MockRouter.go.mock.calls.length).toBe(1);
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA02Svy9DURTHT1vvtfoat32eekVV9fm1kBgwSIw0YWYgBqmpMZkMBomFVfwFEoZKhBjE1qWTgegiDX%2BCQdKI1j2%2BR%2FJ4yzfnvu%2FnfO%2B979yQXiCi7xAkbRpEqsLMsRKWHNZpsSKQnppJVLAdIvc6DGiwxexMaWb7GDZHdJ%2BQaCf71Ia%2F88XsOp1EThk9bOh5P2kkahGN3qPM1wANbyOk87zNHH%2FBUs0gnWN61T9TOwfJ7EWJjMcms1lEo30Gx11BD8f1mh%2FcTkCMMvY0HZcoe4Wk5By%2BFcrrRL0N0OOlrd0Ntv57jGoc%2BH4%2F8EqHj3%2FCUXc4FicC5NFvsJBVIWeFvESlpuXSuCS5RRyLlV70z%2B4uQaw6ypSIJ6KOJDgZgFpQ60YgEU9EPQmUCkAfAj0IJOKJqC4wuYMY9rQD5CuubT0LSag8qdShxHUHoElcyWrAT4l4IsoCw65e%2BRv5BqKtC0mSJu8LH8OFT%2Bb%2BE8SZb0CcEn4AZ3TRDx5q4l1EJ%2BCP1bEM1WSaAwH%2FFkOLPoofwTo0LY8nr7O%2B37cp4yWIu4zHlHiXGfMPmat5gqMCAAA%3D&bn=Imported%20Federal%20Corvette');
expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA02SPy9DURjG3%2F65vW1v47TXVbeqqF7EQtIIBomRJswsYmISH8BgkFhqFZ9AwlALMYitkXQyEF2k4SMYJNK0dV7PK7nc5ck55%2Fm9z%2FnznpBeJqLvECQbM4hUjZnjO5hyWGfFikAGGjGiku0QuddhQCNdZmdWM9snsDmih4REOdlnNvz9DrPrJIicPdSwoZf8pAnTIpq8x7DYADS%2Bi5DERY85%2BYqpmkc6x%2FWGf6beKCR3YBIZFZCxCgrtczjuOmo4qTf94F4KYuxhz5jjEhXmUJNexFrpIUo02ALN1j9u1JMgD%2FMga1GfbMNRd9iHUwGy%2BpspZF3IBSGvMFJluS%2FuR24FJ2KlV%2Fxju6sQq4lhRsQTUVUJTgegLtS6EUjEE1HPAmUC0KdAjwKJeCKqD8zoURx72gHyDW9nvQhJGHkyUscS1x%2BAZnAlqwU%2FI%2BKJKEvextXrf93eQrR1KUlS5HWwGC61mfOn0oN3IM4OHoBzuuIHj33hS5jT8KeamIYa0sjhgH%2BLfplP4kcwD5Xl3xR1wfeHtqWzBHHX8I9SH9Je%2FgGvXxeungIAAA%3D%3D&bn=Imported%20Federal%20Corvette');
});
it('imports a valid v4 build', function() {

View File

@@ -1,6 +1,6 @@
{
"name": "coriolis_shipyard",
"version": "2.2.11",
"version": "2.2.14",
"repository": {
"type": "git",
"url": "https://github.com/EDCD/coriolis"

View File

@@ -174,11 +174,12 @@ export default class Coriolis extends React.Component {
this._showModal(<ModalImport />);
}
break;
case 76: // 'l'
if (e.ctrlKey || e.metaKey) { // CTRL/CMD + l
case 79: // 'o'
if (e.ctrlKey || e.metaKey) { // CTRL/CMD + o
e.preventDefault();
this._showModal(<ModalPermalink url={window.location.href}/>);
}
break;
case 83: // 's'
if (e.ctrlKey || e.metaKey) { // CTRL/CMD + s
e.preventDefault();

View File

@@ -103,6 +103,8 @@ export default class DamageDealt extends TranslatedComponent {
* @return {boolean} Returns the per-weapon damage
*/
_calcWeapons(ship, against, range) {
const translate = this.context.language.translate;
// Tidy up the range so that it's to 4 decimal places
range = Math.round(10000 * range) / 10000;
@@ -137,6 +139,13 @@ export default class DamageDealt extends TranslatedComponent {
}
}
const classRating = `${m.class}${m.rating}${m.missile ? '/' + m.missile : ''}`;
let engineering;
if (m.blueprint && m.blueprint.name) {
engineering = translate(m.blueprint.name) + ' ' + translate('grade') + ' ' + m.blueprint.grade;
if (m.blueprint.special && m.blueprint.special.id >= 0) {
engineering += ', ' + translate(m.blueprint.special.name);
}
}
const effectivenessShields = dropoff;
const effectiveDpsShields = m.getDps() * effectivenessShields;
const effectiveSDpsShields = (m.getClip() ? (m.getClip() * m.getDps() / m.getRoF()) / ((m.getClip() / m.getRoF()) + m.getReload()) * effectivenessShields : effectiveDpsShields);
@@ -154,6 +163,7 @@ export default class DamageDealt extends TranslatedComponent {
mount: m.mount,
name: m.name || m.grp,
classRating,
engineering,
effectiveDpsShields,
effectiveSDpsShields,
effectivenessShields,
@@ -163,9 +173,7 @@ export default class DamageDealt extends TranslatedComponent {
}
}
}
console.log('total dps is ' + totalDps);
totals.effectivenessShields = totalDps == 0 ? 0 : totals.effectiveDpsShields / totalDps;
console.log('total effective dps shields is ' + totals.effectiveDpsShields);
totals.effectivenessHull = totalDps == 0 ? 0 : totals.effectiveDpsHull / totalDps;
return { weapons, totals };
@@ -249,6 +257,7 @@ console.log('total effective dps shields is ' + totals.effectiveDpsShields);
{weapon.mount == 'G' ? <span onMouseOver={termtip.bind(null, 'gimballed')} onMouseOut={tooltip.bind(null, null)}><MountGimballed /></span> : null}
{weapon.mount == 'T' ? <span onMouseOver={termtip.bind(null, 'turreted')} onMouseOut={tooltip.bind(null, null)}><MountTurret /></span> : null}
{weapon.classRating} {translate(weapon.name)}
{weapon.engineering ? ' (' + weapon.engineering + ')' : null }
</td>
<td className='ri'>{formats.round1(weapon.effectiveDpsShields)}</td>
<td className='ri'>{formats.round1(weapon.effectiveSDpsShields)}</td>

View File

@@ -48,7 +48,7 @@ export default class HardpointSlot extends Slot {
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) {
if (m.blueprint.special && m.blueprint.special.id >= 0) {
modTT += ', ' + translate(m.blueprint.special.name);
}
}

View File

@@ -47,13 +47,13 @@ export default class InternalSlot extends Slot {
{ m.rate ? <div className={'l'}>{translate('rate')}: {m.rate}{u.kgs}&nbsp;&nbsp;&nbsp;{translate('refuel time')}: {formats.time(this.props.fuel * 1000 / m.rate)}</div> : null }
{ m.getAmmo() ? <div className={'l'}>{translate('ammunition')}: {formats.gen(m.getAmmo())}</div> : null }
{ m.cells ? <div className={'l'}>{translate('cells')}: {m.cells}</div> : null }
{ m.shieldreinforcement ? <div className={'l'}>{translate('shieldreinforcement')}: {formats.int(m.getShieldReinforcement())} <u>MJ</u>&nbsp;&nbsp;&nbsp;{translate('total')}: {formats.int(m.cells * m.getShieldReinforcement())}{u.MJ}</div> : null }
{ m.getShieldReinforcement() ? <div className={'l'}>{translate('shieldreinforcement')}: {formats.int(m.getShieldReinforcement())} <u>MJ</u>&nbsp;&nbsp;&nbsp;{translate('total')}: {formats.int(m.cells * m.getShieldReinforcement())}{u.MJ}</div> : null }
{ m.repair ? <div className={'l'}>{translate('repair')}: {m.repair}</div> : null }
{ m.getFacingLimit() ? <div className={'l'}>{translate('facinglimit')} {formats.f1(m.getFacingLimit())}°</div> : null }
{ m.getRange() ? <div className={'l'}>{translate('range')} {formats.f2(m.getRange())}{u.km}</div> : null }
{ m.getRangeT() ? <div className={'l'}>{translate('ranget')} {formats.f1(m.getRangeT())}{u.s}</div> : null }
{ m.spinup ? <div className={'l'}>{translate('spinup')}: {formats.f1(m.spinup)}{u.s}</div> : null }
{ m.time ? <div className={'l'}>{translate('time')}: {formats.time(m.time)}</div> : null }
{ m.getSpinup() ? <div className={'l'}>{translate('spinup')}: {formats.f1(m.getSpinup())}{u.s}</div> : null }
{ m.getTime() ? <div className={'l'}>{translate('time')}: {formats.time(m.getTime())}</div> : null }
{ m.maximum ? <div className={'l'}>{translate('max')}: {(m.maximum)}</div> : null }
{ m.rangeLS ? <div className={'l'}>{translate('range')}: {m.rangeLS}{u.Ls}</div> : null }
{ m.rangeLS === null ? <div className={'l'}>{u.Ls}</div> : null }

View File

@@ -50,7 +50,7 @@ export default class Modification extends TranslatedComponent {
let m = this.props.m;
let ship = this.props.ship;
ship.setModification(m, name, scaledValue);
ship.setModification(m, name, scaledValue, true);
this.setState({ value });
this.props.onChange();

View File

@@ -29,6 +29,7 @@ export default class ModificationsMenu extends TranslatedComponent {
this.state = this._initState(props, context);
this._toggleBlueprintsMenu = this._toggleBlueprintsMenu.bind(this);
this._toggleSpecialsMenu = this._toggleSpecialsMenu.bind(this);
this._rollWorst = this._rollWorst.bind(this);
this._rollRandom = this._rollRandom.bind(this);
this._rollAverage = this._rollAverage.bind(this);
@@ -44,13 +45,27 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_initState(props, context) {
let { m, onChange, ship } = props;
const { language, tooltip, termtip } = context;
const translate = language.translate;
// Set up the blueprints
let blueprints = [];
for (const blueprintName in Modifications.modules[m.grp].blueprints) {
for (const grade of Modifications.modules[m.grp].blueprints[blueprintName]) {
const close = this._blueprintSelected.bind(this, Modifications.blueprints[blueprintName].id, grade);
const key = blueprintName + ':' + grade;
blueprints.push(<div style={{ cursor: 'pointer' }} key={ key } onClick={ close }>{Modifications.blueprints[blueprintName].name} grade {grade}</div>);
blueprints.push(<div style={{ cursor: 'pointer' }} key={ key } onClick={ close }>{translate(Modifications.blueprints[blueprintName].name + ' grade ' + grade)}</div>);
}
}
// Set up the special effects
let specials = [];
if (Modifications.modules[m.grp].specials && Modifications.modules[m.grp].specials.length > 0) {
const close = this._specialSelected.bind(this, null);
specials.push(<div style={{ cursor: 'pointer' }} key={ 'none' } onClick={ close }>{translate('PHRASE_NO_SPECIAL')}</div>);
for (const specialName of Modifications.modules[m.grp].specials) {
const close = this._specialSelected.bind(this, specialName);
specials.push(<div style={{ cursor: 'pointer' }} key={ specialName } onClick={ close }>{translate(Modifications.specials[specialName].name)}</div>);
}
}
@@ -58,11 +73,9 @@ export default class ModificationsMenu extends TranslatedComponent {
const modifications = this._setModifications(props);
const blueprintMenuOpened = false;
const specialMenuOpened = false;
// Set up the specials for this module
// const specials = _selectSpecials(m);
return { blueprintMenuOpened, blueprints, modifications };
return { blueprintMenuOpened, blueprints, modifications, specialMenuOpened, specials };
}
/**
@@ -74,7 +87,7 @@ export default class ModificationsMenu extends TranslatedComponent {
const { m, onChange, ship } = props;
let modifications = [];
for (const modName of Modifications.modules[m.grp].modifications) {
if (Modifications.modifications[modName].type === 'percentage' || Modifications.modifications[modName].type === 'numeric') {
if (!Modifications.modifications[modName].hidden) {
const key = modName + (m.getModValue(modName) / 100 || 0);
modifications.push(<Modification key={ key } ship={ ship } m={ m } name={ modName } value={ m.getModValue(modName) / 100 || 0 } onChange={ onChange }/>);
}
@@ -106,30 +119,68 @@ export default class ModificationsMenu extends TranslatedComponent {
this.props.onChange();
}
/**
* Toggle the specials menu
*/
_toggleSpecialsMenu() {
const specialMenuOpened = !this.state.specialMenuOpened;
this.setState({ specialMenuOpened });
}
/**
* Activated when a special is selected
* @param {int} special The name of the selected special
*/
_specialSelected(special) {
const { m } = this.props;
if (m.blueprint) {
if (special === null) {
m.blueprint.special = null;
} else {
m.blueprint.special = Modifications.specials[special];
}
}
const specialMenuOpened = false;
this.setState({ specialMenuOpened, modifications: this._setModifications(this.props) });
this.props.onChange();
}
/**
* Set the result of a roll
* @param {object} ship The ship to which the roll applies
* @param {object} m The module to which the roll applies
* @param {string} featureName The modification feature to which the roll applies
* @param {number} value The value of the roll
*/
_setRollResult(ship, m, featureName, value) {
if (Modifications.modifications[featureName].method !== 'overwrite') {
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
} else {
ship.setModification(m, featureName, value);
}
}
/**
* Provide a 'worst' roll within the information we have
*/
_rollWorst() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, features[featureName][1]);
} else {
let value = features[featureName][0];
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
let value = features[featureName][0];
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
@@ -139,25 +190,11 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollAverage() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, (features[featureName][0] + features[featureName][1]) / 2);
} else {
let value = (features[featureName][0] + features[featureName][1]) / 2;
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
let value = (features[featureName][0] + features[featureName][1]) / 2;
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
@@ -167,25 +204,11 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollRandom() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, features[featureName][1]);
} else {
let value = features[featureName][0] + (Math.random() * (features[featureName][1] - features[featureName][0]));
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
let value = features[featureName][0] + (Math.random() * (features[featureName][1] - features[featureName][0]));
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
@@ -195,25 +218,11 @@ export default class ModificationsMenu extends TranslatedComponent {
*/
_rollBest() {
const { m, ship } = this.props;
const features = m.blueprint.features[m.blueprint.grade];
const features = m.blueprint.grades[m.blueprint.grade].features;
for (const featureName in features) {
if (Modifications.modifications[featureName].method == 'overwrite') {
ship.setModification(m, featureName, features[featureName][1]);
} else {
let value = features[featureName][1];
if (m.grp == 'sb' && featureName == 'shieldboost') {
// Shield boosters are a special case. Their boost is dependent on their base so we need to calculate the value here
value = ((1 + m.shieldboost) * (1 + value) - 1) / m.shieldboost - 1;
}
if (Modifications.modifications[featureName].type == 'percentage') {
ship.setModification(m, featureName, value * 10000);
} else if (Modifications.modifications[featureName].type == 'numeric') {
ship.setModification(m, featureName, value * 100);
}
}
let value = features[featureName][1];
this._setRollResult(ship, m, featureName, value);
}
this.setState({ modifications: this._setModifications(this.props) });
this.props.onChange();
}
@@ -235,13 +244,13 @@ export default class ModificationsMenu extends TranslatedComponent {
* @return {React.Component} List
*/
render() {
const language = this.context.language;
const { language, tooltip, termtip } = this.context;
const translate = language.translate;
const { tooltip, termtip } = this.context;
const { m } = this.props;
const { blueprintMenuOpened } = this.state;
const { blueprintMenuOpened, specialMenuOpened } = this.state;
const _toggleBlueprintsMenu = this._toggleBlueprintsMenu;
const _toggleSpecialsMenu = this._toggleSpecialsMenu;
const _rollBest = this._rollBest;
const _rollWorst = this._rollWorst;
const _rollAverage = this._rollAverage;
@@ -257,31 +266,47 @@ export default class ModificationsMenu extends TranslatedComponent {
blueprintLabel = translate('PHRASE_SELECT_BLUEPRINT');
}
let specialLabel;
let haveSpecial = false;
if (m.blueprint && m.blueprint.special) {
specialLabel = m.blueprint.special.name;
} else {
specialLabel = translate('PHRASE_SELECT_SPECIAL');
}
const showBlueprintsMenu = blueprintMenuOpened;
const showSpecial = haveBlueprint && this.state.specials.length > 0;
const showSpecialsMenu = specialMenuOpened;
const showRolls = haveBlueprint && !blueprintMenuOpened && !specialMenuOpened;
const showMods = !blueprintMenuOpened && !specialMenuOpened;
return (
<div
className={cn('select', this.props.className)}
onClick={(e) => e.stopPropagation() }
onContextMenu={stopCtxPropagation}
>
<div className={ cn('section-menu', { selected: true })} style={{ cursor: 'pointer' }} onClick={_toggleBlueprintsMenu}>{blueprintLabel}</div>
{ blueprintMenuOpened ? this.state.blueprints : '' }
{ haveBlueprint ?
<table style={{ width: '100%', backgroundColor: 'transparent' }}>
<tbody>
<tr>
<td> { translate('roll') }: </td>
<td style={{ cursor: 'pointer' }} onClick={_rollWorst} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('worst') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollAverage}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_AVERAGE')} onMouseOut={tooltip.bind(null, null)}> { translate('average') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollBest}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('best') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollRandom} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>
<td style={{ cursor: 'pointer' }} onClick={_reset}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')} onMouseOut={tooltip.bind(null, null)}> { translate('reset') } </td>
</tr>
</tbody>
<div className={ cn('section-menu', { selected: blueprintMenuOpened })} style={{ cursor: 'pointer' }} onClick={_toggleBlueprintsMenu}>{blueprintLabel}</div>
{ showBlueprintsMenu ? this.state.blueprints : '' }
{ showSpecial ? <div className={ cn('section-menu', { selected: specialMenuOpened })} style={{ cursor: 'pointer' }} onClick={_toggleSpecialsMenu}>{specialLabel}</div> : '' }
{ showSpecialsMenu ? this.state.specials : '' }
{ showRolls ?
<table style={{ width: '100%', backgroundColor: 'transparent' }}>
<tbody>
<tr>
<td> { translate('roll') }: </td>
<td style={{ cursor: 'pointer' }} onClick={_rollWorst} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_WORST')} onMouseOut={tooltip.bind(null, null)}> { translate('worst') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollAverage}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_AVERAGE')} onMouseOut={tooltip.bind(null, null)}> { translate('average') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollBest}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_BEST')} onMouseOut={tooltip.bind(null, null)}> { translate('best') } </td>
<td style={{ cursor: 'pointer' }} onClick={_rollRandom} onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RANDOM')} onMouseOut={tooltip.bind(null, null)}> { translate('random') } </td>
<td style={{ cursor: 'pointer' }} onClick={_reset}onMouseOver={termtip.bind(null, 'PHRASE_BLUEPRINT_RESET')} onMouseOut={tooltip.bind(null, null)}> { translate('reset') } </td>
</tr>
</tbody>
</table> : '' }
{ blueprintMenuOpened ? '' :
{ showMods ?
<span onMouseOver={termtip.bind(null, 'HELP_MODIFICATIONS_MENU')} onMouseOut={tooltip.bind(null, null)} >
{ this.state.modifications }
</span> }
</span> : '' }
</div>
);
}

View File

@@ -42,10 +42,11 @@ export default class ShipSummaryTable extends TranslatedComponent {
<th rowSpan={2} className={ cn({ 'bg-warning-disabled': !ship.canBoost() }) }>{translate('boost')}</th>
<th onMouseEnter={termtip.bind(null, 'damage per second')} onMouseLeave={hide} rowSpan={2}>{translate('DPS')}</th>
<th onMouseEnter={termtip.bind(null, 'energy per second')} onMouseLeave={hide} rowSpan={2}>{translate('EPS')}</th>
<th onMouseEnter={termtip.bind(null, 'time to drain WEP capacitor')} onMouseLeave={hide} rowSpan={2}>{translate('TTD')}</th>
<th onMouseEnter={termtip.bind(null, 'heat per second')} onMouseLeave={hide} rowSpan={2}>{translate('HPS')}</th>
<th rowSpan={2}>{translate('hardness')}</th>
<th rowSpan={2}>{translate('armour')}</th>
<th rowSpan={2}>{translate('shields')}</th>
<th onMouseEnter={termtip.bind(null, 'hull hardness')} onMouseLeave={hide} rowSpan={2}>{translate('hrd')}</th>
<th onMouseEnter={termtip.bind(null, 'armour')} onMouseLeave={hide} rowSpan={2}>{translate('arm')}</th>
<th onMouseEnter={termtip.bind(null, 'shields')} onMouseLeave={hide} rowSpan={2}>{translate('shld')}</th>
<th colSpan={3}>{translate('mass')}</th>
<th rowSpan={2}>{translate('cargo')}</th>
<th rowSpan={2}>{translate('fuel')}</th>
@@ -71,6 +72,7 @@ export default class ShipSummaryTable extends TranslatedComponent {
<td>{ ship.canBoost() ? <span>{int(ship.topBoost)} {u['m/s']}</span> : <span className='warning'>0 <Warning/></span> }</td>
<td>{f1(ship.totalDps)}</td>
<td>{f1(ship.totalEps)}</td>
<td>{ship.timeToDrain === Infinity ? '∞' : time(ship.timeToDrain)}</td>
<td>{f1(ship.totalHps)}</td>
<td>{int(ship.hardness)}</td>
<td>{int(ship.armour)}</td>

View File

@@ -91,7 +91,8 @@ export default class StandardSlot extends TranslatedComponent {
<div className={'r'}>{formats.round(mass)}{units.T}</div>
<div/>
<div className={'cb'}>
{ m.getOptimalMass() ? <div className='l'>{translate('optimal mass')}: {formats.int(m.getOptimalMass())}{units.T}</div> : null }
{ m.getMinMass() ? <div className='l'>{translate('minimum mass')}: {formats.int(m.getMinMass())}{units.T}</div> : null }
{ m.getOptMass() ? <div className='l'>{translate('optimal mass')}: {formats.int(m.getOptMass())}{units.T}</div> : null }
{ m.getMaxMass() ? <div className='l'>{translate('max mass')}: {formats.int(m.getMaxMass())}{units.T}</div> : null }
{ m.getRange() ? <div className='l'>{translate('range')}: {formats.f2(m.getRange())}{units.km}</div> : null }
{ m.time ? <div className='l'>{translate('time')}: {formats.time(m.time)}</div> : null }

View File

@@ -35,6 +35,8 @@ export const terms = {
PHRASE_BLUEPRINT_RANDOM: 'Random selection between worst and best primary values for this blueprint',
PHRASE_BLUEPRINT_BEST: 'Best primary values for this blueprint',
PHRASE_BLUEPRINT_RESET: 'Remove all modifications and blueprint',
PHRASE_SELECT_SPECIAL: 'Click to select an experimental effect',
PHRASE_NO_SPECIAL: 'No experimental effect',
HELP_MODIFICATIONS_MENU: 'Click on a number to enter a new value, or drag along the bar for small changes',
@@ -213,6 +215,8 @@ Along the top of the screen are some of the key values for your build. This is
Here, along with most places in Coriolis, acronyms will have tooltips explaining what they mean. Hover over the acronym to obtain more detail, or look in the glossary at the end of this help.</p>
All values are the highest possible, assuming that you have maximum pips in the relevant capacitor (ENG for speed, WEP for time to drain, etc.).</p>
<h2>Modules</h2>
The next set of panels laid out horizontally across the screen contain the modules you have put in your build. From left to right these are the core modules, the internal modules, the hardpoints and the utility mounts. These represent the available slots in your ship and cannot be altered. Each slot has a class, or size, and in general any module up to a given size can fit in a given slot (exceptions being bulkheads, life support and sensors in core modules and restricted internal slots, which can only take a subset of module depending on their restrictions). </p>
@@ -289,7 +293,7 @@ The damage received panel provides information about the effectiveness of your b
<dt>Ctrl-e</dt><dd>open export dialogue (outfitting page only)</dd>
<dt>Ctrl-h</dt><dd>open help dialogue</dd>
<dt>Ctrl-i</dt><dd>open import dialogue</dd>
<dt>Ctrl-l</dt><dd>open shortlink dialogue</dd>
<dt>Ctrl-o</dt><dd>open shortlink dialogue</dd>
<dt>Esc</dt><dd>close any open dialogue</dd>
</dl>
<h1>Glossary</h1>

View File

@@ -36,7 +36,7 @@ const SPEED_COLORS = ['#0088d2', '#ff8c0d', '#D26D00', '#c06400'];
* @return {String} Document title
*/
function getTitle(shipName, buildName) {
return `${shipName}${buildName ? ` - ${buildName}` : ''}`;
return buildName ? buildName : shipName;
}
/**

View File

@@ -251,7 +251,6 @@ export default class ShipyardPage extends Page {
return (
<div className='page' style={{ fontSize: sizeRatio + 'em' }}>
<p style={{ textAlign: 'center' }}>This is <strong>Coriolis EDCD Edition</strong> - a temporary clone of <a href='https://coriolis.io/' target='_blank'>https://coriolis.io/</a> with added support for E:D 2.2. For more info see Settings / <Link href="/about" className='block'>About</Link></p>
<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 }}>
<thead>

View File

@@ -10,7 +10,7 @@ import Module from './Module';
*/
export function jumpRange(mass, fsd, fuel) {
let fsdMaxFuelPerJump = fsd instanceof Module ? fsd.getMaxFuelPerJump() : fsd.maxfuel;
let fsdOptimalMass = fsd instanceof Module ? fsd.getOptimalMass() : fsd.optmass;
let fsdOptimalMass = fsd instanceof Module ? fsd.getOptMass() : fsd.optmass;
return Math.pow(Math.min(fuel === undefined ? fsdMaxFuelPerJump : fuel, fsdMaxFuelPerJump) / fsd.fuelmul, 1 / fsd.fuelpower) * fsdOptimalMass / mass;
}
@@ -24,7 +24,7 @@ export function jumpRange(mass, fsd, fuel) {
*/
export function fastestRange(mass, fsd, fuel) {
let fsdMaxFuelPerJump = fsd instanceof Module ? fsd.getMaxFuelPerJump() : fsd.maxfuel;
let fsdOptimalMass = fsd instanceof Module ? fsd.getOptimalMass() : fsd.optmass;
let fsdOptimalMass = fsd instanceof Module ? fsd.getOptMass() : fsd.optmass;
let fuelRemaining = fuel % fsdMaxFuelPerJump; // Fuel left after making N max jumps
let jumps = Math.floor(fuel / fsdMaxFuelPerJump);
mass += fuelRemaining;

View File

@@ -36,75 +36,127 @@ export default class Module {
/**
* Get a value for a given modification
* @param {Number} name The name of the modification
* @return {object} The value of the modification. If it is a numeric value then it is returned as an integer value scaled so that 1.23% == 123
* @param {Number} name The name of the modification
* @param {Number} raw True if the value returned should be raw i.e. without the influence of special effects
* @return {object} The value of the modification. If it is a numeric value then it is returned as an integer value scaled so that 1.23% == 123
*/
getModValue(name) {
return this.mods && this.mods[name] ? this.mods[name] : null;
getModValue(name, raw) {
let result = this.mods && this.mods[name] ? this.mods[name] : null;
if ((!raw) && this.blueprint && this.blueprint.special) {
// This module has a special effect, see if we need to alter our returned value
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
if (modifierActions && modifierActions[name]) {
// this special effect modifies our returned value
const modification = Modifications.modifications[name];
if (modification.method === 'additive') {
result = result + modifierActions[name];
} else if (modification.method === 'overwrite') {
result = modifierActions[name];
} else {
// rate of fire is special, as it's really burst interval. Handle that here
let mod = null;
if (name === 'rof') {
mod = 1 / (1 + modifierActions[name]) - 1;
} else {
mod = modifierActions[name];
}
const multiplier = modification.type === 'percentage' ? 10000 : 100;
result = (((1 + result / multiplier) * (1 + mod)) - 1) * multiplier;
}
}
}
// Sanitise the resultant value to 4dp equivalent
return isNaN(result) ? result : Math.round(result);
}
/**
* Set a value for a given modification ID
* @param {Number} name The name of the modification
* @param {Number} name The name of the modification
* @param {object} value The value of the modification. If it is a numeric value then it should be an integer scaled so that -2.34% == -234
* @param {bool} valueiswithspecial true if the value includes the special effect (when coming from a UI component)
*/
setModValue(name, value) {
setModValue(name, value, valueiswithspecial) {
if (!this.mods) {
this.mods = {};
}
if (valueiswithspecial && this.blueprint && this.blueprint.special) {
// This module has a special effect, see if we need to alter the stored value
const modifierActions = Modifications.modifierActions[this.blueprint.special.edname];
if (modifierActions && modifierActions[name]) {
// This special effect modifies the value being set, so we need to revert it prior to storing the value
const modification = Modifications.modifications[name];
if (modification.method === 'additive') {
value = value - modifierActions[name];
} else if (modification.method === 'overwrite') {
value = null;
} else {
// rate of fire is special, as it's really burst interval. Handle that here
let mod = null;
if (name === 'rof') {
mod = 1 / (1 + modifierActions[name]) - 1;
} else {
mod = modifierActions[name];
}
value = ((value / 10000 + 1) / (1 + mod) - 1) * 10000;
}
}
}
if (value == null || value == 0) {
delete this.mods[name];
} else {
if (isNaN(value)) {
this.mods[name] = value;
} else {
// Round just to be sure
this.mods[name] = Math.round(value);
}
this.mods[name] = value;
}
}
/**
* Helper to obtain a modified value using standard multipliers
* @param {String} name the name of the modifier to obtain
* @param {Boolean} additive Optional true if the value is additive rather than multiplicative
* @return {Number} the mass of this module
*/
_getModifiedValue(name, additive) {
let result = this[name] || (additive ? 0 : null); // Additive NULL === 0
if (result != null) {
const modification = Modifications.modifications[name];
if (!modification) {
return result;
}
_getModifiedValue(name) {
const modification = Modifications.modifications[name];
let result = this[name];
// We store percentages as decimals, so to get them back we need to divide by 10000. Otherwise
// we divide by 100. Both ways we end up with a value with two decimal places
let modValue;
if (modification.type === 'percentage') {
modValue = this.getModValue(name) / 10000;
} else if (modification.type === 'numeric') {
modValue = this.getModValue(name) / 100;
if (!result) {
if (modification && modification.method === 'additive') {
// Additive modifications start at 0 rather than NULL
result = 0;
} else {
modValue = this.getModValue(name);
result = null;
}
if (modValue) {
if (additive) {
result = result + modValue;
}
if (result != null) {
if (modification) {
// We store percentages as decimals, so to get them back we need to divide by 10000. Otherwise
// we divide by 100. Both ways we end up with a value with two decimal places
let modValue;
if (modification.type === 'percentage') {
modValue = this.getModValue(name) / 10000;
} else if (modification.type === 'numeric') {
modValue = this.getModValue(name) / 100;
} else {
result = result * (1 + modValue);
modValue = this.getModValue(name);
}
if (modValue) {
if (modification.method === 'additive') {
result = result + modValue;
} else if (modification.method === 'overwrite') {
result = modValue;
} else {
result = result * (1 + modValue);
}
}
}
} else {
if (name === 'burst') {
// Burst is special, as if it can not exist but have a modification
const modValue = this.getModValue(name) / 100;
return modValue;
result = this.getModValue(name) / 100;
} else if (name === 'burstrof') {
// Burst rate of fire is special, as if it can not exist but have a modification
const modValue = this.getModValue(name) / 100;
return modValue;
result = this.getModValue(name) / 100;
}
}
@@ -159,30 +211,6 @@ export default class Module {
return this._getModifiedValue('eff');
}
/**
* Get the maximum mass of this module, taking in to account modifications
* @return {Number} the maximum mass of this module
*/
getMaxMass() {
return this._getModifiedValue('maxmass');
}
/**
* Get the optimal mass of this module, taking in to account modifications
* @return {Number} the optimal mass of this module
*/
getOptimalMass() {
return this._getModifiedValue('optmass');
}
/**
* Get the optimal multiplier of this module, taking in to account modifications
* @return {Number} the optimal multiplier of this module
*/
getOptimalMultiplier() {
return this._getModifiedValue('optmult');
}
/**
* Get the maximum fuel per jump for this module, taking in to account modifications
* @return {Number} the maximum fuel per jump of this module
@@ -244,7 +272,7 @@ export default class Module {
* @return {Number} the kinetic resistance of this module
*/
getKineticResistance() {
return this._getModifiedValue('kinres', true);
return this._getModifiedValue('kinres');
}
/**
@@ -252,7 +280,7 @@ export default class Module {
* @return {Number} the thermal resistance of this module
*/
getThermalResistance() {
return this._getModifiedValue('thermres', true);
return this._getModifiedValue('thermres');
}
/**
@@ -260,7 +288,7 @@ export default class Module {
* @return {Number} the explosive resistance of this module
*/
getExplosiveResistance() {
return this._getModifiedValue('explres', true);
return this._getModifiedValue('explres');
}
/**
@@ -671,9 +699,25 @@ export default class Module {
/**
* Get the shot speed for this module, taking in to account modifications
* @return {string} the damage distribution for this module
* @return {string} the shot speed for this module
*/
getShotSpeed() {
return this._getModifiedValue('shotspeed');
}
/**
* Get the spinup for this module, taking in to account modifications
* @return {string} the spinup for this module
*/
getSpinup() {
return this._getModifiedValue('spinup');
}
/**
* Get the time for this module, taking in to account modifications
* @return {string} the time for this module
*/
getTime() {
return this._getModifiedValue('time');
}
}

View File

@@ -90,7 +90,7 @@ export function toDetailedBuild(buildName, ship) {
code = ship.toString();
let data = {
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/4.json#',
$schema: 'https://coriolis.edcd.io/schemas/ship-loadout/4.json#',
name: buildName,
ship: ship.name,
references: [{

View File

@@ -419,6 +419,7 @@ export default class Ship {
m.mods = {};
this.updatePowerGenerated()
.updatePowerUsed()
.recalculateMass()
.updateJumpStats()
.recalculateShield()
.recalculateShieldCells()
@@ -426,6 +427,7 @@ export default class Ship {
.recalculateDps()
.recalculateEps()
.recalculateHps()
.recalculateTtd()
.updateMovement();
}
@@ -438,12 +440,13 @@ export default class Ship {
}
/**
* Set a modification value
* @param {Object} m The module to change
* @param {Object} name The name of the modification to change
* Set a modification value and update ship stats
* @param {Object} m The module to change
* @param {Object} name The name of the modification to change
* @param {Number} value The new value of the modification. The value of the modification is scaled to provide two decimal places of precision in an integer. For example 1.23% is stored as 123
* @param {bool} sentfromui True if this update was sent from the UI
*/
setModification(m, name, value) {
setModification(m, name, value, sentfromui) {
if (isNaN(value)) {
// Value passed is invalid; reset it to 0
value = 0;
@@ -452,58 +455,59 @@ export default class Ship {
// Handle special cases
if (name === 'pgen') {
// Power generation
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
this.updatePowerGenerated();
} else if (name === 'power') {
// Power usage
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
this.updatePowerUsed();
} else if (name === 'mass') {
// Mass
let oldMass = m.getMass();
m.setModValue(name, value);
let newMass = m.getMass();
this.unladenMass = this.unladenMass - oldMass + newMass;
this.ladenMass = this.ladenMass - oldMass + newMass;
m.setModValue(name, value, sentfromui);
this.recalculateMass();
this.updateMovement();
this.updateJumpStats();
} else if (name === 'maxfuel') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
this.updateJumpStats();
} else if (name === 'optmass') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
// Could be for any of thrusters, FSD or shield
this.updateMovement();
this.updateJumpStats();
this.recalculateShield();
} else if (name === 'optmul') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
// Could be for any of thrusters, FSD or shield
this.updateMovement();
this.updateJumpStats();
this.recalculateShield();
} else if (name === 'shieldboost') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
this.recalculateShield();
} else if (name === 'hullboost' || name === 'hullreinforcement' || name === 'modulereinforcement') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
this.recalculateArmour();
} else if (name === 'shieldreinforcement') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
this.recalculateShieldCells();
} else if (name === 'burst' || name == 'burstrof' || name === 'clip' || name === 'damage' || name === 'distdraw' || name === 'jitter' || name === 'piercing' || name === 'range' || name === 'reload' || name === 'rof' || name === 'thermload') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
this.recalculateDps();
this.recalculateHps();
this.recalculateEps();
this.recalculateTtd();
} else if (name === 'explres' || name === 'kinres' || name === 'thermres') {
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
// Could be for shields or armour
this.recalculateArmour();
this.recalculateShield();
} else if (name === 'wepcap' || name === 'weprate') {
m.setModValue(name, value, sentfromui);
this.recalculateTtd();
} else {
// Generic
m.setModValue(name, value);
m.setModValue(name, value, sentfromui);
}
}
@@ -626,6 +630,7 @@ export default class Ship {
if (comps) {
this.updatePowerGenerated()
.updatePowerUsed()
.recalculateMass()
.updateJumpStats()
.recalculateShield()
.recalculateShieldCells()
@@ -633,6 +638,7 @@ export default class Ship {
.recalculateDps()
.recalculateEps()
.recalculateHps()
.recalculateTtd()
.updateMovement();
}
@@ -814,6 +820,7 @@ export default class Ship {
if (slot.m.getEps()) {
this.recalculateEps();
this.recalculateTtd();
}
}
}
@@ -850,6 +857,7 @@ export default class Ship {
*/
updateStats(slot, n, old, preventUpdate) {
let powerGeneratedChange = slot == this.standard[0];
let powerDistributorChange = slot == this.standard[4];
let powerUsedChange = false;
let dpsChanged = n && n.getDps() || old && old.getDps();
let epsChanged = n && n.getEps() || old && old.getEps();
@@ -862,15 +870,6 @@ export default class Ship {
let shieldCellsChange = (n && n.grp === 'scb') || (old && old.grp === 'scb');
if (old) { // Old modul now being removed
switch (old.grp) {
case 'ft':
this.fuelCapacity -= old.fuel;
break;
case 'cr':
this.cargoCapacity -= old.cargo;
break;
}
if (slot.incCost && old.cost) {
this.totalCost -= old.cost * this.moduleCostMultiplier;
}
@@ -878,20 +877,9 @@ export default class Ship {
if (old.getPowerUsage() > 0 && slot.enabled) {
powerUsedChange = true;
}
this.unladenMass -= old.getMass() || 0;
}
if (n) {
switch (n.grp) {
case 'ft':
this.fuelCapacity += n.fuel;
break;
case 'cr':
this.cargoCapacity += n.cargo;
break;
}
if (slot.incCost && n.cost) {
this.totalCost += n.cost * this.moduleCostMultiplier;
}
@@ -899,18 +887,17 @@ export default class Ship {
if (n.power && slot.enabled) {
powerUsedChange = true;
}
this.unladenMass += n.getMass() || 0;
}
this.ladenMass = this.unladenMass + this.cargoCapacity + this.fuelCapacity;
if (!preventUpdate) {
// Must recalculate mass first, as movement, jump etc. relies on it
this.recalculateMass();
if (dpsChanged) {
this.recalculateDps();
}
if (epsChanged) {
this.recalculateEps();
this.recalculateTtd();
}
if (hpsChanged) {
this.recalculateHps();
@@ -918,6 +905,9 @@ export default class Ship {
if (powerGeneratedChange) {
this.updatePowerGenerated();
}
if (powerDistributorChange) {
this.recalculateTtd();
}
if (powerUsedChange) {
this.updatePowerUsed();
}
@@ -956,7 +946,34 @@ export default class Ship {
}
/**
* Calculate damage per second for weapons
* Calculate time to drain WEP capacitor
* @return {this} The ship instance (for chaining operations)
*/
recalculateTtd() {
let totalSEps = 0;
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m && slot.enabled && slot.type === 'WEP' && slot.m.getDps()) {
totalSEps += slot.m.getClip() ? (slot.m.getClip() * slot.m.getEps() / slot.m.getRoF()) / ((slot.m.getClip() / slot.m.getRoF()) + slot.m.getReload()) : slot.m.getEps();
}
}
// Calculate the drain time
const drainPerSecond = totalSEps - this.standard[4].m.getWeaponsRechargeRate();
if (drainPerSecond <= 0) {
// Can fire forever
this.timeToDrain = Infinity;
} else {
const initialCharge = this.standard[4].m.getWeaponsCapacity();
this.timeToDrain = initialCharge / drainPerSecond;
}
return this;
}
/**
* Calculate damage per second and related items for weapons
* @return {this} The ship instance (for chaining operations)
*/
recalculateDps() {
@@ -978,7 +995,7 @@ export default class Ship {
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m && slot.enabled && slot.m.getDps()) {
if (slot.m && slot.enabled && slot.type === 'WEP' && slot.m.getDps()) {
const dpe = slot.m.getEps() === 0 ? 0 : slot.m.getDps() / slot.m.getEps();
const dps = slot.m.getDps();
const sdps = slot.m.getClip() ? (slot.m.getClip() * slot.m.getDps() / slot.m.getRoF()) / ((slot.m.getClip() / slot.m.getRoF()) + slot.m.getReload()) : dps;
@@ -1039,7 +1056,7 @@ export default class Ship {
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m && slot.enabled && slot.m.getHps()) {
if (slot.m && slot.enabled && slot.type === 'WEP' && slot.m.getHps()) {
totalHps += slot.m.getHps();
}
}
@@ -1057,7 +1074,7 @@ export default class Ship {
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m && slot.enabled && slot.m.getEps()) {
if (slot.m && slot.enabled && slot.m.getEps() && slot.type === 'WEP') {
totalEps += slot.m.getEps();
}
}
@@ -1129,6 +1146,55 @@ export default class Ship {
return this;
}
/**
* Eecalculate mass
* @return {this} The ship instance (for chaining operations)
*/
recalculateMass() {
let unladenMass = this.hullMass;
let cargoCapacity = 0;
let fuelCapacity = 0;
unladenMass += this.bulkheads.m.getMass();
for (let slotNum in this.standard) {
const slot = this.standard[slotNum];
if (slot.m) {
unladenMass += slot.m.getMass();
if (slot.m.grp === 'ft') {
fuelCapacity += slot.m.fuel;
}
}
}
for (let slotNum in this.internal) {
const slot = this.internal[slotNum];
if (slot.m) {
unladenMass += slot.m.getMass();
if (slot.m.grp === 'ft') {
fuelCapacity += slot.m.fuel;
} else if (slot.m.grp === 'cr') {
cargoCapacity += slot.m.cargo;
}
}
}
for (let slotNum in this.hardpoints) {
const slot = this.hardpoints[slotNum];
if (slot.m) {
unladenMass += slot.m.getMass();
}
}
// Update global stats
this.unladenMass = unladenMass;
this.cargoCapacity = cargoCapacity;
this.fuelCapacity = fuelCapacity;
this.ladenMass = unladenMass + fuelCapacity + cargoCapacity;
return this;
}
/**
* Update movement values
* @return {this} The ship instance (for chaining operations)
@@ -1376,7 +1442,7 @@ export default class Ship {
for (let modKey in this.bulkheads.m.mods) {
// Filter out invalid modifications
if (Modifications.modules['bh'] && Modifications.modules['bh'].modifications.indexOf(modKey) != -1) {
bulkheadMods.push({ id: Modifications.modifications[modKey].id, value: this.bulkheads.m.getModValue(modKey) });
bulkheadMods.push({ id: Modifications.modifications[modKey].id, value: this.bulkheads.m.getModValue(modKey, true) });
}
}
bulkheadBlueprint = this.bulkheads.m.blueprint;
@@ -1391,7 +1457,7 @@ export default class Ship {
for (let modKey in slot.m.mods) {
// Filter out invalid modifications
if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) {
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) });
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey, true) });
}
}
}
@@ -1406,7 +1472,7 @@ export default class Ship {
for (let modKey in slot.m.mods) {
// Filter out invalid modifications
if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) {
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) });
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey, true) });
}
}
}
@@ -1421,7 +1487,7 @@ export default class Ship {
for (let modKey in slot.m.mods) {
// Filter out invalid modifications
if (Modifications.modules[slot.m.grp] && Modifications.modules[slot.m.grp].modifications.indexOf(modKey) != -1) {
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey) });
slotMods.push({ id: Modifications.modifications[modKey].id, value: slot.m.getModValue(modKey, true) });
}
}
}

View File

@@ -308,6 +308,9 @@ function _addModifications(module, modifiers, blueprint, grade) {
} else if (modifiers.modifiers[i].name === 'mod_weapon_falloffrange_from_range') {
// Obtain the falloff value directly from the range
module.setModValue('fallofffromrange', 1);
} else if (modifiers.modifiers[i].name && modifiers.modifiers[i].name.startsWith('special_')) {
// We don't add special effects directly, but keep a note of them so they can be added when fetching values
special = Modifications.specials[modifiers.modifiers[i].name];
} else {
// Look up the modifiers to find what we need to do
const modifierActions = Modifications.modifierActions[modifiers.modifiers[i].name];
@@ -327,11 +330,6 @@ function _addModifications(module, modifiers, blueprint, grade) {
}
}
}
// Note the special if present
if (modifiers.modifiers[i].name && modifiers.modifiers[i].name.startsWith('special_')) {
special = Modifications.specials[modifiers.modifiers[i].name];
}
}
// Add the blueprint ID, grade and special

View File

@@ -151,13 +151,15 @@ export function diffDetails(language, m, mm) {
let mmMass = mm ? mm.getMass() : 0;
if (mMass != mmMass) propDiffs.push(<div key='mass'>{translate('mass')}: <span className={diffClass(mMass, mmMass, true)}>{diff(formats.round, mMass, mmMass)}{units.T}</span></div>);
let mPowerGeneration = m.pgen || 0;
let mmPowerGeneration = mm ? mm.getPowerGeneration() : 0;
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}</span></div>);
let mPowerUsage = m.power || 0;
let mmPowerUsage = mm ? mm.getPowerUsage() : 0;
if (mPowerUsage != mmPowerUsage) propDiffs.push(<div key='power'>{translate('power')}: <span className={diffClass(mPowerUsage, mmPowerUsage, true)}>{diff(formats.round, mPowerUsage, mmPowerUsage)}{units.MJ}</span></div>);
if (m.grp === 'pp') {
let mPowerGeneration = m.pgen || 0;
let mmPowerGeneration = mm ? mm.getPowerGeneration() : 0;
if (mPowerGeneration != mmPowerGeneration) propDiffs.push(<div key='pgen'>{translate('pgen')}: <span className={diffClass(mPowerGeneration, mmPowerGeneration)}>{diff(formats.round, mPowerGeneration, mmPowerGeneration)}{units.MJ}</span></div>);
} else {
let mPowerUsage = m.power || 0;
let mmPowerUsage = mm ? mm.getPowerUsage() : 0;
if (mPowerUsage != mmPowerUsage) propDiffs.push(<div key='power'>{translate('power')}: <span className={diffClass(mPowerUsage, mmPowerUsage, true)}>{diff(formats.round, mPowerUsage, mmPowerUsage)}{units.MJ}</span></div>);
}
let mDps = m.damage * (m.rpshot || 1) * (m.rof || 1) || 0;
let mmDps = mm ? mm.getDps() || 0 : 0;

View File

@@ -1,5 +1,5 @@
{
"name": "Coriolis.io",
"name": "Coriolis EDCD Edition",
"short_name": "Coriolis",
"icons": [
{
@@ -27,7 +27,7 @@
"density": "4.0"
}
],
"start_url": "http:\/\/coriolis.io",
"start_url": "https:\/\/edcd.coriolis.io",
"display": "standalone",
"orientation": "portrait"
}

View File

@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://cdn.coriolis.io/schemas/ship-loadout/1.json#",
"id": "https://coriolis.edcd.io/schemas/ship-loadout/1.json#",
"title": "Ship Loadout",
"type": "object",
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",
@@ -278,4 +278,4 @@
"standardRatings": { "enum": ["A", "B", "C", "D", "E"] },
"allRatings": { "enum": ["A", "B", "C", "D", "E", "F", "I" ] }
}
}
}

View File

@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://cdn.coriolis.io/schemas/ship-loadout/2.json#",
"id": "https://coriolis.edcd.io/schemas/ship-loadout/2.json#",
"title": "Ship Loadout",
"type": "object",
"description": "The details for a specific ship build/loadout. DEPRECATED in favor of Version 3",

View File

@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://cdn.coriolis.io/schemas/ship-loadout/3.json#",
"id": "https://coriolis.edcd.io/schemas/ship-loadout/3.json#",
"title": "Ship Loadout",
"type": "object",
"description": "The details for a specific ship build/loadout",

View File

@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://cdn.coriolis.io/schemas/ship-loadout/4.json#",
"id": "https://coriolis.edcd.io/schemas/ship-loadout/4.json#",
"title": "Ship Loadout",
"type": "object",
"description": "The details for a specific ship build/loadout",