poi-plugin-compass 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.
Files changed (452) hide show
  1. package/README.md +79 -0
  2. package/air-status.js +28 -0
  3. package/assets/compass.css +647 -0
  4. package/assets/kcnav/icons/map_common/136.png +0 -0
  5. package/assets/kcnav/icons/map_common/137.png +0 -0
  6. package/assets/kcnav/icons/map_common/19.png +0 -0
  7. package/assets/kcnav/icons/map_main/17.png +0 -0
  8. package/assets/kcnav/icons/map_main/18.png +0 -0
  9. package/assets/kcnav/icons/map_main/40.png +0 -0
  10. package/assets/kcnav/icons/map_main/42.png +0 -0
  11. package/assets/kcnav/icons/map_main/46.png +0 -0
  12. package/assets/kcnav/icons/map_main/47.png +0 -0
  13. package/assets/kcnav/icons/map_main/48.png +0 -0
  14. package/assets/kcnav/icons/map_main/53.png +0 -0
  15. package/assets/kcnav/icons/map_main/54.png +0 -0
  16. package/assets/kcnav/icons/map_main/62.png +0 -0
  17. package/assets/kcnav/maps/1-1.webp +0 -0
  18. package/assets/kcnav/maps/1-2.webp +0 -0
  19. package/assets/kcnav/maps/1-3.webp +0 -0
  20. package/assets/kcnav/maps/1-4.webp +0 -0
  21. package/assets/kcnav/maps/1-5.webp +0 -0
  22. package/assets/kcnav/maps/1-6.webp +0 -0
  23. package/assets/kcnav/maps/2-1.webp +0 -0
  24. package/assets/kcnav/maps/2-2.webp +0 -0
  25. package/assets/kcnav/maps/2-3.webp +0 -0
  26. package/assets/kcnav/maps/2-4.webp +0 -0
  27. package/assets/kcnav/maps/2-5.webp +0 -0
  28. package/assets/kcnav/maps/3-1.webp +0 -0
  29. package/assets/kcnav/maps/3-2.webp +0 -0
  30. package/assets/kcnav/maps/3-3.webp +0 -0
  31. package/assets/kcnav/maps/3-4.webp +0 -0
  32. package/assets/kcnav/maps/3-5.webp +0 -0
  33. package/assets/kcnav/maps/4-1.webp +0 -0
  34. package/assets/kcnav/maps/4-2.webp +0 -0
  35. package/assets/kcnav/maps/4-3.webp +0 -0
  36. package/assets/kcnav/maps/4-4.webp +0 -0
  37. package/assets/kcnav/maps/4-5.webp +0 -0
  38. package/assets/kcnav/maps/5-1.webp +0 -0
  39. package/assets/kcnav/maps/5-2.webp +0 -0
  40. package/assets/kcnav/maps/5-3.webp +0 -0
  41. package/assets/kcnav/maps/5-4.webp +0 -0
  42. package/assets/kcnav/maps/5-5.webp +0 -0
  43. package/assets/kcnav/maps/5-6.webp +0 -0
  44. package/assets/kcnav/maps/6-1.webp +0 -0
  45. package/assets/kcnav/maps/6-2.webp +0 -0
  46. package/assets/kcnav/maps/6-3.webp +0 -0
  47. package/assets/kcnav/maps/6-4.webp +0 -0
  48. package/assets/kcnav/maps/6-5.webp +0 -0
  49. package/assets/kcnav/maps/7-1.webp +0 -0
  50. package/assets/kcnav/maps/7-2.webp +0 -0
  51. package/assets/kcnav/maps/7-3.webp +0 -0
  52. package/assets/kcnav/maps/7-4.webp +0 -0
  53. package/assets/kcnav/maps/7-5.webp +0 -0
  54. package/data/kc3kai-master-ids.json +1 -0
  55. package/data/kc3kai-ship-stats.json +21545 -0
  56. package/data/kcnav-node-types-by-map.json +606 -0
  57. package/data/kcnav-node-types.json +176 -0
  58. package/data/los-config.json +42 -0
  59. package/data/maps.json +590 -0
  60. package/data/normal-maps.json +1590 -0
  61. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/A.json +1 -0
  62. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/B.json +1 -0
  63. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-1/C.json +1 -0
  64. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/A.json +1 -0
  65. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/C.json +1 -0
  66. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/D.json +1 -0
  67. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-2/E.json +1 -0
  68. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/C.json +1 -0
  69. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/E.json +1 -0
  70. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/F.json +1 -0
  71. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-3/J.json +1 -0
  72. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/B.json +1 -0
  73. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/D.json +1 -0
  74. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/H.json +1 -0
  75. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/I.json +1 -0
  76. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/J.json +1 -0
  77. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-4/L.json +1 -0
  78. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/A.json +1 -0
  79. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/C.json +1 -0
  80. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/D.json +1 -0
  81. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/E.json +1 -0
  82. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/F.json +1 -0
  83. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/H.json +1 -0
  84. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/I.json +1 -0
  85. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-5/J.json +1 -0
  86. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/B.json +1 -0
  87. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/C.json +1 -0
  88. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/D.json +1 -0
  89. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/E.json +1 -0
  90. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/F.json +1 -0
  91. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/I.json +1 -0
  92. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/J.json +1 -0
  93. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/K.json +1 -0
  94. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/1-6/L.json +1 -0
  95. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/A.json +1 -0
  96. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/C.json +1 -0
  97. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/D.json +1 -0
  98. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/F.json +1 -0
  99. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-1/H.json +1 -0
  100. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/B.json +1 -0
  101. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/D.json +1 -0
  102. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/E.json +1 -0
  103. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/G.json +1 -0
  104. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-2/K.json +1 -0
  105. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/A.json +1 -0
  106. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/E.json +1 -0
  107. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/F.json +1 -0
  108. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/J.json +1 -0
  109. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/K.json +1 -0
  110. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/M.json +1 -0
  111. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-3/N.json +1 -0
  112. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/B.json +1 -0
  113. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/E.json +1 -0
  114. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/F.json +1 -0
  115. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/I.json +1 -0
  116. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/L.json +1 -0
  117. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/M.json +1 -0
  118. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-4/P.json +1 -0
  119. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/B.json +1 -0
  120. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/C.json +1 -0
  121. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/E.json +1 -0
  122. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/F.json +1 -0
  123. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/J.json +1 -0
  124. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/L.json +1 -0
  125. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/2-5/O.json +1 -0
  126. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/B.json +1 -0
  127. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/C.json +1 -0
  128. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/D.json +1 -0
  129. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/F.json +1 -0
  130. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-1/G.json +1 -0
  131. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/A.json +1 -0
  132. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/C.json +1 -0
  133. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/H.json +1 -0
  134. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/J.json +1 -0
  135. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/K.json +1 -0
  136. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-2/L.json +1 -0
  137. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/A.json +1 -0
  138. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/B.json +1 -0
  139. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/E.json +1 -0
  140. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/G.json +1 -0
  141. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/K.json +1 -0
  142. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-3/M.json +1 -0
  143. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/A.json +1 -0
  144. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/B.json +1 -0
  145. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/C.json +1 -0
  146. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/G.json +1 -0
  147. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/H.json +1 -0
  148. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/I.json +1 -0
  149. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/M.json +1 -0
  150. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/N.json +1 -0
  151. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-4/P.json +1 -0
  152. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/B.json +1 -0
  153. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/D.json +1 -0
  154. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/E.json +1 -0
  155. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/F.json +1 -0
  156. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/G.json +1 -0
  157. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/H.json +1 -0
  158. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/3-5/K.json +1 -0
  159. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/A.json +1 -0
  160. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/C.json +1 -0
  161. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/D.json +1 -0
  162. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/E.json +1 -0
  163. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/G.json +1 -0
  164. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/H.json +1 -0
  165. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-1/J.json +1 -0
  166. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/A.json +1 -0
  167. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/B.json +1 -0
  168. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/C.json +1 -0
  169. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/D.json +1 -0
  170. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/E.json +1 -0
  171. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/G.json +1 -0
  172. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/H.json +1 -0
  173. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-2/L.json +1 -0
  174. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/A.json +1 -0
  175. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/C.json +1 -0
  176. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/D.json +1 -0
  177. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/F.json +1 -0
  178. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/G.json +1 -0
  179. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/H.json +1 -0
  180. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/I.json +1 -0
  181. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/L.json +1 -0
  182. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-3/N.json +1 -0
  183. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/A.json +1 -0
  184. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/B.json +1 -0
  185. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/E.json +1 -0
  186. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/F.json +1 -0
  187. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/G.json +1 -0
  188. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/H.json +1 -0
  189. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/I.json +1 -0
  190. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-4/K.json +1 -0
  191. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/B.json +1 -0
  192. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/D.json +1 -0
  193. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/E.json +1 -0
  194. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/F.json +1 -0
  195. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/G.json +1 -0
  196. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/H.json +1 -0
  197. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/J.json +1 -0
  198. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/K.json +1 -0
  199. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/N.json +1 -0
  200. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/O.json +1 -0
  201. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/S.json +1 -0
  202. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/4-5/T.json +1 -0
  203. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/B.json +1 -0
  204. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/D.json +1 -0
  205. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/E.json +1 -0
  206. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/F.json +1 -0
  207. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/G.json +1 -0
  208. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-1/J.json +1 -0
  209. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/C.json +1 -0
  210. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/D.json +1 -0
  211. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/E.json +1 -0
  212. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/F.json +1 -0
  213. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/I.json +1 -0
  214. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/K.json +1 -0
  215. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/L.json +1 -0
  216. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-2/O.json +1 -0
  217. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/C.json +1 -0
  218. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/I.json +1 -0
  219. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/J.json +1 -0
  220. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/K.json +1 -0
  221. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/M.json +1 -0
  222. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/N.json +1 -0
  223. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/P.json +1 -0
  224. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-3/Q.json +1 -0
  225. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/C.json +1 -0
  226. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/E.json +1 -0
  227. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/F.json +1 -0
  228. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/G.json +1 -0
  229. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/H.json +1 -0
  230. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/J.json +1 -0
  231. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/L.json +1 -0
  232. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-4/P.json +1 -0
  233. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/B.json +1 -0
  234. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/C.json +1 -0
  235. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/G.json +1 -0
  236. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/H.json +1 -0
  237. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/J.json +1 -0
  238. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/K.json +1 -0
  239. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/M.json +1 -0
  240. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/N.json +1 -0
  241. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/P.json +1 -0
  242. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-5/S.json +1 -0
  243. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A.json +1 -0
  244. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A1.json +1 -0
  245. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/A2.json +1 -0
  246. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/B.json +1 -0
  247. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C.json +1 -0
  248. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C1.json +1 -0
  249. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/C2.json +1 -0
  250. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/D.json +1 -0
  251. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/G.json +1 -0
  252. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/H.json +1 -0
  253. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/J.json +1 -0
  254. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K.json +1 -0
  255. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K1.json +1 -0
  256. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/K2.json +1 -0
  257. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/L.json +1 -0
  258. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/N.json +1 -0
  259. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/P.json +1 -0
  260. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q.json +1 -0
  261. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q1.json +1 -0
  262. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Q2.json +1 -0
  263. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/T.json +1 -0
  264. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/U.json +1 -0
  265. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/V.json +1 -0
  266. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/W.json +1 -0
  267. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/X.json +1 -0
  268. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/5-6/Z.json +1 -0
  269. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/C.json +1 -0
  270. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/D.json +1 -0
  271. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/F.json +1 -0
  272. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/H.json +1 -0
  273. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/I.json +1 -0
  274. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/J.json +1 -0
  275. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-1/K.json +1 -0
  276. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/B.json +1 -0
  277. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/C.json +1 -0
  278. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/F.json +1 -0
  279. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/H.json +1 -0
  280. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/I.json +1 -0
  281. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/J.json +1 -0
  282. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-2/K.json +1 -0
  283. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/B.json +1 -0
  284. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/C.json +1 -0
  285. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/D.json +1 -0
  286. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/E.json +1 -0
  287. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/F.json +1 -0
  288. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-3/J.json +1 -0
  289. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/A.json +1 -0
  290. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/B.json +1 -0
  291. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/C.json +1 -0
  292. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/D.json +1 -0
  293. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/E.json +1 -0
  294. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/F.json +1 -0
  295. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/G.json +1 -0
  296. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/H.json +1 -0
  297. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/I.json +1 -0
  298. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/J.json +1 -0
  299. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/K.json +1 -0
  300. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/L.json +1 -0
  301. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/M.json +1 -0
  302. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-4/N.json +1 -0
  303. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/A.json +1 -0
  304. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/B.json +1 -0
  305. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/C.json +1 -0
  306. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/D.json +1 -0
  307. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/E.json +1 -0
  308. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/F.json +1 -0
  309. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/G.json +1 -0
  310. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/H.json +1 -0
  311. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/I.json +1 -0
  312. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/J.json +1 -0
  313. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/6-5/M.json +1 -0
  314. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/B.json +1 -0
  315. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/C.json +1 -0
  316. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/D.json +1 -0
  317. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/F.json +1 -0
  318. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/G.json +1 -0
  319. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/H.json +1 -0
  320. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-1/K.json +1 -0
  321. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/B.json +1 -0
  322. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/C.json +1 -0
  323. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/E.json +1 -0
  324. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/G.json +1 -0
  325. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/H.json +1 -0
  326. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/I.json +1 -0
  327. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/J.json +1 -0
  328. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-2/M.json +1 -0
  329. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/B.json +1 -0
  330. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/C.json +1 -0
  331. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/D.json +1 -0
  332. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/E.json +1 -0
  333. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/J.json +1 -0
  334. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/M.json +1 -0
  335. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/N.json +1 -0
  336. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-3/P.json +1 -0
  337. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/B.json +1 -0
  338. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/C.json +1 -0
  339. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/D.json +1 -0
  340. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/E.json +1 -0
  341. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/G.json +1 -0
  342. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/H.json +1 -0
  343. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/J.json +1 -0
  344. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/K.json +1 -0
  345. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/L.json +1 -0
  346. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/M.json +1 -0
  347. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-4/P.json +1 -0
  348. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/A.json +1 -0
  349. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/B.json +1 -0
  350. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/C.json +1 -0
  351. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/D.json +1 -0
  352. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/E.json +1 -0
  353. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/G.json +1 -0
  354. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/J.json +1 -0
  355. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/K.json +1 -0
  356. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/L.json +1 -0
  357. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/M.json +1 -0
  358. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/N.json +1 -0
  359. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/Q.json +1 -0
  360. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/R.json +1 -0
  361. package/data/sources/kcnav/enemies/2026-08-11_2026-09-11/7-5/T.json +1 -0
  362. package/data/sources/kcnav/enemies/manifest.json +2120 -0
  363. package/data/sources/kcnav/maps/1-1.json +175 -0
  364. package/data/sources/kcnav/maps/1-2.json +277 -0
  365. package/data/sources/kcnav/maps/1-3.json +517 -0
  366. package/data/sources/kcnav/maps/1-4.json +652 -0
  367. package/data/sources/kcnav/maps/1-5.json +553 -0
  368. package/data/sources/kcnav/maps/1-6.json +668 -0
  369. package/data/sources/kcnav/maps/2-1.json +451 -0
  370. package/data/sources/kcnav/maps/2-2.json +557 -0
  371. package/data/sources/kcnav/maps/2-3.json +757 -0
  372. package/data/sources/kcnav/maps/2-4.json +817 -0
  373. package/data/sources/kcnav/maps/2-5.json +779 -0
  374. package/data/sources/kcnav/maps/3-1.json +379 -0
  375. package/data/sources/kcnav/maps/3-2.json +588 -0
  376. package/data/sources/kcnav/maps/3-3.json +654 -0
  377. package/data/sources/kcnav/maps/3-4.json +910 -0
  378. package/data/sources/kcnav/maps/3-5.json +643 -0
  379. package/data/sources/kcnav/maps/4-1.json +561 -0
  380. package/data/sources/kcnav/maps/4-2.json +664 -0
  381. package/data/sources/kcnav/maps/4-3.json +867 -0
  382. package/data/sources/kcnav/maps/4-4.json +690 -0
  383. package/data/sources/kcnav/maps/4-5.json +1232 -0
  384. package/data/sources/kcnav/maps/5-1.json +517 -0
  385. package/data/sources/kcnav/maps/5-2.json +791 -0
  386. package/data/sources/kcnav/maps/5-3.json +889 -0
  387. package/data/sources/kcnav/maps/5-4.json +851 -0
  388. package/data/sources/kcnav/maps/5-5.json +1070 -0
  389. package/data/sources/kcnav/maps/5-6.json +3200 -0
  390. package/data/sources/kcnav/maps/6-1.json +527 -0
  391. package/data/sources/kcnav/maps/6-2.json +717 -0
  392. package/data/sources/kcnav/maps/6-3.json +501 -0
  393. package/data/sources/kcnav/maps/6-4.json +870 -0
  394. package/data/sources/kcnav/maps/6-5.json +814 -0
  395. package/data/sources/kcnav/maps/7-1.json +640 -0
  396. package/data/sources/kcnav/maps/7-2.json +976 -0
  397. package/data/sources/kcnav/maps/7-3.json +1529 -0
  398. package/data/sources/kcnav/maps/7-4.json +1000 -0
  399. package/data/sources/kcnav/maps/7-5.json +1570 -0
  400. package/data/sources/kcnav/maps/manifest.json +340 -0
  401. package/data/sources/kcwiki/routes/1-1.wiki +2 -0
  402. package/data/sources/kcwiki/routes/1-2.wiki +1 -0
  403. package/data/sources/kcwiki/routes/1-3.wiki +1 -0
  404. package/data/sources/kcwiki/routes/1-4.wiki +1 -0
  405. package/data/sources/kcwiki/routes/1-5.wiki +1 -0
  406. package/data/sources/kcwiki/routes/1-6.wiki +1 -0
  407. package/data/sources/kcwiki/routes/2-1.wiki +1 -0
  408. package/data/sources/kcwiki/routes/2-2.wiki +1 -0
  409. package/data/sources/kcwiki/routes/2-3.wiki +1 -0
  410. package/data/sources/kcwiki/routes/2-4.wiki +81 -0
  411. package/data/sources/kcwiki/routes/2-5.wiki +1 -0
  412. package/data/sources/kcwiki/routes/3-1.wiki +1 -0
  413. package/data/sources/kcwiki/routes/3-2.wiki +1 -0
  414. package/data/sources/kcwiki/routes/3-3.wiki +1 -0
  415. package/data/sources/kcwiki/routes/3-4.wiki +1 -0
  416. package/data/sources/kcwiki/routes/3-5.wiki +1 -0
  417. package/data/sources/kcwiki/routes/4-1.wiki +1 -0
  418. package/data/sources/kcwiki/routes/4-2.wiki +1 -0
  419. package/data/sources/kcwiki/routes/4-3.wiki +1 -0
  420. package/data/sources/kcwiki/routes/4-4.wiki +1 -0
  421. package/data/sources/kcwiki/routes/4-5.wiki +1 -0
  422. package/data/sources/kcwiki/routes/5-1.wiki +57 -0
  423. package/data/sources/kcwiki/routes/5-2.wiki +1 -0
  424. package/data/sources/kcwiki/routes/5-3.wiki +1 -0
  425. package/data/sources/kcwiki/routes/5-4.wiki +1 -0
  426. package/data/sources/kcwiki/routes/5-5.wiki +80 -0
  427. package/data/sources/kcwiki/routes/5-6.wiki +753 -0
  428. package/data/sources/kcwiki/routes/6-1.wiki +1 -0
  429. package/data/sources/kcwiki/routes/6-2.wiki +1 -0
  430. package/data/sources/kcwiki/routes/6-3.wiki +1 -0
  431. package/data/sources/kcwiki/routes/6-4.wiki +1 -0
  432. package/data/sources/kcwiki/routes/6-5.wiki +1 -0
  433. package/data/sources/kcwiki/routes/7-1.wiki +1 -0
  434. package/data/sources/kcwiki/routes/7-2.wiki +1 -0
  435. package/data/sources/kcwiki/routes/7-3.wiki +1 -0
  436. package/data/sources/kcwiki/routes/7-4.wiki +1 -0
  437. package/data/sources/kcwiki/routes/7-5.wiki +1 -0
  438. package/data/sources/kcwiki/routes/README.md +11 -0
  439. package/data/sources/kcwiki/routes/manifest.json +450 -0
  440. package/docs/research.md +445 -0
  441. package/docs/sources.md +85 -0
  442. package/enemies.js +56 -0
  443. package/exporters.js +182 -0
  444. package/index.js +1081 -0
  445. package/logic.js +603 -0
  446. package/overview.js +54 -0
  447. package/package.json +66 -0
  448. package/scripts/cache-kcnav-enemies.js +97 -0
  449. package/scripts/cache-kcnav-maps.js +109 -0
  450. package/scripts/cache-kcwiki-routes.js +96 -0
  451. package/scripts/compact-kcnav-enemies.js +53 -0
  452. package/scripts/compress-kcnav-maps.js +90 -0
package/exporters.js ADDED
@@ -0,0 +1,182 @@
1
+ 'use strict'
2
+
3
+ const { routeDecision } = require('./logic')
4
+ const { loadEnemies } = require('./enemies')
5
+ const nodeCatalog = require('./data/kcnav-node-types.json')
6
+ const nodeTypes = require('./data/kcnav-node-types-by-map.json')
7
+ const kc3Ids = require('./data/kc3kai-master-ids.json')
8
+ const kc3Stats = require('./data/kc3kai-ship-stats.json')
9
+ const kc3Ships = new Set(Object.keys(kc3Stats.ships).map(Number))
10
+ const kc3Equips = new Set(kc3Ids.equips)
11
+ const submarines = new Set(kc3Ids.submarines)
12
+
13
+ function enumerateRoutes(definition, geometry, context, overrides = {}) {
14
+ const routes = []
15
+ const blocked = new Set()
16
+ const edges = Object.values(geometry.route || {}).filter((edge) => edge[0] && edge[1])
17
+ const outgoing = new Set(edges.map(([from]) => from))
18
+ let visits = 0
19
+ function walk(node, nodes, probability, score, estimated) {
20
+ if (++visits > 10000) throw new Error('候选路线过多,请先在地图上指定部分能动分歧')
21
+ if (nodes.includes(node)) { blocked.add(node); return }
22
+ const path = [...nodes, node]
23
+ const decision = routeDecision(definition, node, { ...context, passedNodes: nodes }, overrides)
24
+ if (decision.status === 'terminal' || !outgoing.has(node) && !decision.outcomes.length && !decision.rule) {
25
+ routes.push({ key: path.join('>'), nodes: path, probability, score, estimated, boss: node === definition.boss })
26
+ return
27
+ }
28
+ const outcomes = decision.manualChoiceRequired ? decision.manualOutcomes || decision.baseOutcomes : decision.outcomes
29
+ if (decision.status === 'unknown' && !decision.manualChoiceRequired || !outcomes.length) { blocked.add(node); return }
30
+ for (const outcome of outcomes) {
31
+ if (outcome.probability === 0) continue
32
+ const virtualStart = node === '1' && outcome.to === '2' && ['6-4-start-right-lha', '6-4-start-right-heavy', '6-5-start-right'].includes(decision.rule?.id)
33
+ if (!virtualStart && !edges.some(([from, to]) => from === node && to === outcome.to)) { blocked.add(node); continue }
34
+ const p = decision.manualChoiceRequired ? null : outcome.probability
35
+ walk(outcome.to, path, probability == null || p == null ? null : probability * p,
36
+ score * (p ?? 1 / outcomes.length), estimated || outcome.estimated === true)
37
+ }
38
+ }
39
+ walk(definition.start, [], 1, 1, false)
40
+ routes.sort((a, b) => Number(b.boss) - Number(a.boss) || b.score - a.score || a.key.localeCompare(b.key))
41
+ return { routes, blocked: [...blocked] }
42
+ }
43
+
44
+ function battleNodes(mapId, route, geometry, loader = loadEnemies) {
45
+ return route.nodes.flatMap((node, index) => {
46
+ const type = nodeTypes[mapId]?.[node]
47
+ if (!nodeCatalog[type]?.hasEnemies) return []
48
+ const edge = Object.entries(geometry.route).find(([, value]) => value[0] === route.nodes[index - 1] && value[1] === node)
49
+ if (!edge) throw new Error(`${node} 点缺少实际路线编号`)
50
+ const data = loader(mapId, node)
51
+ const rows = data.status === 'ready' ? data.rows.filter((entry) => entry.count > 0) : []
52
+ const subOnly = rows.length > 0 && rows.every((entry) => [...entry.mainFleet, ...entry.escortFleet].every((ship) => submarines.has(ship.id)))
53
+ return [{ node, cell: Number(edge[0]), type, rows, subOnly, formation: subOnly ? 5 : [7, 10].includes(type) ? 3 : 1 }]
54
+ })
55
+ }
56
+
57
+ function required(value, label) {
58
+ if (typeof value !== 'number' || !Number.isFinite(value)) throw new Error(`poi 数据不可用:${label}`)
59
+ return value
60
+ }
61
+
62
+ function playerFleet(state, deckId = 1) {
63
+ const fleet = state.info?.fleets?.[deckId - 1]
64
+ if (!Array.isArray(fleet?.api_ship)) throw new Error(`poi 数据不可用:舰队 ${deckId}`)
65
+ const ships = fleet.api_ship.filter((id) => id > 0).map((id) => {
66
+ const ship = state.info?.ships?.[id]
67
+ const master = state.const?.$ships?.[ship?.api_ship_id]
68
+ if (!ship || !master || !Array.isArray(ship.api_slot) || !Array.isArray(ship.api_onslot) || !Array.isArray(ship.api_kyouka)) throw new Error(`poi 数据不可用:舰娘 #${id}`)
69
+ const slotCount = required(ship.api_slotnum, '装备槽数')
70
+ const items = [...ship.api_slot.slice(0, slotCount), ship.api_slot_ex ?? -1].map((equipId, index) => {
71
+ if (equipId <= 0) return null
72
+ const equip = state.info?.equips?.[equipId]
73
+ const equipMaster = state.const?.$equips?.[equip?.api_slotitem_id]
74
+ if (!equip || !equipMaster) throw new Error(`poi 数据不可用:装备 #${equipId}`)
75
+ return { id: equip.api_slotitem_id, rf: required(equip.api_level, '装备改修'), mas: equip.api_alv ?? 0, ac: index < slotCount ? required(ship.api_onslot[index], '当前搭载') : 0 }
76
+ })
77
+ const level = required(ship.api_lv, '等级')
78
+ const statsBase = {}
79
+ for (const [key, field, mod] of [['fp', 'api_houg', 0], ['tp', 'api_raig', 1], ['aa', 'api_tyku', 2], ['ar', 'api_souk', 3]]) {
80
+ statsBase[key] = required(master[field]?.[0], field) + required(ship.api_kyouka[mod], '近代化改修')
81
+ }
82
+ statsBase.luk = required(ship.api_lucky?.[0], '运')
83
+ return { ship, master, items, slotCount, level, statsBase }
84
+ })
85
+ if (!ships.length || ships.length > 6) throw new Error('仅支持所选舰队的 1~6 艘单舰队导出')
86
+ return { ships, admiralLevel: required(state.info?.basic?.api_level, '司令部等级') }
87
+ }
88
+
89
+ function validateBattles(battles) {
90
+ if (!battles.length) throw new Error('此路线没有战斗节点')
91
+ const missing = battles.filter((battle) => !battle.rows.length)
92
+ if (missing.length) throw new Error(`${missing.map((b) => b.node).join('、')} 点尚未缓存或本月无敌编成样本`)
93
+ }
94
+
95
+ function kc3Enemy(ship) {
96
+ if (!kc3Ships.has(ship.id)) throw new Error(`KC3Kai 数据未收录敌舰 #${ship.id}`)
97
+ const equips = ship.equips.filter((id) => id > 0).map((id) => ({ mstId: id > 500 && id < 1000 ? id + 1000 : id, rank: 0 }))
98
+ if (ship.exslot > 0) equips.push({ mstId: ship.exslot, rank: 0 })
99
+ for (const equip of equips) if (!kc3Equips.has(equip.mstId)) throw new Error(`KC3Kai 数据未收录装备 #${equip.mstId}`)
100
+ return { mstId: ship.id, level: ship.lvl, hp: ship.hp, hpInit: ship.hp,
101
+ statsBase: { fp: ship.fp, tp: ship.torp, aa: ship.aa, ar: ship.armor }, equips }
102
+ }
103
+
104
+ function kc3Save(state, mapId, battles, formations = {}, deckId = 1) {
105
+ validateBattles(battles)
106
+ if (battles.length > 9) throw new Error('KC3Kai 最多支持 9 个战斗节点')
107
+ const excessive = battles.find((battle) => battle.rows.length > 12)
108
+ if (excessive) throw new Error(`KC3Kai 每节点最多支持 12 套敌编成,${excessive.node} 点有 ${excessive.rows.length} 套;请改用 noro6 选择单套编成`)
109
+ const unknownType = battles.find((battle) => ![4, 5, 7, 10, 11].includes(battle.type))
110
+ if (unknownType) throw new Error(`${unknownType.node} 点战斗类型尚未适配 KC3Kai`)
111
+ const { ships } = playerFleet(state, deckId)
112
+ const players = ships.map(({ ship, master, items, slotCount, level, statsBase }) => {
113
+ if (!kc3Ships.has(master.api_id)) throw new Error(`KC3Kai 数据未收录舰娘 #${master.api_id}`)
114
+ for (const item of items) if (item && !kc3Equips.has(item.id)) throw new Error(`KC3Kai 数据未收录装备 #${item.id}`)
115
+ // Missing EV/LOS/ASW are derived by KC3Kai from level. Only override ASW
116
+ // when modernization cannot be represented by level alone.
117
+ const aswModernization = required(ship.api_kyouka[6], '对潜改修')
118
+ const exportedStats = { ...statsBase }
119
+ if (aswModernization > 0) {
120
+ const growth = kc3Stats.ships[master.api_id]
121
+ if (!Number.isFinite(growth?.ASWbase) || !Number.isFinite(growth?.ASW)) throw new Error(`KC3Kai 本地缓存缺少 #${master.api_id} 对潜成长数据`)
122
+ exportedStats.asw = growth.ASWbase + Math.floor((growth.ASW - growth.ASWbase) * level / 99) + aswModernization
123
+ }
124
+ return { mstId: master.api_id, level, hp: required(ship.api_maxhp, '最大耐久'), hpInit: required(ship.api_nowhp, '当前耐久'),
125
+ morale: required(ship.api_cond, '士气'), fuelInit: required(ship.api_fuel, '燃油') / required(master.api_fuel_max, '燃油上限') * 100,
126
+ ammoInit: required(ship.api_bull, '弹药') / required(master.api_bull_max, '弹药上限') * 100,
127
+ statsBase: exportedStats, slots: ship.api_onslot.slice(0, slotCount),
128
+ equips: items.map((item) => item ? { mstId: item.id, level: item.rf, rank: item.mas } : null) }
129
+ })
130
+ return {
131
+ version: 2, fleetFMain: { version: 2, type: 0, formation: 1, ships: players },
132
+ useSupportN: false, useSupportB: false, useFF: false, fleetsFFriend: [], landBases: [],
133
+ settings: { airRaidCostW6: mapId.startsWith('6-') },
134
+ battles: battles.map((battle, index) => ({
135
+ id: index + 1, ind: index, formation: Number(formations[battle.node] || battle.formation),
136
+ nodeType: ({ 11: 2, 7: 4, 10: 6 })[battle.type] || 1,
137
+ doNB: battle.type === 5, doNBCond: '', subOnly: battle.subOnly,
138
+ lbasWaves: [false, false, false, false, false, false],
139
+ enemyComps: battle.rows.map((entry, compIndex) => ({ num: compIndex + 1, rate: entry.count,
140
+ fleet: { version: 2, type: entry.escortFleet.length ? 1 : 0, formation: entry.formation,
141
+ ships: entry.mainFleet.map(kc3Enemy), ...(entry.escortFleet.length ? { shipsEscort: entry.escortFleet.map(kc3Enemy) } : {}) } })),
142
+ })),
143
+ }
144
+ }
145
+
146
+ function noroDeck(state, mapId, battles, selected = {}, formations = {}, deckId = 1) {
147
+ validateBattles(battles)
148
+ const { ships, admiralLevel } = playerFleet(state, deckId)
149
+ const f1 = { name: `舰队 ${deckId}`, t: 0 }
150
+ ships.forEach(({ ship, master, level, items, slotCount }, index) => {
151
+ const equipment = {}
152
+ items.forEach((item, i) => { if (item) equipment[i === slotCount ? 'ix' : `i${i + 1}`] = item })
153
+ f1[`s${index + 1}`] = { id: master.api_id, lv: level, luck: ship.api_lucky[0], hp: ship.api_maxhp,
154
+ asw: required(ship.api_taisen?.[0], '对潜'), exa: ship.api_slot_ex !== 0, items: equipment }
155
+ })
156
+ const [a, i] = mapId.split('-').map(Number)
157
+ const fleet = (shipsE) => ({ s: shipsE.map((ship) => ({ id: ship.id, items: ship.equips.filter((id) => id > 0).map((id) => ({ id })) })) })
158
+ return { version: 4, hqlv: admiralLevel, f1, s: { a, i, c: battles.map((battle) => {
159
+ const entry = battle.rows.find((row) => compositionKey(row) === selected[battle.node]) || battle.rows[0]
160
+ return { c: battle.cell, pf: Number(formations[battle.node] || battle.formation), ef: entry.formation,
161
+ f1: fleet(entry.mainFleet), ...(entry.escortFleet.length ? { f2: fleet(entry.escortFleet) } : {}) }
162
+ }) } }
163
+ }
164
+
165
+ function compositionKey(entry) {
166
+ return JSON.stringify([entry.masterId, entry.formation, entry.mainFleet, entry.escortFleet])
167
+ }
168
+
169
+ function kc3Url(save) {
170
+ return new Promise((resolve, reject) => {
171
+ require('lzma').compress(JSON.stringify(save), 1, (bytes, error) => {
172
+ if (error) reject(error)
173
+ else resolve(`https://kc3kai.github.io/kancolle-replay/simulator.html#backup=${Buffer.from(bytes).toString('base64')}`)
174
+ })
175
+ })
176
+ }
177
+
178
+ function noroUrl(deck) {
179
+ return `https://noro6.github.io/kc-web/?predeck=${encodeURIComponent(JSON.stringify(deck))}#/`
180
+ }
181
+
182
+ module.exports = { enumerateRoutes, battleNodes, playerFleet, kc3Save, noroDeck, compositionKey, kc3Url, noroUrl }