forked from kageroh/cond_checker
-
Notifications
You must be signed in to change notification settings - Fork 5
/
devtools.js
4308 lines (4151 loc) · 160 KB
/
devtools.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// -*- coding: utf-8 -*-
var $mst_ship = load_storage('mst_ship');
var $mst_slotitem = load_storage('mst_slotitem');
var $mst_slotitemeq = load_storage('mst_slotitemeq');
var $mst_mission = load_storage('mst_mission');
var $mst_mission_name_to_id = load_storage('mst_mission_name_to_id');
var $mst_useitem = load_storage('mst_useitem');
var $mst_mapinfo = load_storage('mst_mapinfo');
var $mst_maparea = load_storage('mst_maparea');
var $ship_list = load_storage('ship_list');
var $slotitem_list = load_storage('slotitem_list');
var $remodel_slotlist = load_storage('remodel_slotlist');
var $remodel_slotweek = load_storage('remodel_slotweek');
var $enemy_db = load_storage('enemy_db');
var $weekly = load_storage('weekly');
var $quest_clear = load_storage('quest_clear');
var $logbook = load_storage('logbook', []);
var $quest_list = load_storage('quest_list');
var $air_base = load_storage('air_base', []); // for noro6/kc-web
var $debug_battle_json = null;
var $debug_ship_names = [];
var $debug_api_name = '';
var $tmp_ship_id = -1000; // ドロップ艦の仮ID.
var $tmp_slot_id = -1000; // ドロップ艦装備の仮ID.
var $max_ship = 0;
var $max_slotitem = 0;
var $command_lv = 0;
var $combined_flag = 0;
var $fdeck_list = {};
var $ship_fdeck = {};
var $ship_escape = {}; // 護衛退避したshipidのマップ.
var $mapinfo_rank = {}; // 海域難易度 undefined:なし, 1:丁, 2:丙, 3:乙, 4:甲.
var $locked_ship_idset = {}; // ロック艦の艦種IDセット.
var $locked_ship_double = {}; // ロック艦のダブリ順番号マップ. [艦固有ID] := 1:一隻目, 2:二隻目, 3:三隻目...
var $next_mapinfo = null;
var $next_enemy = null;
var $is_boss = false;
var $is_next = false;
var $material = {
// [燃料,弾薬,鋼材,ボーキ, バーナー,バケツ,歯車,螺子]
mission: [0,0,0,0, 0,0,0,0], ///< 遠征累計.
quest : [0,0,0,0, 0,0,0,0], ///< 任務累計.
charge : [0,0,0,0, 0,0,0,0], ///< 補給累計.
ndock : [0,0,0,0, 0,0,0,0], ///< 入渠累計.
dropitem : [0,0,0,0, 0,0,0,0], ///< 道中資源累計.
autosupply : [0,0,0,0, 0,0,0,0], ///< 自然増加/轟沈回収累計.
createship : [0,0,0,0, 0,0,0,0], ///< 艦娘建造/改造累計.
createitem : [0,0,0,0, 0,0,0,0], ///< 装備開発累計.
remodelslot : [0,0,0,0, 0,0,0,0], ///< 装備改修累計.
destroyship : [0,0,0,0, 0,0,0,0], ///< 艦娘解体累計.
destroyitem : [0,0,0,0, 0,0,0,0], ///< 装備破棄累計.
now : [], ///< 現在資材. 初回は全項目undefinedとする.
beg : null, ///< 初期資材. 初回更新時にnowのコピーを保持する.
diff: "" ///< 変化量メッセージ.
};
var $material_sum = null;
var $quest_count = -1;
var $quest_exec_count = 0;
var $battle_count = 0;
var $ndock_list = {};
var $do_print_port_on_ndock = false;
var $do_print_port_on_slot_item = false;
var $kdock_list = {};
var $battle_api_data = null;
var $battle_deck_id = -1;
var $battle_log = [];
var $last_mission = {};
var $f_maxhps = null;
var $f_beginhps = null;
var $e_beginhps = null;
var $e_prevhps = null;
var $f_damage = 0;
var $e_lost_count = 0;
var $e_leader_lost = false;
var $e_combined = null;
var $guess_win_rank = '?';
var $guess_info_str = '';
var $pcDateTime = null;
var $svDateTime = null;
var $newship_slots = null;
var $enemy_formation = '';
var $enemy_ship_names = [];
var $log_daily = 0;
var $kaizou_list_orig = null;
var $convert_list_orig = null;
$quest_complete_daily = {
210 : 10, // (日)敵艦隊を10回邀撃せよ!
303 : 3, // (日)演習3回実施.
304 : 5, // (日)演習5回勝利.
402 : 3, // (日)遠征3回成功.
403 : 10, // (日)遠征10回成功.
503 : 5, // (日)艦隊大整備!5回.
504 : 15, // (日)艦隊酒保祭り!15回.
607 : 3, // (日)装備「開発」集中強化!
608 : 3, // (日)艦娘「建造」艦隊強化!
702 : 2, // (日)近代化改修成功2回.
9999: null // dummy
};
$quest_complete_weekly = {
302 : 20, // (週)大規模演習20回勝利.
404 : 30, // (週)大規模遠征30回成功.
613 : 24, // (週)資源の再利用24回.
703 : 15, // (週)近代化改修15回.
9999: null // dummy
};
//-------------------------------------------------------------------------
// Ship クラス.
function Ship(data, ship) {
this.p_cond = (ship) ? ship.c_cond : 49;
this.sortie_dn = (ship) ? ship.sortie_dn : 0;
this.c_cond = data.api_cond;
this.maxhp = data.api_maxhp;
this.nowhp = data.api_nowhp;
this.slot = data.api_slot; // []装備ID.
this.onslot = data.api_onslot; // []装備数.
this.bull = data.api_bull; // 弾薬.
this.fuel = data.api_fuel; // 燃料.
this.id = data.api_id; // 背番号.
this.lv = data.api_lv;
this.locked = data.api_locked;
this.ndock_time = data.api_ndock_time;
this.ndock_item = data.api_ndock_item; // 入渠消費量[燃料,鋼材].
this.ship_id = data.api_ship_id;
this.kyouka = data.api_kyouka; // 近代化改修による強化値[火力,雷装,対空,装甲,運].
this.karyoku = data.api_karyoku;
this.taiku = data.api_taiku;
this.taisen = data.api_taisen;
this.sakuteki = data.api_sakuteki;
this.nextlv = data.api_exp[1];
this.exp = data.api_exp;
this.slot_ex = data.api_slot_ex; // for noro6/kc-web
if (data.api_slot_ex > 0) { // api_slot_ex:: 0:増設スロットなし, -1:増設スロット空, 1以上:増設スロット装備ID.
this.slot.push(data.api_slot_ex);
}
if (data.api_sally_area !== null) { // お札情報 イベント中限定 0: 札なし, 1~ : 各種札
this.sally_area = data.api_sally_area;
}
}
Ship.prototype.name_lv = function() {
let name = ship_name(this.ship_id);
let dup = $locked_ship_double[this.id];
if (dup > 1) name += '#' + dup; // ダブリ番号を追加する.
return name + 'Lv' + this.lv;
};
Ship.prototype.fleet_name_lv = function() {
var name = this.name_lv();
var fdeck = $ship_fdeck[this.id];
if (fdeck) name = '(艦隊' + fdeck + ')' + name; // 頭に艦隊番号を付ける.
return name;
};
Ship.prototype.fleet_name_lv_afterlv = function() {
return this.fleet_name_lv() + '(' + $mst_ship[this.ship_id].api_afterlv + ')';
};
Ship.prototype.kira_cond_diff_name = function() {
return kira_name(this.c_cond) + this.c_cond + diff_name(this.c_cond, this.p_cond);
};
Ship.prototype.fuel_max = function() {
var max = $mst_ship[this.ship_id].api_fuel_max;
return max == null ? 0 : max; // if null or undefined then 0
};
Ship.prototype.bull_max = function() {
var max = $mst_ship[this.ship_id].api_bull_max;
return max == null ? 0 : max; // if null or undefined then 0
};
Ship.prototype.fuel_name = function() {
var max = $mst_ship[this.ship_id].api_fuel_max;
if (max && this.fuel < max) return percent_name(this.fuel, max);
return ''; // 100% or unknown
};
Ship.prototype.bull_name = function() {
var max = $mst_ship[this.ship_id].api_bull_max;
if (max && this.bull < max) return percent_name(this.bull, max);
return ''; // 100% or unknown
};
Ship.prototype.charge = function(data) { ///< 補給.
var d_fuel = data.api_fuel - this.fuel;
var d_bull = data.api_bull - this.bull;
if (this.lv > 99) { // ケッコンカッコカリ艦は消費量15%軽減.
d_fuel = Math.floor(d_fuel * 0.85);
d_bull = Math.floor(d_bull * 0.85);
}
this.fuel = data.api_fuel;
this.bull = data.api_bull;
this.onslot = data.api_onslot;
$material.charge[0] -= d_fuel;
$material.charge[1] -= d_bull;
};
Ship.prototype.highspeed_repair = function() { ///< 高速修復.
this.nowhp = this.maxhp;
this.ndock_time = 0;
delete $ndock_list[this.id];
};
Ship.prototype.can_kaizou = function() {
var afterlv = $mst_ship[this.ship_id].api_afterlv;
return afterlv && afterlv <= this.lv;
};
Ship.prototype.will_kaizou = function() {
var afterlv = $mst_ship[this.ship_id].api_afterlv;
return afterlv && afterlv > this.lv;
};
Ship.prototype.can_convert = function() {
if (this.can_kaizou()) {
let checked = {}; // 通過記録.
const current = $mst_ship[this.ship_id];
for (let after = $mst_ship[current.api_aftershipid]; after != null; after = $mst_ship[after.api_aftershipid]) {
if (after == current) return true;
if (checked[after.api_id]) break;
if (after.api_afterlv > this.lv) break;
checked[after.api_id] = true;
}
}
return false;
};
Ship.prototype.max_kyouka = function() {
var mst = $mst_ship[this.ship_id];
return [
mst.api_houg[1] - mst.api_houg[0], // 火力.
mst.api_raig[1] - mst.api_raig[0], // 雷装.
mst.api_tyku[1] - mst.api_tyku[0], // 対空.
mst.api_souk[1] - mst.api_souk[0], // 装甲.
mst.api_luck[1] - mst.api_luck[0] // 運.
];
};
function get_begin_shipid(ship_id) {
var mst = $mst_ship[ship_id];
return mst.yps_begin_shipid ? mst.yps_begin_shipid : ship_id;
}
Ship.prototype.begin_shipid = function() {
return get_begin_shipid(this.ship_id);
};
Ship.prototype.slot_names = function() {
var slot = this.slot;
var onslot = this.onslot;
var maxslot = $mst_ship[this.ship_id].api_maxeq;
var slotnum = $mst_ship[this.ship_id].api_slot_num; // 通常スロット数.
var a = [];
for (var i = 0; i < slot.length; ++i) {
var value = $slotitem_list[slot[i]];
if (value) {
a.push(slotitem_name(value.item_id, value.level, value.alv, value.p_alv, onslot[i], maxslot[i]));
}
else if (slot[i] == -1 && i < slotnum) {
a.push('空');
}
}
return a.join(', ');
};
Ship.prototype.deckbuilder_slot = function() { ///< デッキビルダー用装備情報.
const slot = this.slot;
const slotnum = $mst_ship[this.ship_id].api_slot_num; // 通常スロット数.
const a = {};
for (let i = 0; i < slot.length; ++i) {
const value = $slotitem_list[slot[i]];
if (value) {
const item = {
id: value.item_id,
rf: value.level
};
if (value.alv >= 1) item.mas = value.alv;
const name = 'i' + (i < slotnum ? i+1 : 'x'); // i1, i2, i3, i4, ix
a[name] = item;
}
}
return a;
};
Ship.prototype.slot_seiku = function() { ///< 制空値.
var slot = this.slot;
var onslot = this.onslot;
var a = 0;
for (var i = 0; i < slot.length; ++i) {
var value = $slotitem_list[slot[i]];
if (value) {
a += slotitem_seiku(value.item_id, value.level, value.alv, onslot[i]);
}
}
return a;
};
Ship.prototype.blank_slot_num = function() { ///< 通常スロットの空き数を返す(補強スロットは対象外とする)
var num = 0;
var slot = this.slot;
var slotnum = $mst_ship[this.ship_id].api_slot_num;
for (var i = 0; i < slot.length; ++i) {
if (slot[i] == -1 && i < slotnum) ++num;
}
return num;
};
Ship.prototype.next_level = function () {
return 'あと ' + this.nextlv;
};
//------------------------------------------------------------------------
// データ保存と更新.
//
function try_json_parse(a) {
try {
a = JSON.parse(a);
}
catch (e) {
// ignore parse errors.
}
return a;
}
function sync_cloud() {
chrome.storage.sync.get({weekly: $weekly}, function(a) {
let w = try_json_parse(a.weekly);
let savetime = ($weekly.savetime || 0);
if (savetime < w.savetime) $weekly = w;
let saveDate = to_date($weekly.savetime);
chrome.runtime.sendMessage({appendData: ['## 任務、演習進捗データのデバイス間同期完了', saveDate.toLocaleString() ]});
});
chrome.storage.sync.get({quest_clear: $quest_clear}, function(a) {
let w = try_json_parse(a.quest_clear);
let savetime = ($quest_clear.savetime || 0);
if (savetime < w.savetime) $quest_clear = w;
let saveDate = to_date($weekly.savetime);
chrome.runtime.sendMessage({appendData: ['## 任務クリア済データのデバイス間同期完了', saveDate.toLocaleString() ]});
});
}
function save_weekly() {
$weekly.savetime = Date.now();
chrome.storage.sync.set({weekly: JSON.stringify($weekly)});
save_storage('weekly', $weekly);
}
function save_quest_clear() {
$quest_clear.savetime = Date.now();
chrome.storage.sync.set({quest_clear: JSON.stringify($quest_clear)});
save_storage('quest_clear', $quest_clear);
}
function load_storage(name, def) {
if (!def) def = {};
var v = localStorage[name];
return v ? JSON.parse(v) : def;
}
function save_storage(name, v) {
localStorage[name] = JSON.stringify(v);
}
function update_ship_list(list, is_delta) {
if (!list) return;
// update ship_list
var prev_ship_list = $ship_list;
if (!is_delta) $ship_list = {};
list.forEach(function(data) {
var prev = prev_ship_list[data.api_id];
var ship = new Ship(data, prev);
$ship_list[data.api_id] = ship;
if ($newship_slots && !prev) {
// ship2廃止によりドロップ艦の装備数が母港帰還まで反映できなくなったので、母港帰還時に新規入手艦の装備数を記録保存し、
// ドロップ時に装備数分のダミー装備IDを用意する. 初入手艦など未記録の艦は装備数0となるので、装備数が少なく表示される場合がある.
if (ship.id < 0) { // on_battle_result で仮登録するドロップ艦の場合.
for (var slots = $newship_slots[ship.ship_id]; slots; --slots) { // 装備数未登録なら何もしない(装備数合計が少なく表示される)
$slotitem_list[$tmp_slot_id] = null; // 個数を合せるためnullのダミーエントリを追加する. 母港帰還時 /api_get_member/slot_item にリストが全更新される.
ship.slot.push($tmp_slot_id--); // 初期装備数分のダミー装備IDを載せる. 母港帰還(portパケット)により正しい値に上書きされる.
}
}
else if (ship.lv == 1) { // 海域ドロップ、報酬、建造などにより新規入手したLv1艦の場合.
$newship_slots[ship.ship_id] = count_unless(ship.slot, -1); // 初期装備数を記録する.
}
}
});
if (!$newship_slots) {
// ゲーム開始直後の保有艦リスト更新では、別環境で入手済みの既存Lv1艦(装備変更の可能性あり)も新規入手扱いになるので都合が悪い.
// よって $newship_slots のロードをここで行い、開始直後の装備数記録をスキップする.
$newship_slots = load_storage('newship_slots'); // この環境で保存した新規艦の初期装備数をロードする.
for (var i in $init_newship_slots) { // 既知艦の初期装備個数を上書きする.
var n = $init_newship_slots[i];
if (n != null)
$newship_slots[i] = n;
}
}
save_storage('ship_list', $ship_list);
save_storage('newship_slots', $newship_slots);
}
function delta_update_ship_list(list) {
update_ship_list(list, true);
}
function update_fdeck_list(list, is_delta) {
if (!list) return;
if (!is_delta) {
$fdeck_list = {};
$ship_fdeck = {};
}
for (var idx in list) { // list が Array でも Object($fdeck_list自身) でも扱えるようにする.
var deck = list[idx];
$fdeck_list[deck.api_id] = deck;
for (var i in deck.api_ship) {
var ship_id = deck.api_ship[i];
if (ship_id != -1) $ship_fdeck[ship_id] = deck.api_id;
}
}
}
function delta_update_fdeck_list(list) {
update_fdeck_list(list, true);
}
function update_ndock_complete() {
// $ndock_list のクリア前に現在のリストで入渠完了した艦がないかチェックする
for (var id in $ndock_list) {
var d = $ndock_list[id];
var ship = $ship_list[id];
if (d.api_complete_time < $svDateTime.getTime() + 60000) {
//alert(d.api_complete_time_str);
ship.highspeed_repair();
$do_print_port_on_ndock = true;
}
}
}
function update_ndock_list(list) {
if (!list) return;
$ndock_list = {};
list.forEach(function(data) {
var ship_id = data.api_ship_id;
if (ship_id) $ndock_list[ship_id] = data;
});
}
function update_kdock_list(list) {
if (!list) return;
$kdock_list = {};
list.forEach(function(data) {
// state: -1:未開放, 0:空き, 1:不明, 2:建造中, 3:完成.
if (data.api_state >= 2) $kdock_list[data.api_id] = data;
});
}
function update_slotitem_list(list) {
if (!list) return;
var prev = $slotitem_list;
$slotitem_list = {};
add_slotitem_list(list, prev);
save_storage('slotitem_list', $slotitem_list);
}
/// $mst_ship を list の内容で一新する.
/// さらに改装情報として yps_before_shipid, yps_begin_shipid を設定する.
function update_mst_ship(list) {
if (!list) return;
$mst_ship = {};
let before = {}; // before[艦種ID] ::= 改装前の艦種ID. コンバートで改装前が複数ある場合はLvの低い方.
let begin = {}; // begin[艦種ID] ::= 未改装の艦種ID なら true.
list.forEach(function(data) {
$mst_ship[data.api_id] = data;
const a = data.api_aftershipid;
if (a > 0) {
const b = before[a];
if (b == null || $mst_ship[b].api_afterlv > data.api_afterlv)
before[a] = data.api_id;
}
const getmes = to_string(data.api_getmes);
if (getmes.replace('<br>', '').length > 0) // 未改装の艦種IDにのみ、取得時挨拶文があると想定した判定条件である.
begin[data.api_id] = true;
});
for (let id in $mst_ship) {
let b = before[id];
if (b > 0) {
$mst_ship[id].yps_before_shipid = b; // 改装前の艦種ID. コンバートで改装前が複数ある場合はLvの低い方.
let checked = {}; // 通過記録.
while (before[b] > 0) {
if (begin[b]) break; // 未改装の艦種IDに到達した.
if (checked[b]) break; // コンバート改装で同じ艦種IDに戻ってきたらループを打ち切る.
checked[b] = true;
b = before[b];
}
if (id != b)
$mst_ship[id].yps_begin_shipid = b; // 改装の出発点となる未改装の艦種ID. 自身が出発点なら設定しない.
}
}
save_storage('mst_ship', $mst_ship);
}
function update_mst_slotitem(list) {
if (!list) return;
$mst_slotitem = {};
list.forEach(function(data) {
$mst_slotitem[data.api_id] = data;
});
save_storage('mst_slotitem', $mst_slotitem);
}
function update_mst_slotitemeq(list) {
if (!list) return;
$mst_slotitemeq = {};
list.forEach(function(data) {
$mst_slotitemeq[data.api_id] = data;
});
save_storage('mst_slotitemeq', $mst_slotitemeq);
}
function update_mst_mission(list) {
if (!list) return;
$mst_mission = {};
$mst_mission_name_to_id = {};
list.forEach(function(data) {
$mst_mission[data.api_id] = data;
$mst_mission_name_to_id[data.api_name] = data.api_id;
});
save_storage('mst_mission', $mst_mission);
save_storage('mst_mission_name_to_id', $mst_mission_name_to_id);
}
function update_mst_useitem(list) {
if (!list) return;
$mst_useitem = {};
list.forEach(function(data) {
$mst_useitem[data.api_id] = data;
});
save_storage('mst_useitem', $mst_useitem);
}
function update_mst_mapinfo(list) {
if (!list) return;
$mst_mapinfo = {};
list.forEach(function(data) {
$mst_mapinfo[data.api_id] = data;
});
save_storage('mst_mapinfo', $mst_mapinfo);
}
function update_mst_maparea(list) {
if (!list) return;
$mst_maparea = {};
list.forEach(function(data) {
$mst_maparea[data.api_id] = data.api_name;
});
save_storage('mst_maparea', $mst_maparea);
}
function clear_quest_progress(id)
{
const quest = $quest_list[id];
if (quest && quest.api_state == 2) {
quest.api_state = 3;
}
}
function inc_quest_progress(id, w) {
const quest = $quest_list[id];
const complete = $quest_complete_daily[id] || $quest_complete_weekly[id];
if (complete && quest && quest.api_state == 2) {
w = w || get_weekly();
if (w.quest_progress[id] == null) w.quest_progress[id] = 0; // dirty hack.
if (++w.quest_progress[id] >= complete) {
quest.api_state = 3;
}
w.savetime = 0; // calling save_weekly()
}
}
function get_weekly() {
const now = Date.now();
const ms = now - Date.UTC(2013, 4-1, 22, 5-9, 0); // 2013-4-22 05:00 JST からの経過ミリ秒数.
var dn = Math.floor(ms / (24*60*60*1000)); // 経過日数に変換する.
var wn = Math.floor(dn / 7); // 経過週数に変換する.
var hn = Math.floor((ms + 2*60*60*1000) / (12*60*60*1000)); // 演習更新数(03:00JST起点の半日周期)に変換する.
if ($weekly == null || $weekly.week != wn) {
$weekly = {
quest_progress : {
214 : // あ号.
{
sortie : 0,
boss_cell : 0,
win_boss : 0,
win_S : 0
}
},
monday_material : null,
week : wn,
savetime : 0
};
for (let id in $quest_complete_weekly) {
// 任務カウンタのリセットと同時に、任務遂行状態をリセットする.
if ($quest_complete_weekly[id] == null) continue;
$weekly.quest_progress[id] = 0;
if ($quest_list[id] != null) $quest_list[id].api_state = -1;
}
if ($quest_list[214] != null) $quest_list[214].api_state = -1;
}
if ($weekly.daily != dn) {
const date = new Date(now + 9*60*60*1000);
$weekly.month = date.getUTCMonth(); // 実行環境のタイムゾーンに関係なくJSTの月番号が必要なので, タイムゾーン分ずらした世界時で月番号を得る.
$weekly.daily = dn;
$weekly.savetime = 0;
$quest_count = -1; // 日替わりで任務リストが更新されるので、任務のリセットを予約する.
for (let id in $quest_complete_daily) {
// 任務カウンタのリセットと同時に、任務遂行状態をリセットする.
if ($quest_complete_daily[id] == null) continue;
$weekly.quest_progress[id] = 0;
if ($quest_list[id] != null) $quest_list[id].api_state = -1;
}
}
if ($weekly.halfdaily != hn) {
$weekly.halfdaily = hn;
$weekly.practice_done = 0;
$weekly.savetime = 0;
}
if ($weekly.monday_material == null) {
$weekly.monday_material = $material.now.concat();
$weekly.savetime = 0;
}
if ($weekly.savetime == 0) save_weekly();
return $weekly;
}
function month_to_quarter(m) { ///< m 0(Jan)..11(Dec) -> 1:Dec,Jan,Feb, 2:Mar,Apr,May, 3:Jun,Jul,Aug, 4:Sep,Oct,Nov.
return Math.floor(((m+1)%12)/3)+1;
}
function push_to_logbook(log) {
if ($logbook.push(log) > 50) $logbook.shift(); // 50を超えたら古いものから削除する.
save_storage('logbook', $logbook);
}
//------------------------------------------------------------------------
// 表示文字列化.
//
function fraction_name(num, denom) {
if (num >= denom)
return '達成';
else
return num + '/' + denom;
}
function quest_progress_name(w, id) {
if (id == 214) {
return quest214_progress_name(w.quest_progress[214]); // あ号任務.
}
let num = w.quest_progress[id];
let denom = $quest_complete_daily[id] || $quest_complete_weekly[id];
return (num == null || denom == null) ? '' : '(' + fraction_name(num, denom) + ')';
}
function quest214_progress_name(w) {
return '(出撃数:' + fraction_name(w.sortie, 36)
+ ', ボス勝利:' + fraction_name(w.win_boss, 12)
+ ', ボス到達:' + fraction_name(w.boss_cell, 24)
+ ', S勝利:' + fraction_name(w.win_S, 6)
+ ')';
}
function key_array(obj) {
let a = [];
for(let key in obj) {
a.push(key + ':' + obj[key]);
}
return a;
}
function key_join(obj, separator) {
return key_array(obj).join(separator);
}
function to_number(a) { ///< NaN,undefined,null,"","非数値文字列"に対して0を返し、常にnumberを返す.
// isNaN(NaN) => true
// isNaN(undefined) => true
// isNaN("str") => true
// isNaN("123") => false
// isNaN("") => false
// isNaN(null) => false
// isNaN(123) => false
// +"" => 0
// +null => 0
return isNaN(a) ? 0 : +a; // 数値文字列はnumber化する.
}
function inc_number(obj, key, value) {
obj[key] = to_number(obj[key]) + value;
}
function to_string(id,nullstr) { ///< id == null に対して代理文字列を返し、例外落ちしない.
if (id == null) return nullstr ? nullstr : '';
return id.toString();
}
function to_date(a) { ///< aが日付型ではなければ日付型に変換して返す.
if (a instanceof Date) return a;
return new Date(a);
}
function diff_name(now, prev) { // now:1, prev:2 -> "(-1)"
var diff = now - prev; // 演算項目のどちらかがundefinedなら減算結果はNaNとなる. 項目がnullならば0として減算する.
if (prev == null) return ''; // nullかundefinedなら増減なしと見做して空文字列を返す.
else if (diff > 0) return '(+' + diff + ')'; // with plus sign
else if (diff < 0) return '(' + diff +')'; // with minus sign
else /* diff == 0 */ return '';
}
function percent_name(now, max, decimal_digits) { // now:1, max:2 -> "50%"
if (!max) return '';
var pow10 = decimal_digits ? Math.pow(10, decimal_digits) : 1;
return Math.floor(100 * pow10 * now / max) / pow10 + '%';
}
function percent_name_unless100(now, max, decimal_digits) { // now:1, max:2 -> "(50%)"
if (!max || now == max) return '';
return '(' + percent_name(now, max, decimal_digits) + ')';
}
function fraction_percent_name(now, max) { // now:1, max:2 -> "1/2(50%)"
if (!max) return ''; // 0除算回避.
var d = (100 * now / max < 1) ? 1 : 0; // 1%未満なら小数部2桁目を切り捨て、1%以上なら小数部切り捨て.
return now + '/' + max + '(' + percent_name(now, max, d) + ')';
}
function kira_name(cond) {
return (cond >= 85) ? '*** ' : // 三重キラ.
(cond >= 53) ? '** ' : // 回避向上キラ.
(cond >= 50) ? '* ' : // キラ.
(cond == 49) ? '. ' : // 通常.
(cond >= 30) ? '> ' : // 疲労.
(cond >= 20) ? '>> ' : // オレンジ疲労.
/* cond 0..19 */ '>>> '; // 赤疲労.
}
function kira_names(list) {
var count = {}; // kira_name をキーとするカウンター.
list.forEach(function(cond) {
var name = kira_name(cond).trim();
if (count[name] == null)
count[name] = 1;
else
count[name]++;
});
var msg = [];
var n;
if (n = count['***']) msg.push('***' + n);
if (n = count['**']) msg.push('**' + n);
if (n = count['*']) msg.push('*' + n);
// if (n = count['.']) msg.push('通常' + n); --- 通常は表示しない.
if (n = count['>']) msg.push('疲労' + n);
if (n = count['>>']) msg.push('橙疲労' + n);
if (n = count['>>>']) msg.push('赤疲労' + n);
return msg.join(' ');
}
function material_name(id) {
switch (parseInt(id, 10)) {
case 1: return '燃料';
case 2: return '弾薬';
case 3: return '鋼材';
case 4: return 'ボーキ';
case 5: return '高速建造材'; // バーナー.
case 6: return '高速修復材'; // バケツ.
case 7: return '開発資材'; // 歯車.
case 8: return '改修資材'; // ネジ.
case 10: return '家具箱小';
case 11: return '家具箱中';
case 12: return '家具箱大';
default: return 'id(' + id + ')';
}
}
function combined_name() {
switch ($combined_flag) {
case 1: return '連合機動部隊';
case 2: return '連合水上部隊';
case 3: return '連合輸送護衛部隊';
default: return to_string(id);
}
}
function formation_name(id) {
switch (parseInt(id, 10)) { // 連合艦隊戦闘では id が数値ではなく文字列になっている.
case 1: return '単縦';
case 2: return '複縦';
case 3: return '輪形';
case 4: return '梯形';
case 5: return '単横';
case 6: return '警戒';
case 11: return '連合対潜警戒';
case 12: return '連合前方警戒';
case 13: return '連合輪形陣';
case 14: return '連合戦闘隊形';
default: return to_string(id);
}
}
function match_name(id) {
switch (id) {
case 1: return '同航';
case 2: return '反航';
case 3: return 'T字有利';
case 4: return 'T字不利';
default: return to_string(id);
}
}
function support_name(id) { ///@param id 支援タイプ api_support_flag
switch (id) {
case 1: return '航空支援';
case 2: return '支援射撃';
case 3: return '支援長距離雷撃';
case 4: return '対潜支援哨戒';
default: return to_string(id);
}
}
function seiku_name(id) { ///@param id 制空権 api_disp_seiku
switch (id) {
case 1: return '制空権確保';
case 2: return '航空優勢';
case 0: return '航空互角';
case 3: return '航空劣勢';
case 4: return '制空権喪失';
default: return to_string(id);
}
}
function search_name(id) { ///@param id 索敵結果 api_search[]
switch (id) {
case 1: return '敵艦隊発見!';
case 2: return '敵艦隊発見!索敵機未帰還機あり';
case 3: return '敵艦隊発見できず…索敵機未帰還機あり';
case 4: return '敵艦隊発見できず…';
case 5: return '敵艦隊発見!(索敵機なし)';
case 6: return 'なし';
default: return to_string(id);
}
}
function event_sally_tag_name(id) { ///@param id イベント札番号 api_sally_area.
return $event_sally_tag_names[id] || '札'+to_string(id);
}
function event_kind_name(id) { ///@param id 非戦闘マスのメッセージ api_event_kind.
switch (id) {
case 0: return '気のせいだった';
case 1: return '敵影を見ず';
case 2: return '能動分岐';
case 3: return '穏やかな海です';
case 4: return '穏やかな海峡です';
case 5: return '警戒が必要です';
case 6: return '静かな海です';
default: return '??'+to_string(id);
}
}
function battle_kind_name(id) { ///@param id 戦闘マスのメッセージ api_event_kind.
switch (id) {
case 1: return ''; // 通常戦.
case 2: return '夜戦';
case 3: return '払暁戦'; // 夜昼戦.
case 4: return '航空戦';
case 5: return '通常戦(敵連合)';
case 6: return '空襲戦';
case 7: return '払暁戦(敵連合)'; // 夜昼戦(敵連合).
case 8: return '敵レーダー射撃夜戦';
default: return '??'+to_string(id);
}
}
function battle_api_kind_name(name) { ///@param name battle_api_name.
if (/midnight/.test(name)) return '夜戦';
if (/night_to_day/.test(name)) return '払暁戦'; // 夜昼戦.
if (/ld_airbattle/.test(name)) return '空襲戦';
if (/ld_shooting/.test(name)) return '敵レーダー射撃夜戦';
if (/airbattle/.test(name)) return '航空戦';
return '';
}
function mission_clear_name(cr) { ///@param c 遠征クリア api_clear_result
switch (cr) {
case 1: return '成功';
case 2: return '大成功';
default: return '失敗';
}
}
function boss_next_name() {
if ($is_boss) return '(boss)';
if (!$is_next) return '(end)';
return '';
}
function slotitem_name(id, lv, alv, p_alv, n, max, distance) {
var item = $mst_slotitem[id];
if (!item) return id.toString(); // unknown slotitem.
var name = item.api_name;
if (lv >= 10) name += '★max'; // 改修レベルを追加する.
else if (lv >= 1) name += '★+' + lv; // 改修レベルを追加する.
if (alv >= 1 || alv < p_alv) {
if (alv >= 7) name += '♥♥'; // 熟練度最大なら♥2個を追加する.
else name += '♥' + alv; // さもなくば熟練度数値を追加する.
var diff = diff_name(alv, p_alv);
if (diff.length > 0) name += '@!!' + diff + '!!@'; // 熟練度変化量を追加する.
}
if (is_airplane(item) && n != null) name += (n == 0 && n < max) ? 'x0(@!!全滅!!@)' : 'x' + n + percent_name_unless100(n, max); // 航空機なら、機数と搭載割合を追加する.
if (distance) name += ' 戦闘行動半径' + item.api_distance; // 基地航空隊用
return name;
}
function slotitem_seiku(id, lv, alv, n, airbase) {
// airbase ::= undefined:艦隊制空戦, 1:基地航空隊出撃, 2:基地航空隊防空
// https://gist.github.com/YSRKEN/4cdecc6e8a1c2c75b13b08126c94f4cf の制空値計算式を採用する.
// http://kancollecalc.web.fc2.com/air_supremacy.html の計算結果に合うように計算式を修正する.
// seiku(attack) ::= floor((P + Ga * lv + 1.5 * In) * sqrt(n) + sqrt(v/10) + Vc)
// seiku(intercept) ::= floor((P + Ga * lv + In + 2 * Ba) * sqrt(n) + sqrt(v/10) + Vc)
// lv ::= 改修レベル:0-10
// alv::= 熟練度:0-7
// n ::= 搭載機数.
// P ::= 装備対空値. api_tyku
// In ::= 装備迎撃値. 局地戦闘機:api_houk, その他:0
// Ga ::= 改修レベル係数. 艦上戦闘機&水上戦闘機:0.2, 艦上爆撃機:0.25, その他:0
// v ::= 内部熟練度:0-120
// Vc ::= 熟練度ボーナス. 艦上戦闘機&水上戦闘機:0-22, 水上爆撃機:0-6, その他:0
// Ba ::= 対爆値. api_houm
var item = $mst_slotitem[id];
if (!is_airplane(item)) return 0;
var seiku = 0;
var In = 0;
var Ba = 0;
var Ga = 0;
var Vc = null;
switch (item.api_type[2]) {
case 48:// 局地戦闘機.
In = item.api_houk;
Ba = item.api_houm;
break;
case 6: // 艦上戦闘機.
case 45:// 水上戦闘機.
Ga = 0.2;
Vc = [0, 0, 2, 5, 6, 14, 14, 22];
break;
case 7: // 艦上爆撃機.
Ga = 0.25;
break;
case 11:// 水上爆撃機.
Vc = [0, 0, 1, 1, 1, 3, 3, 6];
break;
case 9: // 艦上偵察機.
case 10:// 水上偵察機.
case 41:// 大型飛行艇.
if (airbase == null) return 0; // 艦隊制空戦に参加しない機種.
break;
case 25:// オートジャイロ.
case 26:// 対潜哨戒機.
return 0; // 制空戦に参加しない機種.
case 8: // 艦上攻撃機.
case 47:// 陸上攻撃機.
case 56:// 噴式戦闘機.
case 57:// 噴式戦闘爆撃機.
case 58:// 噴式攻撃機.
case 59:// 噴式偵察機.
case 94:// 艦上偵察機(II).
break;
}
if (n > 0) {
var P = item.api_tyku;
if (airbase == 2)
seiku += (P + Ga * lv + In + 2 * Ba) * Math.sqrt(n);
else
seiku += (P + Ga * lv + 1.5 * In) * Math.sqrt(n);
}
if (alv > 0) {
var v = [0, 10, 25, 40, 55, 70, 85, 100][alv]; // 内部熟練度:下端.
// var v = [9, 24, 39, 54, 69, 85, 99, 120][alv]; // 内部熟練度:上端.
seiku += Math.sqrt(v / 10.0);
if (Vc) seiku += Vc[alv]; // Vc: 艦上戦闘機、水上戦闘機.
}
return Math.floor(seiku);
}
// 装備運用枠(上限 $max_slotitem)として数えるアイテムか?
function is_total_slotitem(id) {
let item = $mst_slotitem[id];
switch (item.api_type[2]) {
case 23: // 応急修理要員:ダメコン、女神.
case 43: // 戦闘糧食:おにぎり、特別なおにぎり.
case 44: // 補給物資:洋上補給.
return false; // 上限で保持数が制限されないアイテムである.