[银河奶牛]强化工具(血压工具)

在线统计强化成功/失败次数

  1. // ==UserScript==
  2. // @name [MWI]Enhancement Tool
  3. // @name:zh-CN [银河奶牛]强化工具(血压工具)
  4. // @name:zh-TW [銀河奶牛]強化工具
  5. // @namespace http://tampermonkey.net/
  6. // @version 1.10
  7. // @description Track the number of enhancement successes and failures
  8. // @description:zh-CN 在线统计强化成功/失败次数
  9. // @description:zh-TW 統計強化成功/失敗次數
  10. // @author Truth_Light
  11. // @license Truth_Light
  12. // @match https://www.milkywayidle.com/*
  13. // @match https://test.milkywayidle.com/*
  14. // @icon https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com
  15. // @grant GM.xmlHttpRequest
  16. // @grant GM_registerMenuCommand
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. 'use strict';
  21. let enhancementLevel;
  22. let currentEnhancingIndex = 1;
  23. let enhancementData = {
  24. [currentEnhancingIndex]: { "强化数据": {}, "其他数据": {} }
  25. };
  26. let item_name_to_hrid;
  27. let item_hrid_to_name;
  28.  
  29. const userLanguage = navigator.language || navigator.userLanguage;
  30. const isZH = userLanguage.startsWith("zh");
  31.  
  32. function hookWS() {
  33. const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
  34. const oriGet = dataProperty.get;
  35.  
  36. dataProperty.get = hookedGet;
  37. Object.defineProperty(MessageEvent.prototype, "data", dataProperty);
  38.  
  39. function hookedGet() {
  40. const socket = this.currentTarget;
  41. if (!(socket instanceof WebSocket)) {
  42. return oriGet.call(this);
  43. }
  44. if (socket.url.indexOf("api.milkywayidle.com/ws") <= -1 && socket.url.indexOf("api-test.milkywayidle.com/ws") <= -1) {
  45. return oriGet.call(this);
  46. }
  47.  
  48. const message = oriGet.call(this);
  49. Object.defineProperty(this, "data", { value: message });
  50.  
  51. return handleMessage(message);
  52. }
  53. }
  54.  
  55. function handleMessage(message) {
  56. try {
  57. let obj = JSON.parse(message);
  58. if (obj && obj.type === "init_character_data") {
  59. const initClientData = localStorage.getItem('initClientData');
  60. if (!initClientData) return;
  61. let obj;
  62. try {
  63. obj = JSON.parse(initClientData);
  64. } catch (error) {
  65. console.error('数据解析失败:', error);
  66. return;
  67. }
  68. if (obj.type !== 'init_client_data') return;
  69. item_hrid_to_name = obj.itemDetailMap;
  70. for (const key in item_hrid_to_name) {
  71. if (item_hrid_to_name[key] && typeof item_hrid_to_name[key] === 'object' && item_hrid_to_name[key].name) {
  72. item_hrid_to_name[key] = item_hrid_to_name[key].name;
  73. }
  74. }
  75. item_name_to_hrid = Object.fromEntries(
  76. Object.entries(item_hrid_to_name).map(([key, value]) => [value, key])
  77. );
  78. } else if (obj && obj.type === "action_completed" && obj.endCharacterAction && obj.endCharacterAction.actionHrid === "/actions/enhancing/enhance") {
  79. const now_enhancementLevel = parseInt(obj.endCharacterAction.primaryItemHash.match(/::(\d+)$/)[1]);
  80. const currentCount = obj.endCharacterAction.currentCount;
  81. if (enhancementLevel !== undefined) {
  82. // 开始新的物品的强化
  83. if (currentCount < enhancementData[currentEnhancingIndex]["强化次数"]) {
  84. currentEnhancingIndex++;
  85. enhancementData[currentEnhancingIndex] = { "强化数据": {}, "其他数据": {} };
  86. enhancementLevel = undefined;
  87. return message
  88. }
  89.  
  90. const currentItem = enhancementData[currentEnhancingIndex]["强化数据"];
  91.  
  92.  
  93. if (!currentItem[enhancementLevel]) {
  94. currentItem[enhancementLevel] = { "成功次数": 0, "失败次数": 0, "成功率": 0 };
  95. }
  96.  
  97. if (enhancementLevel < now_enhancementLevel) {
  98. currentItem[enhancementLevel]["成功次数"]++;
  99. } else {
  100. currentItem[enhancementLevel]["失败次数"]++;
  101. if (obj.endCharacterAction.enhancingProtectionMinLevel >= 2 && enhancementLevel >= obj.endCharacterAction.enhancingProtectionMinLevel) {
  102. enhancementData[currentEnhancingIndex]["其他数据"]["保护消耗总数"]++;
  103. }
  104. }
  105.  
  106. const success = currentItem[enhancementLevel]["成功次数"];
  107. const failure = currentItem[enhancementLevel]["失败次数"];
  108. currentItem[enhancementLevel]["成功率"] = success / (success + failure);
  109.  
  110. // 计算强化状态
  111. const highestSuccessLevel = Math.max(...Object.keys(currentItem).filter(level => currentItem[level]["成功次数"] > 0));
  112. const enhancementState = (highestSuccessLevel + 1 >= enhancementData[currentEnhancingIndex]["其他数据"]["目标强化等级"]) ? "强化成功" : "强化失败";
  113. enhancementData[currentEnhancingIndex]["强化状态"] = enhancementState;
  114. enhancementLevel = now_enhancementLevel;
  115. } else {
  116. // 初始化数据
  117. enhancementLevel = now_enhancementLevel;
  118. const itemName = item_hrid_to_name[obj.endCharacterAction.primaryItemHash.match(/::([^:]+)::[^:]*$/)[1]];
  119. enhancementData[currentEnhancingIndex]["其他数据"] = {
  120. "物品名称": itemName,
  121. "目标强化等级": obj.endCharacterAction.enhancingMaxLevel,
  122. "保护消耗总数": 0,
  123. };
  124. }
  125. console.log(enhancementData)
  126. enhancementData[currentEnhancingIndex]["强化次数"] = currentCount;
  127. updateDisplay();
  128. } else {
  129. return message;
  130. }
  131. } catch (error) {
  132. console.error("Error processing message:", error);
  133. }
  134. return message;
  135. }
  136.  
  137. function updateDisplay() {
  138. const targetElement = document.querySelector(".SkillActionDetail_enhancingComponent__17bOx");
  139. if (!targetElement) return;
  140.  
  141. // 创建父容器
  142. let parentContainer = document.querySelector("#enhancementParentContainer");
  143. if (!parentContainer) {
  144. parentContainer = document.createElement("div");
  145. parentContainer.id = "enhancementParentContainer";
  146. parentContainer.style.display = "block"; // 设置为纵向布局(块级元素)
  147. parentContainer.style.borderLeft = "2px solid var(--color-divider)";
  148. parentContainer.style.padding = "0 4px";
  149.  
  150. // 创建并添加标题
  151. const title = document.createElement("div");
  152. title.textContent = isZH ? "强化数据" : "Enhancement Data";
  153. title.style.fontWeight = "bold";
  154. title.style.marginBottom = "10px"; // 标题与下拉框之间的间距
  155. title.style.textAlign = "center";
  156. title.style.color = "var(--color-space-300)";
  157. parentContainer.appendChild(title);
  158.  
  159. // 创建并添加下拉框
  160. const dropdownContainer = document.createElement("div");
  161. dropdownContainer.style.marginBottom = "10px"; // 下拉框与表格之间的间距
  162.  
  163. const dropdown = document.createElement("select");
  164. dropdown.id = "enhancementDropdown";
  165. dropdown.addEventListener("change", function () {
  166. renderStats(this.value);
  167. updateDropdownColor();
  168. });
  169.  
  170. dropdownContainer.appendChild(dropdown);
  171. parentContainer.appendChild(dropdownContainer);
  172.  
  173. // 创建并添加表格容器
  174. const enhancementStatsContainer = document.createElement("div");
  175. enhancementStatsContainer.id = "enhancementStatsContainer";
  176. enhancementStatsContainer.style.display = "grid";
  177. enhancementStatsContainer.style.gridTemplateColumns = "repeat(4, 1fr)"; // 设置为4列
  178. enhancementStatsContainer.style.gap = "10px"; // 每列之间的间距
  179. enhancementStatsContainer.style.textAlign = "center";
  180. enhancementStatsContainer.style.marginTop = "10px";
  181.  
  182. parentContainer.appendChild(enhancementStatsContainer);
  183. targetElement.appendChild(parentContainer); // 将父容器添加到目标元素中
  184. }
  185.  
  186. // 更新下拉框内容
  187. const dropdown = document.querySelector("#enhancementDropdown");
  188. const previousSelectedValue = dropdown.value;
  189. dropdown.innerHTML = ""; // 清空下拉框内容
  190.  
  191. Object.keys(enhancementData).forEach(key => {
  192. const item = enhancementData[key];
  193. const option = document.createElement("option");
  194. const itemName = item["其他数据"]["物品名称"];
  195. const targetLevel = item["其他数据"]["目标强化等级"];
  196. const currentLevel = Math.max(...Object.keys(item["强化数据"]));
  197. const enhancementState = item["强化状态"];
  198.  
  199. option.text = isZH
  200. ? `${itemName} (目标: ${targetLevel}, 总计: ${item["强化次数"]}${item["其他数据"]["保护消耗总数"] > 0 ? `, 垫子: ${item["其他数据"]["保护消耗总数"]}` : ""})`
  201. : `${itemName} (Target: ${targetLevel}, Total: ${item["强化次数"]}${item["其他数据"]["保护消耗总数"] > 0 ? `, Protectors Used: ${item["其他数据"]["保护消耗总数"]}` : ""})`;
  202.  
  203. option.value = key;
  204. option.style.color = enhancementState === "强化成功" ? "green"
  205. : (currentLevel < targetLevel && Object.keys(enhancementData).indexOf(key) === Object.keys(enhancementData).length - 1) ? "orange"
  206. : "red";
  207.  
  208. dropdown.appendChild(option);
  209. });
  210.  
  211. // 设置默认选中项并渲染表格数据
  212. if (Object.keys(enhancementData).length > 0) {
  213. dropdown.value = previousSelectedValue || Object.keys(enhancementData)[0];
  214. updateDropdownColor();
  215. renderStats(dropdown.value);
  216. }
  217.  
  218. function updateDropdownColor() {
  219. const selectedOption = dropdown.options[dropdown.selectedIndex];
  220. dropdown.style.color = selectedOption ? selectedOption.style.color : "black";
  221. }
  222. }
  223.  
  224. function renderStats(selectedKey) {
  225. const enhancementStatsContainer = document.querySelector("#enhancementStatsContainer");
  226. enhancementStatsContainer.innerHTML = ""; // 清空现有内容
  227.  
  228. const item = enhancementData[selectedKey];
  229.  
  230. // 表头
  231. const headers = ["等级", "成功", "失败", "概率"];
  232. headers.forEach(headerText => {
  233. const headerDiv = document.createElement("div");
  234. headerDiv.style.fontWeight = "bold";
  235. headerDiv.textContent = isZH ? headerText : (headerText === "等级" ? "Level" : headerText === "成功次数" ? "Success" : headerText === "失败次数" ? "Failure" : "Success Rate");
  236. enhancementStatsContainer.appendChild(headerDiv);
  237. });
  238.  
  239. // 总计信息
  240. const totalSuccess = Object.values(item["强化数据"]).reduce((acc, val) => acc + val["成功次数"], 0);
  241. const totalFailure = Object.values(item["强化数据"]).reduce((acc, val) => acc + val["失败次数"], 0);
  242. const totalCount = totalSuccess + totalFailure;
  243. const totalRate = totalCount > 0 ? (totalSuccess / totalCount * 100).toFixed(2) : "0.00";
  244.  
  245. // 将总计信息添加到表格中
  246. ["总计", totalSuccess, totalFailure, `${totalRate}%`].forEach((totalText, index) => {
  247. const totalDiv = document.createElement("div");
  248. totalDiv.textContent = isZH ? totalText : index === 0 ? "Total" : totalText;
  249. enhancementStatsContainer.appendChild(totalDiv);
  250. });
  251.  
  252. // 渲染各个强化等级的数据
  253. Object.keys(item["强化数据"]).sort((a, b) => b - a).forEach(level => {
  254. const levelData = item["强化数据"][level];
  255. const levelDivs = [level, levelData["成功次数"], levelData["失败次数"], `${(levelData["成功率"] * 100).toFixed(2)}%`];
  256.  
  257. levelDivs.forEach(data => {
  258. const dataDiv = document.createElement("div");
  259. dataDiv.textContent = data;
  260. enhancementStatsContainer.appendChild(dataDiv);
  261. });
  262. });
  263. }
  264.  
  265.  
  266.  
  267.  
  268. hookWS();
  269. })();