poi-plugin-leveling-plan 0.0.1 → 0.0.2
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/assets/icon/75.png +0 -0
- package/assets/icon/77.png +0 -0
- package/assets/icon/78.png +0 -0
- package/assets/icon/94.png +0 -0
- package/assets/icon/useitem.svg +107 -0
- package/assets/kaisou_materials.json +4881 -0
- package/assets/main.css +265 -1
- package/i18n/en-US.json +8 -1
- package/i18n/ja-JP.json +8 -1
- package/i18n/zh-CN.json +8 -1
- package/i18n/zh-TW.json +8 -1
- package/index.js +21 -1
- package/package.json +1 -1
- package/services/battle-observer.js +59 -0
- package/utils/kaisou-cost.js +269 -0
- package/views/components/map-selector.js +119 -85
- package/views/components/plan-form.js +31 -1
- package/views/components/plan-item.js +101 -6
- package/views/components/plan-list.js +29 -12
- package/views/components/plan-settings.js +54 -5
- package/views/components/useitem-icon.js +87 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.getTotalShortageCount = exports.calcAllShortages = exports.calcShortage = exports.getShipRemodelCost = exports.countRemodelNodesInRange = exports.getRemodelLevelsForShip = exports.getRemodelChainForShip = exports.parseShipMaterials = exports.getShipMaterials = exports.multiplyCost = exports.addCost = exports.emptyCost = exports.RESOURCE_INDEX = void 0;
|
|
5
|
+
|
|
6
|
+
var _lodash = _interopRequireDefault(require("lodash"));
|
|
7
|
+
|
|
8
|
+
var _constants = require("./constants");
|
|
9
|
+
|
|
10
|
+
var _kaisou_materials = _interopRequireDefault(require("../assets/kaisou_materials.json"));
|
|
11
|
+
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
|
|
14
|
+
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
15
|
+
|
|
16
|
+
const KAISOU_ITEM_ID = {
|
|
17
|
+
drawing: 58,
|
|
18
|
+
catapult: 65,
|
|
19
|
+
report: 78,
|
|
20
|
+
devkit: 3,
|
|
21
|
+
buildkit: 2,
|
|
22
|
+
aviation: 77,
|
|
23
|
+
hokoheso: 75,
|
|
24
|
+
arms: 94
|
|
25
|
+
};
|
|
26
|
+
const RESOURCE_INDEX = {
|
|
27
|
+
fuel: 0,
|
|
28
|
+
ammo: 1,
|
|
29
|
+
steel: 2,
|
|
30
|
+
bauxite: 3,
|
|
31
|
+
buildkit: 4,
|
|
32
|
+
bucket: 5,
|
|
33
|
+
devmat: 6,
|
|
34
|
+
screw: 7
|
|
35
|
+
};
|
|
36
|
+
exports.RESOURCE_INDEX = RESOURCE_INDEX;
|
|
37
|
+
|
|
38
|
+
const emptyCost = () => ({
|
|
39
|
+
ammo: 0,
|
|
40
|
+
steel: 0,
|
|
41
|
+
consumable: {},
|
|
42
|
+
equipment: {}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
exports.emptyCost = emptyCost;
|
|
46
|
+
|
|
47
|
+
const addCost = (a, b) => {
|
|
48
|
+
const addMap = (mapA, mapB) => {
|
|
49
|
+
const result = _extends({}, mapA);
|
|
50
|
+
|
|
51
|
+
Object.keys(mapB).forEach(key => {
|
|
52
|
+
result[key] = (result[key] || 0) + mapB[key];
|
|
53
|
+
});
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
ammo: (a.ammo || 0) + (b.ammo || 0),
|
|
59
|
+
steel: (a.steel || 0) + (b.steel || 0),
|
|
60
|
+
consumable: addMap(a.consumable || {}, b.consumable || {}),
|
|
61
|
+
equipment: addMap(a.equipment || {}, b.equipment || {})
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
exports.addCost = addCost;
|
|
66
|
+
|
|
67
|
+
const multiplyCost = (cost, multiplier) => {
|
|
68
|
+
const m = Number(multiplier || 0);
|
|
69
|
+
if (m <= 0) return emptyCost();
|
|
70
|
+
|
|
71
|
+
const multiplyMap = map => {
|
|
72
|
+
const result = {};
|
|
73
|
+
Object.keys(map).forEach(key => {
|
|
74
|
+
result[key] = map[key] * m;
|
|
75
|
+
});
|
|
76
|
+
return result;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
ammo: (cost.ammo || 0) * m,
|
|
81
|
+
steel: (cost.steel || 0) * m,
|
|
82
|
+
consumable: multiplyMap(cost.consumable || {}),
|
|
83
|
+
equipment: multiplyMap(cost.equipment || {})
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
exports.multiplyCost = multiplyCost;
|
|
88
|
+
|
|
89
|
+
const getShipMaterials = shipMasterId => {
|
|
90
|
+
return _kaisou_materials.default[String(shipMasterId)] || null;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
exports.getShipMaterials = getShipMaterials;
|
|
94
|
+
|
|
95
|
+
const parseShipMaterials = materialsData => {
|
|
96
|
+
if (!materialsData) return emptyCost();
|
|
97
|
+
const result = emptyCost();
|
|
98
|
+
result.ammo = Number(materialsData.ammo || 0);
|
|
99
|
+
result.steel = Number(materialsData.steel || 0);
|
|
100
|
+
|
|
101
|
+
if (Array.isArray(materialsData.consumable)) {
|
|
102
|
+
materialsData.consumable.forEach(([itemId, count]) => {
|
|
103
|
+
result.consumable[String(itemId)] = (result.consumable[String(itemId)] || 0) + count;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (Array.isArray(materialsData.equipment)) {
|
|
108
|
+
materialsData.equipment.forEach(([equipId, count]) => {
|
|
109
|
+
result.equipment[String(equipId)] = (result.equipment[String(equipId)] || 0) + count;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return result;
|
|
114
|
+
}; // 直接从当前舰船往后遍历,不需要往前找起点
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
exports.parseShipMaterials = parseShipMaterials;
|
|
118
|
+
|
|
119
|
+
const getRemodelChainForShip = (shipMasterId, $ships) => {
|
|
120
|
+
if (!$ships || !$ships[shipMasterId]) return [shipMasterId];
|
|
121
|
+
const chain = [shipMasterId];
|
|
122
|
+
const visited = new Set([shipMasterId]);
|
|
123
|
+
let current = shipMasterId;
|
|
124
|
+
let iterations = 0;
|
|
125
|
+
const MAX_ITERATIONS = 20; // 防止无限循环
|
|
126
|
+
|
|
127
|
+
while (iterations < MAX_ITERATIONS) {
|
|
128
|
+
var _$ships$current;
|
|
129
|
+
|
|
130
|
+
iterations++;
|
|
131
|
+
const next = +(((_$ships$current = $ships[current]) === null || _$ships$current === void 0 ? void 0 : _$ships$current.api_aftershipid) || 0);
|
|
132
|
+
if (next <= 0 || visited.has(next)) break;
|
|
133
|
+
visited.add(next);
|
|
134
|
+
chain.push(next);
|
|
135
|
+
current = next;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return chain;
|
|
139
|
+
}; // 直接往后遍历获取改造等级
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
exports.getRemodelChainForShip = getRemodelChainForShip;
|
|
143
|
+
|
|
144
|
+
const getRemodelLevelsForShip = (shipMasterId, $ships) => {
|
|
145
|
+
if (!$ships || !$ships[shipMasterId]) return [];
|
|
146
|
+
const levels = [];
|
|
147
|
+
const visited = new Set();
|
|
148
|
+
let current = shipMasterId;
|
|
149
|
+
let iterations = 0;
|
|
150
|
+
const MAX_ITERATIONS = 20; // 防止无限循环
|
|
151
|
+
|
|
152
|
+
while (iterations < MAX_ITERATIONS) {
|
|
153
|
+
var _$ships$current2, _$ships$nextId;
|
|
154
|
+
|
|
155
|
+
iterations++;
|
|
156
|
+
const nextId = +(((_$ships$current2 = $ships[current]) === null || _$ships$current2 === void 0 ? void 0 : _$ships$current2.api_aftershipid) || 0);
|
|
157
|
+
if (nextId <= 0 || visited.has(nextId)) break;
|
|
158
|
+
visited.add(nextId);
|
|
159
|
+
const nextLv = +(((_$ships$nextId = $ships[nextId]) === null || _$ships$nextId === void 0 ? void 0 : _$ships$nextId.api_afterlv) || 0);
|
|
160
|
+
|
|
161
|
+
if (nextLv > 0 && nextLv < 200) {
|
|
162
|
+
// 过滤异常值
|
|
163
|
+
levels.push(nextLv);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
current = nextId;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (levels.length === 0) return [];
|
|
170
|
+
levels.sort((a, b) => a - b);
|
|
171
|
+
const lastLv = levels[levels.length - 1]; // 确保 MAX_LEVEL 是有效值
|
|
172
|
+
|
|
173
|
+
const maxLvl = typeof _constants.MAX_LEVEL === 'number' && _constants.MAX_LEVEL > 0 ? _constants.MAX_LEVEL : 100;
|
|
174
|
+
|
|
175
|
+
if (lastLv < 100) {
|
|
176
|
+
return [...levels, 99, maxLvl];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return [...levels, maxLvl];
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
exports.getRemodelLevelsForShip = getRemodelLevelsForShip;
|
|
183
|
+
|
|
184
|
+
const countRemodelNodesInRange = (shipMasterId, fromLevel, toLevel, $ships) => {
|
|
185
|
+
if (fromLevel >= toLevel) return 0;
|
|
186
|
+
const levels = getRemodelLevelsForShip(shipMasterId, $ships);
|
|
187
|
+
if (levels.length === 0) return 0;
|
|
188
|
+
return levels.filter(lv => lv > fromLevel && lv <= toLevel).length;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
exports.countRemodelNodesInRange = countRemodelNodesInRange;
|
|
192
|
+
|
|
193
|
+
const getShipRemodelCost = (shipMasterId, fromLevel, toLevel, $ships) => {
|
|
194
|
+
if (!shipMasterId || fromLevel >= toLevel) return emptyCost();
|
|
195
|
+
const chain = getRemodelChainForShip(shipMasterId, $ships);
|
|
196
|
+
const levels = getRemodelLevelsForShip(shipMasterId, $ships);
|
|
197
|
+
if (levels.length === 0) return emptyCost();
|
|
198
|
+
let totalCost = emptyCost(); // 遍历改造等级,找出需要改造的节点
|
|
199
|
+
|
|
200
|
+
for (let i = 0; i < levels.length; i++) {
|
|
201
|
+
const targetLv = levels[i];
|
|
202
|
+
if (targetLv <= fromLevel || targetLv > toLevel) continue; // 改造前的舰船是 chain[i]
|
|
203
|
+
|
|
204
|
+
const shipIdBeforeRemodel = chain[i];
|
|
205
|
+
const materials = getShipMaterials(shipIdBeforeRemodel);
|
|
206
|
+
|
|
207
|
+
if (materials) {
|
|
208
|
+
const parsed = parseShipMaterials(materials);
|
|
209
|
+
totalCost = addCost(totalCost, parsed);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return totalCost;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
exports.getShipRemodelCost = getShipRemodelCost;
|
|
217
|
+
|
|
218
|
+
const calcShortage = (required, available) => {
|
|
219
|
+
const req = Number(required || 0);
|
|
220
|
+
const avail = Number(available || 0);
|
|
221
|
+
return {
|
|
222
|
+
required: req,
|
|
223
|
+
available: avail,
|
|
224
|
+
gap: Math.max(0, req - avail)
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
exports.calcShortage = calcShortage;
|
|
229
|
+
|
|
230
|
+
const calcAllShortages = (totalCost, resources, useitems, equips) => {
|
|
231
|
+
const resourcesArr = Array.isArray(resources) ? resources : [];
|
|
232
|
+
const shortages = {
|
|
233
|
+
ammo: calcShortage(totalCost.ammo, resourcesArr[RESOURCE_INDEX.ammo]),
|
|
234
|
+
steel: calcShortage(totalCost.steel, resourcesArr[RESOURCE_INDEX.steel]),
|
|
235
|
+
devmat: calcShortage(totalCost.consumable[KAISOU_ITEM_ID.devkit] || 0, resourcesArr[RESOURCE_INDEX.devmat]),
|
|
236
|
+
buildkit: calcShortage(totalCost.consumable[KAISOU_ITEM_ID.buildkit] || 0, resourcesArr[RESOURCE_INDEX.buildkit]),
|
|
237
|
+
consumable: {},
|
|
238
|
+
equipment: {}
|
|
239
|
+
};
|
|
240
|
+
Object.entries(totalCost.consumable || {}).forEach(([itemId, required]) => {
|
|
241
|
+
const available = _lodash.default.get(useitems, [itemId, 'api_count'], 0);
|
|
242
|
+
|
|
243
|
+
shortages.consumable[itemId] = calcShortage(required, available);
|
|
244
|
+
});
|
|
245
|
+
Object.entries(totalCost.equipment || {}).forEach(([equipId, required]) => {
|
|
246
|
+
const available = _lodash.default.get(equips, [equipId, 'length'], 0);
|
|
247
|
+
|
|
248
|
+
shortages.equipment[equipId] = calcShortage(required, available);
|
|
249
|
+
});
|
|
250
|
+
return shortages;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
exports.calcAllShortages = calcAllShortages;
|
|
254
|
+
|
|
255
|
+
const getTotalShortageCount = shortages => {
|
|
256
|
+
var _shortages$ammo, _shortages$steel, _shortages$devmat, _shortages$buildkit;
|
|
257
|
+
|
|
258
|
+
let count = 0;
|
|
259
|
+
if (((_shortages$ammo = shortages.ammo) === null || _shortages$ammo === void 0 ? void 0 : _shortages$ammo.gap) > 0) count++;
|
|
260
|
+
if (((_shortages$steel = shortages.steel) === null || _shortages$steel === void 0 ? void 0 : _shortages$steel.gap) > 0) count++;
|
|
261
|
+
if (((_shortages$devmat = shortages.devmat) === null || _shortages$devmat === void 0 ? void 0 : _shortages$devmat.gap) > 0) count++;
|
|
262
|
+
if (((_shortages$buildkit = shortages.buildkit) === null || _shortages$buildkit === void 0 ? void 0 : _shortages$buildkit.gap) > 0) count++;
|
|
263
|
+
Object.values(shortages.consumable || {}).forEach(s => {
|
|
264
|
+
if (s.gap > 0) count++;
|
|
265
|
+
});
|
|
266
|
+
return count;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
exports.getTotalShortageCount = getTotalShortageCount;
|
|
@@ -5,8 +5,6 @@ exports.default = void 0;
|
|
|
5
5
|
|
|
6
6
|
var _react = _interopRequireWildcard(require("react"));
|
|
7
7
|
|
|
8
|
-
var _reactBootstrap = require("react-bootstrap");
|
|
9
|
-
|
|
10
8
|
var _core = require("@blueprintjs/core");
|
|
11
9
|
|
|
12
10
|
var _select = require("@blueprintjs/select");
|
|
@@ -33,92 +31,38 @@ const {
|
|
|
33
31
|
__
|
|
34
32
|
} = window.i18n['poi-plugin-leveling-plan'];
|
|
35
33
|
|
|
36
|
-
const MapMultiSelect = _select.MultiSelect.ofType(); //
|
|
34
|
+
const MapMultiSelect = _select.MultiSelect.ofType(); // 按世界分组
|
|
35
|
+
|
|
37
36
|
|
|
37
|
+
const getWorldGroups = () => {
|
|
38
|
+
const groups = {};
|
|
39
|
+
Object.keys(_constants.EXP_BY_POI_DB).sort((a, b) => Number(a) - Number(b)).forEach(id => {
|
|
40
|
+
const world = Math.floor(Number(id) / 10);
|
|
41
|
+
if (!groups[world]) groups[world] = [];
|
|
42
|
+
groups[world].push(id);
|
|
43
|
+
});
|
|
44
|
+
return groups;
|
|
45
|
+
};
|
|
38
46
|
|
|
39
47
|
class MapSelector extends _react.Component {
|
|
40
48
|
constructor(props) {
|
|
41
49
|
super(props);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
writable: true,
|
|
46
|
-
value: mapId => {
|
|
47
|
-
const {
|
|
48
|
-
value = [],
|
|
49
|
-
onChange
|
|
50
|
-
} = this.props;
|
|
51
|
-
|
|
52
|
-
if (value.includes(mapId)) {
|
|
53
|
-
// 取消选择
|
|
54
|
-
onChange(value.filter(id => id !== mapId));
|
|
55
|
-
} else {
|
|
56
|
-
// 添加选择
|
|
57
|
-
onChange([...value, mapId]);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
Object.defineProperty(this, "handleItemSelect", {
|
|
62
|
-
configurable: true,
|
|
63
|
-
enumerable: true,
|
|
64
|
-
writable: true,
|
|
65
|
-
value: mapId => {
|
|
66
|
-
this.toggleMap(mapId);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
Object.defineProperty(this, "handleTagRemove", {
|
|
70
|
-
configurable: true,
|
|
71
|
-
enumerable: true,
|
|
72
|
-
writable: true,
|
|
73
|
-
value: mapId => {
|
|
74
|
-
const {
|
|
75
|
-
value = [],
|
|
76
|
-
onChange
|
|
77
|
-
} = this.props;
|
|
78
|
-
onChange(value.filter(id => id !== mapId));
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
Object.defineProperty(this, "renderMap", {
|
|
82
|
-
configurable: true,
|
|
83
|
-
enumerable: true,
|
|
84
|
-
writable: true,
|
|
85
|
-
value: (mapId, {
|
|
86
|
-
handleClick,
|
|
87
|
-
modifiers
|
|
88
|
-
}) => {
|
|
89
|
-
const {
|
|
90
|
-
value = []
|
|
91
|
-
} = this.props;
|
|
92
|
-
const isSelected = value.includes(mapId);
|
|
93
|
-
return _react.default.createElement(_core.MenuItem, {
|
|
94
|
-
key: mapId,
|
|
95
|
-
text: (0, _planHelpers.formatMapName)(mapId),
|
|
96
|
-
onClick: handleClick,
|
|
97
|
-
active: modifiers.active,
|
|
98
|
-
shouldDismissPopover: false,
|
|
99
|
-
icon: isSelected ? 'tick' : 'blank'
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
Object.defineProperty(this, "renderTag", {
|
|
104
|
-
configurable: true,
|
|
105
|
-
enumerable: true,
|
|
106
|
-
writable: true,
|
|
107
|
-
value: mapId => {
|
|
108
|
-
return (0, _planHelpers.formatMapName)(mapId);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
50
|
+
|
|
51
|
+
_initialiseProps.call(this);
|
|
52
|
+
|
|
111
53
|
this.state = {
|
|
112
|
-
isOpen: false
|
|
54
|
+
isOpen: false,
|
|
55
|
+
activeWorld: null
|
|
113
56
|
};
|
|
57
|
+
this.worldGroups = getWorldGroups();
|
|
58
|
+
const worlds = Object.keys(this.worldGroups).sort((a, b) => Number(a) - Number(b));
|
|
59
|
+
this.state.activeWorld = worlds[0] || null;
|
|
114
60
|
}
|
|
115
61
|
|
|
116
62
|
render() {
|
|
117
63
|
const {
|
|
118
|
-
value = []
|
|
119
|
-
|
|
120
|
-
} = this.props; // 所有海图
|
|
121
|
-
|
|
64
|
+
value = []
|
|
65
|
+
} = this.props;
|
|
122
66
|
const allMapIds = Object.keys(_constants.EXP_BY_POI_DB);
|
|
123
67
|
return _react.default.createElement("div", {
|
|
124
68
|
className: "map-selector"
|
|
@@ -128,10 +72,8 @@ class MapSelector extends _react.Component {
|
|
|
128
72
|
items: allMapIds,
|
|
129
73
|
selectedItems: value.filter(id => allMapIds.includes(id)),
|
|
130
74
|
onItemSelect: this.handleItemSelect,
|
|
131
|
-
itemRenderer:
|
|
132
|
-
|
|
133
|
-
isOpen: !this.state.isOpen
|
|
134
|
-
}),
|
|
75
|
+
itemRenderer: () => null,
|
|
76
|
+
itemListRenderer: () => this.renderPopoverContent(),
|
|
135
77
|
tagRenderer: this.renderTag,
|
|
136
78
|
tagInputProps: {
|
|
137
79
|
onRemove: this.handleTagRemove,
|
|
@@ -147,20 +89,112 @@ class MapSelector extends _react.Component {
|
|
|
147
89
|
popoverProps: {
|
|
148
90
|
minimal: true,
|
|
149
91
|
usePortal: false,
|
|
150
|
-
isOpen: this.state.isOpen
|
|
92
|
+
isOpen: this.state.isOpen,
|
|
93
|
+
onClose: () => this.setState({
|
|
94
|
+
isOpen: false
|
|
95
|
+
}),
|
|
96
|
+
popoverClassName: 'map-selector-popover'
|
|
151
97
|
}
|
|
152
98
|
})));
|
|
153
99
|
}
|
|
154
100
|
|
|
155
|
-
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
var _initialiseProps = function () {
|
|
104
|
+
Object.defineProperty(this, "toggleMap", {
|
|
105
|
+
configurable: true,
|
|
106
|
+
enumerable: true,
|
|
107
|
+
writable: true,
|
|
108
|
+
value: mapId => {
|
|
109
|
+
const {
|
|
110
|
+
value = [],
|
|
111
|
+
onChange
|
|
112
|
+
} = this.props;
|
|
156
113
|
|
|
114
|
+
if (value.includes(mapId)) {
|
|
115
|
+
onChange(value.filter(id => id !== mapId));
|
|
116
|
+
} else {
|
|
117
|
+
onChange([...value, mapId]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
Object.defineProperty(this, "handleItemSelect", {
|
|
122
|
+
configurable: true,
|
|
123
|
+
enumerable: true,
|
|
124
|
+
writable: true,
|
|
125
|
+
value: mapId => {
|
|
126
|
+
this.toggleMap(mapId);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
Object.defineProperty(this, "handleTagRemove", {
|
|
130
|
+
configurable: true,
|
|
131
|
+
enumerable: true,
|
|
132
|
+
writable: true,
|
|
133
|
+
value: mapId => {
|
|
134
|
+
const {
|
|
135
|
+
value = [],
|
|
136
|
+
onChange
|
|
137
|
+
} = this.props;
|
|
138
|
+
onChange(value.filter(id => id !== mapId));
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
Object.defineProperty(this, "renderTag", {
|
|
142
|
+
configurable: true,
|
|
143
|
+
enumerable: true,
|
|
144
|
+
writable: true,
|
|
145
|
+
value: mapId => {
|
|
146
|
+
return (0, _planHelpers.formatMapName)(mapId);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
Object.defineProperty(this, "renderPopoverContent", {
|
|
150
|
+
configurable: true,
|
|
151
|
+
enumerable: true,
|
|
152
|
+
writable: true,
|
|
153
|
+
value: () => {
|
|
154
|
+
const {
|
|
155
|
+
value = []
|
|
156
|
+
} = this.props;
|
|
157
|
+
const {
|
|
158
|
+
activeWorld
|
|
159
|
+
} = this.state;
|
|
160
|
+
const worlds = Object.keys(this.worldGroups).sort((a, b) => Number(a) - Number(b));
|
|
161
|
+
return _react.default.createElement("div", {
|
|
162
|
+
className: "map-selector-tabs"
|
|
163
|
+
}, _react.default.createElement(_core.Tabs, {
|
|
164
|
+
id: "map-world-tabs",
|
|
165
|
+
selectedTabId: activeWorld,
|
|
166
|
+
onChange: id => this.setState({
|
|
167
|
+
activeWorld: id
|
|
168
|
+
}),
|
|
169
|
+
renderActiveTabPanelOnly: true,
|
|
170
|
+
vertical: true
|
|
171
|
+
}, worlds.map(world => _react.default.createElement(_core.Tab, {
|
|
172
|
+
key: world,
|
|
173
|
+
id: world,
|
|
174
|
+
title: `${world}`,
|
|
175
|
+
panel: _react.default.createElement("div", {
|
|
176
|
+
className: "map-selector-tab-panel"
|
|
177
|
+
}, this.worldGroups[world].map(mapId => {
|
|
178
|
+
const isSelected = value.includes(mapId);
|
|
179
|
+
return _react.default.createElement(_core.MenuItem, {
|
|
180
|
+
key: mapId,
|
|
181
|
+
text: (0, _planHelpers.formatMapName)(mapId),
|
|
182
|
+
icon: isSelected ? 'tick' : 'blank',
|
|
183
|
+
onClick: () => this.toggleMap(mapId),
|
|
184
|
+
shouldDismissPopover: false
|
|
185
|
+
});
|
|
186
|
+
}))
|
|
187
|
+
}))));
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
};
|
|
157
191
|
|
|
158
192
|
const mapStateToProps = (0, _reselect.createSelector)([_selectors.personalStatsSelector], personalStats => {
|
|
159
|
-
// 获取所有海图的经验数据
|
|
160
193
|
const allMapIds = Object.keys(_constants.EXP_BY_POI_DB);
|
|
161
194
|
const mapExpData = {};
|
|
162
195
|
allMapIds.forEach(mapId => {
|
|
163
|
-
|
|
196
|
+
const result = (0, _expCalculator.getMapExp)(mapId, personalStats, 30);
|
|
197
|
+
mapExpData[mapId] = result.exp || 0;
|
|
164
198
|
});
|
|
165
199
|
return {
|
|
166
200
|
mapExpData
|
|
@@ -21,6 +21,8 @@ var _selectors = require("../../utils/selectors");
|
|
|
21
21
|
|
|
22
22
|
var _planHelpers = require("../../utils/plan-helpers");
|
|
23
23
|
|
|
24
|
+
var _kaisouCost = require("../../utils/kaisou-cost");
|
|
25
|
+
|
|
24
26
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
27
|
|
|
26
28
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
|
|
@@ -96,7 +98,35 @@ class PlanForm extends _react.Component {
|
|
|
96
98
|
min: currentLevel + 1,
|
|
97
99
|
max: 185,
|
|
98
100
|
placeholder: __('Enter target level')
|
|
99
|
-
}), selectedShip &&
|
|
101
|
+
}), selectedShip && $ships && (() => {
|
|
102
|
+
const shipMasterId = selectedShip.api_ship_id;
|
|
103
|
+
const remodelLevels = (0, _kaisouCost.getRemodelLevelsForShip)(shipMasterId, $ships);
|
|
104
|
+
const startLv = parseInt(startLevel) || 0;
|
|
105
|
+
const filteredLevels = remodelLevels.filter(lv => lv > startLv);
|
|
106
|
+
if (filteredLevels.length === 0) return null;
|
|
107
|
+
return _react.default.createElement("div", {
|
|
108
|
+
className: "remodel-level-tags",
|
|
109
|
+
style: {
|
|
110
|
+
marginBottom: 8,
|
|
111
|
+
display: 'flex',
|
|
112
|
+
flexWrap: 'wrap',
|
|
113
|
+
gap: 5
|
|
114
|
+
}
|
|
115
|
+
}, filteredLevels.map(lv => _react.default.createElement("span", {
|
|
116
|
+
key: lv,
|
|
117
|
+
onClick: () => this.setState({
|
|
118
|
+
targetLevel: String(lv)
|
|
119
|
+
}),
|
|
120
|
+
style: {
|
|
121
|
+
cursor: 'pointer',
|
|
122
|
+
padding: '2px 8px',
|
|
123
|
+
backgroundColor: parseInt(targetLevel) === lv ? '#337ab7' : '#f0f0f0',
|
|
124
|
+
color: parseInt(targetLevel) === lv ? 'white' : '#333',
|
|
125
|
+
borderRadius: 3,
|
|
126
|
+
fontSize: 12
|
|
127
|
+
}
|
|
128
|
+
}, "lv", lv)));
|
|
129
|
+
})(), selectedShip && _react.default.createElement("p", {
|
|
100
130
|
className: "help-block"
|
|
101
131
|
}, __('Current level'), ": ", currentLevel)), _react.default.createElement(_reactBootstrap.FormGroup, null, _react.default.createElement(_reactBootstrap.ControlLabel, null, __('Maps')), _react.default.createElement(_mapSelector.default, {
|
|
102
132
|
value: maps,
|
|
@@ -7,24 +7,109 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
7
7
|
|
|
8
8
|
var _reactBootstrap = require("react-bootstrap");
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _icon = require("views/components/etc/icon");
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var _useitemIcon = require("./useitem-icon");
|
|
13
|
+
|
|
14
|
+
var _kaisouCost = require("../../utils/kaisou-cost");
|
|
15
|
+
|
|
16
|
+
var _lodash = _interopRequireDefault(require("lodash"));
|
|
13
17
|
|
|
14
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
19
|
|
|
16
20
|
const {
|
|
17
21
|
__
|
|
18
|
-
} = window.i18n['poi-plugin-leveling-plan'];
|
|
22
|
+
} = window.i18n['poi-plugin-leveling-plan'];
|
|
23
|
+
const {
|
|
24
|
+
__: __r
|
|
25
|
+
} = window.i18n.resources;
|
|
26
|
+
|
|
27
|
+
const RemodelCostDisplay = ({
|
|
28
|
+
cost,
|
|
29
|
+
resources,
|
|
30
|
+
useitems,
|
|
31
|
+
$useitems
|
|
32
|
+
}) => {
|
|
33
|
+
var _shortages$ammo, _shortages$steel;
|
|
34
|
+
|
|
35
|
+
if (!cost || cost.ammo === 0 && cost.steel === 0 && Object.keys(cost.consumable).length === 0) {
|
|
36
|
+
return _react.default.createElement("span", {
|
|
37
|
+
style: {
|
|
38
|
+
opacity: 0.5
|
|
39
|
+
}
|
|
40
|
+
}, __('No remodel required'));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const shortages = (0, _kaisouCost.calcAllShortages)(cost, resources, useitems || {}, {});
|
|
44
|
+
return _react.default.createElement("span", {
|
|
45
|
+
style: {
|
|
46
|
+
textAlign: 'right',
|
|
47
|
+
fontSize: '0.9em'
|
|
48
|
+
}
|
|
49
|
+
}, _react.default.createElement("span", {
|
|
50
|
+
style: {
|
|
51
|
+
display: 'inline-flex',
|
|
52
|
+
alignItems: 'center',
|
|
53
|
+
gap: '4px',
|
|
54
|
+
flexWrap: 'wrap'
|
|
55
|
+
}
|
|
56
|
+
}, cost.ammo > 0 && _react.default.createElement("span", null, _react.default.createElement(_icon.MaterialIcon, {
|
|
57
|
+
materialId: 2,
|
|
58
|
+
className: "material-icon-sm"
|
|
59
|
+
}), cost.ammo.toLocaleString(), ((_shortages$ammo = shortages.ammo) === null || _shortages$ammo === void 0 ? void 0 : _shortages$ammo.gap) > 0 && _react.default.createElement("span", {
|
|
60
|
+
style: {
|
|
61
|
+
color: '#d9534f'
|
|
62
|
+
}
|
|
63
|
+
}, "(-", shortages.ammo.gap.toLocaleString(), ")")), cost.steel > 0 && _react.default.createElement("span", null, _react.default.createElement(_icon.MaterialIcon, {
|
|
64
|
+
materialId: 3,
|
|
65
|
+
className: "material-icon-sm"
|
|
66
|
+
}), cost.steel.toLocaleString(), ((_shortages$steel = shortages.steel) === null || _shortages$steel === void 0 ? void 0 : _shortages$steel.gap) > 0 && _react.default.createElement("span", {
|
|
67
|
+
style: {
|
|
68
|
+
color: '#d9534f'
|
|
69
|
+
}
|
|
70
|
+
}, "(-", shortages.steel.gap.toLocaleString(), ")")), Object.keys(cost.consumable || {}).length > 0 && Object.entries(cost.consumable).map(([itemId, count]) => {
|
|
71
|
+
const shortage = _lodash.default.get(shortages, ['consumable', itemId, 'gap'], 0);
|
|
72
|
+
|
|
73
|
+
const numId = Number(itemId); // 建造资材(2) materialId=4,开发资材(3) materialId=6
|
|
74
|
+
|
|
75
|
+
const isMaterial = numId === 2 || numId === 3;
|
|
76
|
+
const materialId = numId === 2 ? 4 : 6;
|
|
77
|
+
return _react.default.createElement("span", {
|
|
78
|
+
key: itemId,
|
|
79
|
+
style: {
|
|
80
|
+
fontSize: '0.85em',
|
|
81
|
+
display: 'inline-flex',
|
|
82
|
+
alignItems: 'center',
|
|
83
|
+
gap: 2
|
|
84
|
+
}
|
|
85
|
+
}, isMaterial ? _react.default.createElement(_icon.MaterialIcon, {
|
|
86
|
+
materialId: materialId,
|
|
87
|
+
className: "material-icon-sm"
|
|
88
|
+
}) : _react.default.createElement(_useitemIcon.UseitemIcon, {
|
|
89
|
+
useitemId: numId,
|
|
90
|
+
className: "useitem-icon-sm"
|
|
91
|
+
}), count, shortage > 0 && _react.default.createElement("span", {
|
|
92
|
+
style: {
|
|
93
|
+
color: '#d9534f'
|
|
94
|
+
}
|
|
95
|
+
}, "(-", shortage, ")"));
|
|
96
|
+
})));
|
|
97
|
+
}; // 单个计划卡片组件
|
|
98
|
+
|
|
19
99
|
|
|
20
100
|
const PlanItem = ({
|
|
21
101
|
planDetail,
|
|
22
102
|
onEdit,
|
|
23
103
|
onDelete,
|
|
24
|
-
onComplete
|
|
104
|
+
onComplete,
|
|
105
|
+
$ships,
|
|
106
|
+
resources,
|
|
107
|
+
useitems,
|
|
108
|
+
$useitems
|
|
25
109
|
}) => {
|
|
26
110
|
if (!planDetail) return null;
|
|
27
111
|
const {
|
|
112
|
+
shipMasterId,
|
|
28
113
|
shipName,
|
|
29
114
|
startLv,
|
|
30
115
|
currentLv,
|
|
@@ -37,7 +122,8 @@ const PlanItem = ({
|
|
|
37
122
|
notes,
|
|
38
123
|
completed
|
|
39
124
|
} = planDetail;
|
|
40
|
-
|
|
125
|
+
const fromLevel = startLv === undefined ? currentLv : startLv;
|
|
126
|
+
const remodelCost = $ships && shipMasterId && fromLevel && targetLv ? (0, _kaisouCost.getShipRemodelCost)(shipMasterId, fromLevel, targetLv, $ships) : null;
|
|
41
127
|
return _react.default.createElement(_reactBootstrap.Panel, {
|
|
42
128
|
className: "plan-item"
|
|
43
129
|
}, _react.default.createElement(_reactBootstrap.Panel.Heading, null, _react.default.createElement("div", {
|
|
@@ -74,7 +160,16 @@ const PlanItem = ({
|
|
|
74
160
|
className: "exp-info"
|
|
75
161
|
}, __('Current EXP'), ": ", currentExp.toLocaleString(), " / ", targetTotalExp.toLocaleString()), _react.default.createElement("div", {
|
|
76
162
|
className: "exp-info"
|
|
77
|
-
}, __('Required EXP'), ": ", requiredExp.toLocaleString()
|
|
163
|
+
}, __('Required EXP'), ": ", requiredExp.toLocaleString(), remodelCost && _react.default.createElement("span", {
|
|
164
|
+
style: {
|
|
165
|
+
marginLeft: 15
|
|
166
|
+
}
|
|
167
|
+
}, _react.default.createElement(RemodelCostDisplay, {
|
|
168
|
+
cost: remodelCost,
|
|
169
|
+
resources: resources,
|
|
170
|
+
useitems: useitems,
|
|
171
|
+
$useitems: $useitems
|
|
172
|
+
})))), _react.default.createElement("div", {
|
|
78
173
|
className: "maps-section"
|
|
79
174
|
}, _react.default.createElement("div", {
|
|
80
175
|
className: "maps-label"
|