mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-09 06:43:24 +00:00
Merge branch 'feature/burst' into develop
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
#2.2.5
|
||||
* Calculate rate of fire for multi-burst weapons
|
||||
|
||||
#2.2.4
|
||||
* Add shortlink for outfitting page
|
||||
* Use coriolis-data 2.2.4:
|
||||
|
||||
@@ -271,7 +271,7 @@
|
||||
"totalExplDpe": 0,
|
||||
"totalExplDps": 0,
|
||||
"totalExplSDps": 0,
|
||||
"totalHps": 33.28,
|
||||
"totalHps": 33.62,
|
||||
"totalKinDpe": 103.97,
|
||||
"totalKinDps": 28.92,
|
||||
"totalKinSDps": 21.23,
|
||||
|
||||
@@ -8,7 +8,7 @@ import Header from './components/Header';
|
||||
import Tooltip from './components/Tooltip';
|
||||
import ModalImport from './components/ModalImport';
|
||||
import * as CompanionApiUtils from './utils/CompanionApiUtils';
|
||||
import { outfitURL } from './utils/UrlGenerators'
|
||||
import { outfitURL } from './utils/UrlGenerators';
|
||||
|
||||
import AboutPage from './pages/AboutPage';
|
||||
import NotFoundPage from './pages/NotFoundPage';
|
||||
|
||||
@@ -72,7 +72,7 @@ export default class ComparisonTable extends TranslatedComponent {
|
||||
* @return {React.Component} Table row
|
||||
*/
|
||||
_buildRow(build, facets, formats, units) {
|
||||
let url = outfitURL(build.id, build.toString(), build.buildName)
|
||||
let url = outfitURL(build.id, build.toString(), build.buildName);
|
||||
let cells = [
|
||||
<td key='s' className='tl'><Link href={url}>{build.name}</Link></td>,
|
||||
<td key='bn' className='tl'><Link href={url}>{build.buildName}</Link></td>
|
||||
|
||||
@@ -48,22 +48,22 @@ export default class HardpointSlot extends Slot {
|
||||
let modTT = translate('modified');
|
||||
if (m && m.blueprint) {
|
||||
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) {
|
||||
modTT += ', ' + translate(m.blueprint.special.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return <div className='details' draggable='true' onDragStart={drag} onDragEnd={drop}>
|
||||
<div className={'cb'}>
|
||||
<div className={'l'}>
|
||||
{m.mount && m.mount == 'F' ? <span onMouseOver={termtip.bind(null, 'fixed')} onMouseOut={tooltip.bind(null, null)}><MountFixed /></span> : ''}
|
||||
{m.mount && m.mount == 'G' ? <span onMouseOver={termtip.bind(null, 'gimballed')} onMouseOut={tooltip.bind(null, null)}><MountGimballed /></span> : ''}
|
||||
{m.mount && m.mount == 'T' ? <span onMouseOver={termtip.bind(null, 'turreted')} onMouseOut={tooltip.bind(null, null)}><MountTurret /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('K') ? <span onMouseOver={termtip.bind(null, 'kinetic')} onMouseOut={tooltip.bind(null, null)}><DamageKinetic /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('T') ? <span onMouseOver={termtip.bind(null, 'thermal')} onMouseOut={tooltip.bind(null, null)}><DamageThermal /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('E') ? <span onMouseOver={termtip.bind(null, 'explosive')} onMouseOut={tooltip.bind(null, null)}><DamageExplosive /></span> : ''}
|
||||
{m.mount && m.mount == 'F' ? <span onMouseOver={termtip.bind(null, 'fixed')} onMouseOut={tooltip.bind(null, null)}><MountFixed /></span> : ''}
|
||||
{m.mount && m.mount == 'G' ? <span onMouseOver={termtip.bind(null, 'gimballed')} onMouseOut={tooltip.bind(null, null)}><MountGimballed /></span> : ''}
|
||||
{m.mount && m.mount == 'T' ? <span onMouseOver={termtip.bind(null, 'turreted')} onMouseOut={tooltip.bind(null, null)}><MountTurret /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('K') ? <span onMouseOver={termtip.bind(null, 'kinetic')} onMouseOut={tooltip.bind(null, null)}><DamageKinetic /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('T') ? <span onMouseOver={termtip.bind(null, 'thermal')} onMouseOut={tooltip.bind(null, null)}><DamageThermal /></span> : ''}
|
||||
{m.getDamageType() && m.getDamageType().match('E') ? <span onMouseOver={termtip.bind(null, 'explosive')} onMouseOut={tooltip.bind(null, null)}><DamageExplosive /></span> : ''}
|
||||
{classRating} {translate(m.name || m.grp)}{ m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={'r'}>{formats.round(m.getMass())}{u.T}</div>
|
||||
</div>
|
||||
|
||||
@@ -346,6 +346,7 @@ export default class ModalImport extends TranslatedComponent {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// console.log(e.stack);
|
||||
this.setState({ errorMsg: (typeof e == 'string') ? e : 'Cannot Parse the data!' });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,9 +63,24 @@ export default class Modification extends TranslatedComponent {
|
||||
let translate = this.context.language.translate;
|
||||
let name = this.props.name;
|
||||
|
||||
if (name === 'type') {
|
||||
// We don't show type
|
||||
return null;
|
||||
}
|
||||
|
||||
let symbol;
|
||||
if (name === 'jitter') {
|
||||
symbol = '°';
|
||||
} else if (name !== 'burst') {
|
||||
symbol = '%';
|
||||
}
|
||||
if (symbol) {
|
||||
symbol = ' (' + symbol + ')';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'cb'} key={name}>
|
||||
<div className={'cb'}>{translate(name)}{name === 'jitter' ? ' (°)' : ' (%)'}</div>
|
||||
<div className={'cb'}>{translate(name)}{symbol}</div>
|
||||
<NumberEditor className={'cb'} style={{ width: '90%', textAlign: 'center' }} step={0.01} stepModifier={1} decimals={2} value={this.state.value} onValueChange={this._updateValue.bind(this)} />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as ModuleUtils from './ModuleUtils';
|
||||
import * as _ from 'lodash';
|
||||
import { Modifications } from 'coriolis-data/dist';
|
||||
|
||||
/**
|
||||
* Module - active module in a ship's buildout
|
||||
@@ -65,8 +66,20 @@ export default class Module {
|
||||
_getModifiedValue(name, additive) {
|
||||
let result = this[name] || (additive ? 0 : null); // Additive NULL === 0
|
||||
if (result != null) {
|
||||
// Jitter is special, being the only non-percentage value (it is in fact degrees)
|
||||
const modValue = name === 'jitter' ? this.getModValue(name) / 100 : this.getModValue(name) / 10000;
|
||||
const modification = Modifications.modifications[name];
|
||||
if (!modification) {
|
||||
return result;
|
||||
}
|
||||
// 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 {
|
||||
modValue = this.getModValue(name);
|
||||
}
|
||||
if (modValue) {
|
||||
if (additive) {
|
||||
result = result + modValue;
|
||||
@@ -74,7 +87,18 @@ export default class Module {
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -425,7 +449,7 @@ export default class Module {
|
||||
getDps() {
|
||||
// DPS is a synthetic value
|
||||
let damage = this.getDamage();
|
||||
let rpshot = this.getRoundsPerShot() || 1;
|
||||
let rpshot = this.roundspershot || 1;
|
||||
let rof = this.getRoF() || 1;
|
||||
|
||||
return damage * rpshot * rof;
|
||||
@@ -438,7 +462,7 @@ export default class Module {
|
||||
getEps() {
|
||||
// EPS is a synthetic value
|
||||
let distdraw = this.getDistDraw();
|
||||
let rpshot = this.getRoundsPerShot() || 1;
|
||||
let rpshot = this.roundspershot || 1;
|
||||
let rof = this.getRoF() || 1;
|
||||
|
||||
return distdraw * rpshot * rof;
|
||||
@@ -451,7 +475,7 @@ export default class Module {
|
||||
getHps() {
|
||||
// HPS is a synthetic value
|
||||
let heat = this.getThermalLoad();
|
||||
let rpshot = this.getRoundsPerShot() || 1;
|
||||
let rpshot = this.roundspershot || 1;
|
||||
let rof = this.getRoF() || 1;
|
||||
|
||||
return heat * rpshot * rof;
|
||||
@@ -482,11 +506,35 @@ export default class Module {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rate of fire for this module, taking in to account modifications
|
||||
* Get the burst size for this module, taking in to account modifications
|
||||
* @return {Number} the burst size of this module
|
||||
*/
|
||||
getBurst() {
|
||||
return this._getModifiedValue('burst');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the burst rate of fire for this module, taking in to account modifications
|
||||
* @return {Number} the burst rate of fire of this module
|
||||
*/
|
||||
getBurstRoF() {
|
||||
return this._getModifiedValue('burstrof');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rate of fire for this module, taking in to account modifications.
|
||||
* The rate of fire is a combination value, and needs to take in to account
|
||||
* bursts of fire.
|
||||
* Firing goes [burst 1] [burst interval] [burst 2] [burst interval] ... [burst n] [interval]
|
||||
* where 'n' is 'burst', 'burst interval' is '1/burstrof' and 'interval' is '1/rof'
|
||||
* @return {Number} the rate of fire for this module
|
||||
*/
|
||||
getRoF() {
|
||||
return this._getModifiedValue('rof');
|
||||
const burst = this.getBurst() || 1;
|
||||
const burstRoF = this.getBurstRoF() || 1;
|
||||
const intRoF = this._getModifiedValue('rof');
|
||||
|
||||
return burst / (((burst - 1) / burstRoF) + 1 / intRoF);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@ import { outfitURL } from '../utils/UrlGenerators';
|
||||
|
||||
const STANDARD = ['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'];
|
||||
|
||||
const STANDARD_GROUPS = {'powerPlant': 'pp', 'thrusters': 't', 'frameShiftDrive': 'fsd', 'lifeSupport': 'ls', 'powerDistributor': 'pd', 'sensors': 's', 'fuelTank': 'ft'};
|
||||
const STANDARD_GROUPS = { 'powerPlant': 'pp', 'thrusters': 't', 'frameShiftDrive': 'fsd', 'lifeSupport': 'ls', 'powerDistributor': 'pd', 'sensors': 's', 'fuelTank': 'ft' };
|
||||
|
||||
/**
|
||||
* Generates ship-loadout JSON Schema standard object
|
||||
|
||||
@@ -458,7 +458,7 @@ export default class Ship {
|
||||
} else if (name === 'shieldreinforcement') {
|
||||
m.setModValue(name, value);
|
||||
this.recalculateShieldCells();
|
||||
} else if (name === 'burst' || name === 'clip' || name === 'damage' || name === 'distdraw' || name === 'jitter' || name === 'piercing' || name === 'range' || name === 'reload' || name === 'rof' || name === 'thermload') {
|
||||
} 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);
|
||||
this.recalculateDps();
|
||||
this.recalculateHps();
|
||||
@@ -1260,7 +1260,7 @@ export default class Ship {
|
||||
let modElements = mods[j].split(':');
|
||||
if (modElements[0].match('[0-9]+')) {
|
||||
const modification = _.find(Modifications.modifications, function(o) { return o.id === modElements[0]; });
|
||||
if (modification != null) arr[i][modification.name] = Number(modElements[1]);
|
||||
if (modification != null) arr[i][modification.name] = Number(modElements[1]);
|
||||
} else {
|
||||
arr[i][modElements[0]] = Number(modElements[1]);
|
||||
}
|
||||
@@ -1297,7 +1297,7 @@ export default class Ship {
|
||||
bulkheadBlueprint = this.bulkheads.m.blueprint;
|
||||
}
|
||||
slots.push(bulkheadMods);
|
||||
blueprints.push(bulkheadBlueprint)
|
||||
blueprints.push(bulkheadBlueprint);
|
||||
specials.push(bulkheadBlueprint ? bulkheadBlueprint.special : null);
|
||||
|
||||
for (let slot of this.standard) {
|
||||
@@ -1356,7 +1356,7 @@ export default class Ship {
|
||||
for (let special of specials) {
|
||||
if (special) {
|
||||
// Length is 5 for each special
|
||||
bufsize += 5;
|
||||
bufsize += 5;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1376,20 +1376,20 @@ export default class Ship {
|
||||
buffer.writeInt8(MODIFICATION_ID_GRADE, curpos++);
|
||||
buffer.writeInt32LE(blueprints[i].grade, curpos);
|
||||
curpos += 4;
|
||||
}
|
||||
}
|
||||
if (specials[i]) {
|
||||
buffer.writeInt8(MODIFICATION_ID_SPECIAL, curpos++);
|
||||
buffer.writeInt32LE(specials[i].id, curpos);
|
||||
curpos += 4;
|
||||
}
|
||||
}
|
||||
for (let slotMod of slot) {
|
||||
buffer.writeInt8(slotMod.id, curpos++);
|
||||
if (isNaN(slotMod.value)) {
|
||||
// Need to write the string with exactly four characters, so pad with whitespace
|
||||
buffer.write((" " + slotMod.value).slice(-4), curpos, 4);
|
||||
} else {
|
||||
buffer.writeInt32LE(slotMod.value, curpos);
|
||||
}
|
||||
if (isNaN(slotMod.value)) {
|
||||
// Need to write the string with exactly four characters, so pad with whitespace
|
||||
buffer.write((' ' + slotMod.value).slice(-4), curpos, 4);
|
||||
} else {
|
||||
buffer.writeInt32LE(slotMod.value, curpos);
|
||||
}
|
||||
// const modification = _.find(Modifications.modifications, function(o) { return o.id === slotMod.id; });
|
||||
// console.log('ENCODE Slot ' + i + ': ' + modification.name + ' = ' + slotMod.value);
|
||||
curpos += 4;
|
||||
@@ -1414,7 +1414,7 @@ export default class Ship {
|
||||
* See updateModificationsString() for details of the structure.
|
||||
* @param {String} buffer Buffer holding modification info
|
||||
* @param {Array} modArr Modification array
|
||||
* @param {Array} bluprintArr Blueprint array
|
||||
* @param {Array} blueprintArr Blueprint array
|
||||
*/
|
||||
decodeModificationsStruct(buffer, modArr, blueprintArr) {
|
||||
let curpos = 0;
|
||||
@@ -1428,22 +1428,22 @@ export default class Ship {
|
||||
if (modificationId === 40) {
|
||||
// Type is special, in that it's a character string
|
||||
modificationValue = buffer.toString('utf8', curpos, curpos + 4).trim();
|
||||
} else {
|
||||
} else {
|
||||
modificationValue = buffer.readInt32LE(curpos);
|
||||
}
|
||||
}
|
||||
curpos += 4;
|
||||
// There are a number of 'special' modification IDs, check for them here
|
||||
if (modificationId === MODIFICATION_ID_BLUEPRINT) {
|
||||
// There are a number of 'special' modification IDs, check for them here
|
||||
if (modificationId === MODIFICATION_ID_BLUEPRINT) {
|
||||
blueprint = Object.assign(blueprint, _.find(Modifications.blueprints, function(o) { return o.id === modificationValue; }));
|
||||
} else if (modificationId === MODIFICATION_ID_GRADE) {
|
||||
} else if (modificationId === MODIFICATION_ID_GRADE) {
|
||||
blueprint.grade = modificationValue;
|
||||
} else if (modificationId === MODIFICATION_ID_SPECIAL) {
|
||||
} else if (modificationId === MODIFICATION_ID_SPECIAL) {
|
||||
blueprint.special = _.find(Modifications.specials, function(o) { return o.id === modificationValue; });
|
||||
} else {
|
||||
} else {
|
||||
const modification = _.find(Modifications.modifications, function(o) { return o.id === modificationId; });
|
||||
// console.log('DECODE Slot ' + slot + ': ' + modification.name + ' = ' + modificationValue);
|
||||
modifications[modification.name] = modificationValue;
|
||||
}
|
||||
}
|
||||
modificationId = buffer.readInt8(curpos++);
|
||||
}
|
||||
modArr[slot] = modifications;
|
||||
|
||||
@@ -277,29 +277,43 @@ export function shipFromJson(json) {
|
||||
function _addModifications(module, modifiers, blueprint, grade) {
|
||||
if (!modifiers || !modifiers.modifiers) return;
|
||||
|
||||
var special;
|
||||
let special;
|
||||
for (const i in modifiers.modifiers) {
|
||||
// Look up the modifiers to find what we need to do
|
||||
const modifierActions = Modifications.modifierActions[modifiers.modifiers[i].name];
|
||||
const value = modifiers.modifiers[i].value;
|
||||
// Some special modifications
|
||||
if (modifiers.modifiers[i].name === 'mod_weapon_clip_size_override') {
|
||||
// This is a numeric addition to the clip size, but we need to work it out in terms of being a percentage so
|
||||
// that it works the same as other modifications
|
||||
const origClip = module.clip || 1;
|
||||
module.setModValue('clip', ((modifiers.modifiers[i].value - origClip) / origClip) * 10000);
|
||||
} else if (modifiers.modifiers[i].name === 'mod_weapon_burst_size') {
|
||||
// This is an absolute number that acts as an override
|
||||
module.setModValue('burst', modifiers.modifiers[i].value * 100);
|
||||
} else if (modifiers.modifiers[i].name === 'mod_weapon_burst_rof') {
|
||||
// For some reason this is a non-normalised percentage (i.e. 12.23% is 12.23 value rather than 0.1223 as everywhere else), so fix that here
|
||||
module.setModValue('burstrof', modifiers.modifiers[i].value * 100);
|
||||
} else {
|
||||
// Look up the modifiers to find what we need to do
|
||||
const modifierActions = Modifications.modifierActions[modifiers.modifiers[i].name];
|
||||
const value = modifiers.modifiers[i].value;
|
||||
|
||||
// Carry out the required changes
|
||||
for (const action in modifierActions) {
|
||||
if (isNaN(modifierActions[action])) {
|
||||
module.setModValue(action, modifierActions[action]);
|
||||
} else {
|
||||
const actionValue = modifierActions[action] * value;
|
||||
let mod = module.getModValue(action) / 10000;
|
||||
if (!mod) {
|
||||
mod = 0;
|
||||
// Carry out the required changes
|
||||
for (const action in modifierActions) {
|
||||
if (isNaN(modifierActions[action])) {
|
||||
module.setModValue(action, modifierActions[action]);
|
||||
} else {
|
||||
const actionValue = modifierActions[action] * value;
|
||||
let mod = module.getModValue(action) / 10000;
|
||||
if (!mod) {
|
||||
mod = 0;
|
||||
}
|
||||
module.setModValue(action, ((1 + mod) * (1 + actionValue) - 1) * 10000);
|
||||
}
|
||||
module.setModValue(action, ((1 + mod) * (1 + actionValue) - 1) * 10000);
|
||||
}
|
||||
}
|
||||
|
||||
// Note the special if present
|
||||
if (modifiers.modifiers[i].name && modifiers.modifiers[i].name.startsWith('special_')) {
|
||||
special = Modifications.specials[modifiers.modifiers[i].name];
|
||||
special = Modifications.specials[modifiers.modifiers[i].name];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user