poi-plugin-lbas-bis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/i18n/en-US.json +56 -0
- package/i18n/ja-JP.json +56 -0
- package/i18n/zh-CN.json +56 -0
- package/i18n/zh-TW.json +56 -0
- package/index.js +558 -0
- package/package.json +40 -0
- package/src/air-power.js +183 -0
- package/src/damage.js +54 -0
- package/src/import-plan.js +31 -0
- package/src/optimizer.js +417 -0
- package/src/poi-data.js +154 -0
- package/src/simulator-calc.js +90 -0
- package/src/simulator-state.js +216 -0
- package/src/ui/BaseTable.js +134 -0
- package/src/ui/EnemyPanel.js +56 -0
- package/src/ui/OptimizerPanel.js +149 -0
- package/src/ui/SimulatorPanel.js +95 -0
- package/src/ui/WaveStatusTable.js +41 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const React = require('react');
|
|
4
|
+
|
|
5
|
+
const h = React.createElement;
|
|
6
|
+
|
|
7
|
+
function OptimizerPanel(props) {
|
|
8
|
+
const {
|
|
9
|
+
candidateMode,
|
|
10
|
+
equipmentCount,
|
|
11
|
+
theoreticalCount,
|
|
12
|
+
messages,
|
|
13
|
+
results,
|
|
14
|
+
onCandidateModeChange,
|
|
15
|
+
onOptimize,
|
|
16
|
+
onImportPlan,
|
|
17
|
+
t,
|
|
18
|
+
styles,
|
|
19
|
+
} = props;
|
|
20
|
+
|
|
21
|
+
return h(
|
|
22
|
+
'section',
|
|
23
|
+
{ style: styles.optimizerPanel },
|
|
24
|
+
h('h3', { style: styles.sectionTitle }, t('optimizerTitle')),
|
|
25
|
+
h(
|
|
26
|
+
'div',
|
|
27
|
+
{ style: styles.optimizerControls },
|
|
28
|
+
h(
|
|
29
|
+
'label',
|
|
30
|
+
{ style: styles.radioLabel },
|
|
31
|
+
h('input', {
|
|
32
|
+
type: 'radio',
|
|
33
|
+
name: 'candidateMode',
|
|
34
|
+
value: 'owned',
|
|
35
|
+
checked: candidateMode !== 'theoretical',
|
|
36
|
+
onChange: () => onCandidateModeChange('owned'),
|
|
37
|
+
}),
|
|
38
|
+
t('ownedOnly'),
|
|
39
|
+
),
|
|
40
|
+
h(
|
|
41
|
+
'label',
|
|
42
|
+
{ style: styles.radioLabel },
|
|
43
|
+
h('input', {
|
|
44
|
+
type: 'radio',
|
|
45
|
+
name: 'candidateMode',
|
|
46
|
+
value: 'theoretical',
|
|
47
|
+
checked: candidateMode === 'theoretical',
|
|
48
|
+
onChange: () => onCandidateModeChange('theoretical'),
|
|
49
|
+
}),
|
|
50
|
+
t('includeMissing'),
|
|
51
|
+
),
|
|
52
|
+
h('button', { type: 'button', onClick: onOptimize, style: styles.primaryButton }, t('optimize')),
|
|
53
|
+
h('span', { style: styles.meta }, `${t('availablePlanes')}: ${equipmentCount} / ${t('candidatePlanes')}: ${theoreticalCount}`),
|
|
54
|
+
),
|
|
55
|
+
renderMessages(messages, styles),
|
|
56
|
+
renderResults({ results, onImportPlan, t, styles }),
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function renderMessages(messages, styles) {
|
|
61
|
+
if (!messages.length) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return h(
|
|
65
|
+
'ul',
|
|
66
|
+
{ style: styles.messages },
|
|
67
|
+
messages.map((message) => h('li', { key: message }, message)),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function renderResults({ results, onImportPlan, t, styles }) {
|
|
72
|
+
if (!results.length) {
|
|
73
|
+
return h(
|
|
74
|
+
'table',
|
|
75
|
+
{ style: styles.table },
|
|
76
|
+
h(
|
|
77
|
+
'thead',
|
|
78
|
+
null,
|
|
79
|
+
h(
|
|
80
|
+
'tr',
|
|
81
|
+
null,
|
|
82
|
+
h('th', { style: styles.th }, t('plan')),
|
|
83
|
+
h('th', { style: styles.th }, t('sixWaveState')),
|
|
84
|
+
h('th', { style: styles.th }, t('damagePower')),
|
|
85
|
+
h('th', { style: styles.th }, t('missingEquipment')),
|
|
86
|
+
h('th', { style: styles.th }, t('importToSimulator')),
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
h('tbody', null, h('tr', null, h('td', { colSpan: 5, style: styles.emptyCell }, t('noResult')))),
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return h(
|
|
94
|
+
'div',
|
|
95
|
+
{ style: styles.results },
|
|
96
|
+
results.map((plan, planIndex) =>
|
|
97
|
+
h(
|
|
98
|
+
'section',
|
|
99
|
+
{ key: `plan-${planIndex}`, style: styles.plan },
|
|
100
|
+
h(
|
|
101
|
+
'div',
|
|
102
|
+
{ style: styles.planHeader },
|
|
103
|
+
h('strong', null, `${t('plan')} ${planIndex + 1}`),
|
|
104
|
+
h('span', null, `${t('damagePower')} ${plan.totalDamagePower}`),
|
|
105
|
+
h('span', null, `${t('worstMargin')} ${plan.worstMargin}`),
|
|
106
|
+
h('button', { type: 'button', onClick: () => onImportPlan(plan), style: styles.button }, t('importToSimulator')),
|
|
107
|
+
),
|
|
108
|
+
h('div', { style: styles.planSummary }, formatMissing(plan.missingEquipment, t)),
|
|
109
|
+
h(
|
|
110
|
+
'div',
|
|
111
|
+
{ style: styles.waves },
|
|
112
|
+
plan.waves.map((wave) =>
|
|
113
|
+
h(
|
|
114
|
+
'span',
|
|
115
|
+
{ key: wave.waveIndex, style: styles.wave },
|
|
116
|
+
`${format(t('wave'), { index: wave.waveIndex + 1 })}: ${t(wave.state.key)} / ${t('targetState')} ${t(wave.targetState)} / ${t('airPower')} ${wave.airPower}`,
|
|
117
|
+
),
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
...plan.bases.map((base, baseIndex) =>
|
|
121
|
+
h(
|
|
122
|
+
'ol',
|
|
123
|
+
{ key: `base-${baseIndex}`, style: styles.loadout },
|
|
124
|
+
base.loadout.map((item) =>
|
|
125
|
+
h(
|
|
126
|
+
'li',
|
|
127
|
+
{ key: item.instanceId, style: item.available === false ? styles.missingItem : null },
|
|
128
|
+
`${item.name} #${item.instanceId} · ${t('airPower')} ${item.antiAir} · ${t('radius')} ${item.radius}`,
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
),
|
|
132
|
+
),
|
|
133
|
+
),
|
|
134
|
+
),
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function formatMissing(missingEquipment, t) {
|
|
139
|
+
if (!missingEquipment || !missingEquipment.length) {
|
|
140
|
+
return `${t('missingEquipment')}: -`;
|
|
141
|
+
}
|
|
142
|
+
return `${t('missingEquipment')}: ${missingEquipment.map((item) => `${item.name} x${item.count}`).join(', ')}`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function format(template, values) {
|
|
146
|
+
return String(template).replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? '');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = OptimizerPanel;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const React = require('react');
|
|
4
|
+
const BaseTable = require('./BaseTable');
|
|
5
|
+
const EnemyPanel = require('./EnemyPanel');
|
|
6
|
+
const WaveStatusTable = require('./WaveStatusTable');
|
|
7
|
+
|
|
8
|
+
const h = React.createElement;
|
|
9
|
+
|
|
10
|
+
function SimulatorPanel(props) {
|
|
11
|
+
const {
|
|
12
|
+
simulator,
|
|
13
|
+
summary,
|
|
14
|
+
equipment,
|
|
15
|
+
onBaseCountChange,
|
|
16
|
+
onTargetRadiusChange,
|
|
17
|
+
onEnemyAirChange,
|
|
18
|
+
onSlotPlaneChange,
|
|
19
|
+
onSlotLockChange,
|
|
20
|
+
onWaveTargetChange,
|
|
21
|
+
onClear,
|
|
22
|
+
t,
|
|
23
|
+
styles,
|
|
24
|
+
} = props;
|
|
25
|
+
|
|
26
|
+
return h(
|
|
27
|
+
'section',
|
|
28
|
+
{ style: styles.simulatorPanel },
|
|
29
|
+
h('h2', { style: styles.title }, t('simulatorTitle')),
|
|
30
|
+
h(
|
|
31
|
+
'div',
|
|
32
|
+
{ style: styles.simulatorGrid },
|
|
33
|
+
h(
|
|
34
|
+
'div',
|
|
35
|
+
null,
|
|
36
|
+
h(
|
|
37
|
+
'div',
|
|
38
|
+
{ style: styles.toolbar },
|
|
39
|
+
h(
|
|
40
|
+
'label',
|
|
41
|
+
{ style: styles.fieldInline },
|
|
42
|
+
h('span', null, t('targetRadius')),
|
|
43
|
+
h('input', {
|
|
44
|
+
type: 'number',
|
|
45
|
+
min: 1,
|
|
46
|
+
value: simulator.targetRadius,
|
|
47
|
+
onChange: (event) => onTargetRadiusChange(Number(event.target.value)),
|
|
48
|
+
style: styles.numberInput,
|
|
49
|
+
}),
|
|
50
|
+
),
|
|
51
|
+
h(
|
|
52
|
+
'label',
|
|
53
|
+
{ style: styles.fieldInline },
|
|
54
|
+
h('span', null, t('baseCount')),
|
|
55
|
+
h(
|
|
56
|
+
'select',
|
|
57
|
+
{
|
|
58
|
+
value: simulator.baseCount,
|
|
59
|
+
onChange: (event) => onBaseCountChange(Number(event.target.value)),
|
|
60
|
+
style: styles.smallSelect,
|
|
61
|
+
},
|
|
62
|
+
[1, 2, 3].map((count) => h('option', { key: count, value: count }, count)),
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
h('span', { style: styles.meta }, `${t('displayWaves')}: ${simulator.baseCount * 2}`),
|
|
66
|
+
h('button', { type: 'button', onClick: onClear, style: styles.button }, t('clearComposition')),
|
|
67
|
+
),
|
|
68
|
+
h(BaseTable, {
|
|
69
|
+
bases: simulator.bases,
|
|
70
|
+
equipment,
|
|
71
|
+
summaries: summary.bases,
|
|
72
|
+
onSlotPlaneChange,
|
|
73
|
+
onSlotLockChange,
|
|
74
|
+
t,
|
|
75
|
+
styles,
|
|
76
|
+
}),
|
|
77
|
+
h(WaveStatusTable, {
|
|
78
|
+
waves: summary.waves,
|
|
79
|
+
onWaveTargetChange,
|
|
80
|
+
t,
|
|
81
|
+
styles,
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
h(EnemyPanel, {
|
|
85
|
+
enemy: simulator.enemy,
|
|
86
|
+
lines: summary.enemyAirLines,
|
|
87
|
+
onEnemyAirChange,
|
|
88
|
+
t,
|
|
89
|
+
styles,
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = SimulatorPanel;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const React = require('react');
|
|
4
|
+
|
|
5
|
+
const h = React.createElement;
|
|
6
|
+
const STATE_OPTIONS = ['denial', 'parity', 'superiority', 'supremacy'];
|
|
7
|
+
|
|
8
|
+
function WaveStatusTable(props) {
|
|
9
|
+
const { waves, onWaveTargetChange, t, styles } = props;
|
|
10
|
+
return h(
|
|
11
|
+
'div',
|
|
12
|
+
{ style: styles.wavePanel },
|
|
13
|
+
h(
|
|
14
|
+
'div',
|
|
15
|
+
{ style: styles.waveList },
|
|
16
|
+
waves.map((wave) =>
|
|
17
|
+
h(
|
|
18
|
+
'label',
|
|
19
|
+
{ key: `wave-${wave.waveIndex}`, style: styles.waveField },
|
|
20
|
+
h('span', null, format(t('wave'), { index: wave.waveIndex + 1 })),
|
|
21
|
+
h(
|
|
22
|
+
'select',
|
|
23
|
+
{
|
|
24
|
+
value: wave.targetState,
|
|
25
|
+
onChange: (event) => onWaveTargetChange(wave.waveIndex, event.target.value),
|
|
26
|
+
style: styles.smallSelect,
|
|
27
|
+
},
|
|
28
|
+
STATE_OPTIONS.map((option) => h('option', { key: option, value: option }, t(option))),
|
|
29
|
+
),
|
|
30
|
+
h('strong', { style: wave.fulfilled ? styles.goodState : styles.badState }, t(wave.state.key)),
|
|
31
|
+
),
|
|
32
|
+
),
|
|
33
|
+
),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function format(template, values) {
|
|
38
|
+
return String(template).replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? '');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = WaveStatusTable;
|