- // ==UserScript==
- // @name [银河奶牛]食用工具
- // @namespace http://tampermonkey.net/
- // @version 0.448
- // @description 开箱记录、箱子期望、离线统计、公会钉钉、食物警察、掉落追踪
- // @author Truth_Light
- // @license Truth_Light
- // @match https://www.milkywayidle.com/*
- // @match https://test.milkywayidle.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=milkywayidle.com
- // @grant GM.xmlHttpRequest
- // @grant GM_registerMenuCommand
- // @grant GM_openInTab
- // @grant GM_setValue
- // @grant GM_getValue
- // ==/UserScript==
-
- (async function() {
- 'use strict';
-
- const itemSelector = '.ItemDictionary_drop__24I5f';
- const iconSelector = '.Icon_icon__2LtL_ use';
- const chestNameSelector = '#root > div > div > div.Modal_modalContainer__3B80m > div.Modal_modal__1Jiep > div.ItemDictionary_modalContent__WvEBY > div.ItemDictionary_itemAndDescription__28_he > div.Item_itemContainer__x7kH1 > div > div > div > svg > use';
- const MARKET_API_URL = "https://raw.githubusercontent.com/holychikenz/MWIApi/main/medianmarket.json";
- let timer = null;
- let formattedChestDropData = {};
- let battlePlayerFood = {};
- let battlePlayerLoot = {};
- let battleDuration;
- let item_icon_url
-
- let marketData = JSON.parse(localStorage.getItem('MWITools_marketAPI_json'));
- const init_Client_Data = localStorage.getItem('initClientData');
- if (!init_Client_Data) return;
- let init_Client_Data_;
- try {
- init_Client_Data_ = JSON.parse(init_Client_Data);
- } catch (error) {
- console.error('数据解析失败:', error);
- return;
- }
- if (init_Client_Data_.type !== 'init_client_data') return;
- const item_hrid_to_name = init_Client_Data_.itemDetailMap;
- for (const key in item_hrid_to_name) {
- if (item_hrid_to_name[key] && typeof item_hrid_to_name[key] === 'object' && item_hrid_to_name[key].name) {
- item_hrid_to_name[key] = item_hrid_to_name[key].name;
- }
- }
- const item_name_to_hrid = Object.fromEntries(
- Object.entries(item_hrid_to_name).map(([key, value]) => [value, key])
- );
-
- async function fetchMarketData() {
- return new Promise((resolve, reject) => {
- GM.xmlHttpRequest({
- method: 'GET',
- url: MARKET_API_URL,
- responseType: 'json',
- timeout: 5000,
- onload: function(response) {
- if (response.status === 200) {
- const data = JSON.parse(response.responseText);
- console.log('从API获取到的数据:', data);
- resolve(data);
- } else {
- console.error('获取数据失败。状态码:', response.status);
- reject(new Error('数据获取失败'));
- }
- },
- ontimeout: function() {
- console.error('请求超时:超过5秒未能获取到数据');
- reject(new Error('请求超时'));
- },
- onerror: function(error) {
- console.error('获取数据时发生错误:', error);
- reject(error);
- }
- });
- });
- }
-
- hookWS();
- initObserver();
-
- try {
- // 尝试从 API 获取数据
- marketData = await fetchMarketData();
- } catch (error) {
- console.error('从 API 获取数据失败,尝试从本地存储获取数据。', error);
-
- // 从本地存储获取数据
- const marketDataStr = localStorage.getItem('MWITools_marketAPI_json');
- marketData = JSON.parse(marketDataStr);
-
- if (!marketData) {
- alert('无法获取 market 数据');
- } else {
- console.log('从本地存储获取到的数据:', marketData);
- }
- }
-
- function getSpecialItemPrice(itemName, priceType) {
- if (marketData?.market?.[itemName]) {
- const itemPrice = marketData.market[itemName][priceType];
- if (itemPrice !== undefined && itemPrice !== -1) {
- return itemPrice;
- }
- }
- console.error(`未找到物品 ${itemName} 的 ${priceType} 价格信息`);
- return null;
- }
-
- let specialItemPrices = {
- 'Coin': { ask: 1, bid: 1 }, // 默认的特殊物品价值,包括 ask 和 bid 价值
- 'Cowbell': {
- ask: getSpecialItemPrice('Bag Of 10 Cowbells', 'ask') / 10 || 50000,
- bid: getSpecialItemPrice('Bag Of 10 Cowbells', 'bid') / 10 || 50000
- },
- 'Chimerical Token': {
- ask: getSpecialItemPrice('Chimerical Essence', 'ask') || 3000,
- bid: getSpecialItemPrice('Chimerical Essence', 'bid') || 2850
- },
- 'Sinister Token': {
- ask: getSpecialItemPrice('Sinister Essence', 'ask') || 3000,
- bid: getSpecialItemPrice('Sinister Essence', 'bid') || 2900
- },
- 'Enchanted Token': {
- ask: getSpecialItemPrice('Enchanted Essence', 'ask') || 4000,
- bid: getSpecialItemPrice('Enchanted Essence', 'bid') || 4000
- },
- };
-
- function getItemNameFromElement(element) {
- const itemNameRaw = element.getAttribute('href').split('#').pop();
- return formatItemName(itemNameRaw);
- }
-
- function formatItemName(itemNameRaw) {
- return item_hrid_to_name[`/items/${itemNameRaw}`]
- }
-
-
- function formatPrice(value) {
- const isNegative = value < 0;
- value = Math.abs(value);
-
- if (value >= 1e13) {
- return (isNegative ? '-' : '') + (value / 1e12).toFixed(1) + 'T';
- } else if (value >= 1e10) {
- return (isNegative ? '-' : '') + (value / 1e9).toFixed(1) + 'B';
- } else if (value >= 1e7) {
- return (isNegative ? '-' : '') + (value / 1e6).toFixed(1) + 'M';
- } else if (value >= 1e4) {
- return (isNegative ? '-' : '') + (value / 1e3).toFixed(1) + 'K';
- } else {
- return (isNegative ? '-' : '') + value.toFixed(0);
- }
- }
-
-
- function parseQuantityString(quantityStr) {
- const suffix = quantityStr.slice(-1);
- const base = parseFloat(quantityStr.slice(0, -1));
- if (suffix === 'K') {
- return base * 1000;
- } else if (suffix === 'M') {
- return base * 1000000;
- } else if (suffix === 'B') {
- return base * 1000000000;
- } else {
- return parseFloat(quantityStr);
- }
- }
-
- function recordChestOpening(modalElement) {
- if (document.querySelector('.ChestStatistics')) {
- return;
- }
-
- // 从本地存储读取数据
- let edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {};
- edibleTools.Chest_Open_Data = edibleTools.Chest_Open_Data || {};
-
- let chestOpenData = edibleTools.Chest_Open_Data;
- const chestDropData = edibleTools.Chest_Drop_Data;
-
- const chestNameElement = modalElement.querySelector("div.Modal_modal__1Jiep > div.Inventory_modalContent__3ObSx > div.Item_itemContainer__x7kH1 > div > div > div.Item_iconContainer__5z7j4 > svg > use");
- const chestCountElement = modalElement.querySelector("div.Modal_modal__1Jiep > div.Inventory_modalContent__3ObSx > div.Item_itemContainer__x7kH1 > div > div > div.Item_count__1HVvv");
-
- if (chestNameElement && chestCountElement) {
- const chestName = getItemNameFromElement(chestNameElement);
- chestOpenData[chestName] = chestOpenData[chestName] || {};
- let chestData = chestOpenData[chestName];
- const chestCount = parseQuantityString(chestCountElement.textContent.trim());
- chestData["总计开箱数量"] = (chestData["总计开箱数量"] || 0) + chestCount;
- chestData["获得物品"] = chestData["获得物品"] || {};
- const itemsContainer = modalElement.querySelector('.Inventory_gainedItems___e9t9');
- const itemElements = itemsContainer.querySelectorAll('.Item_itemContainer__x7kH1');
-
- let totalAskValue = 0;
- let totalBidValue = 0;
-
- itemElements.forEach(itemElement => {
- const itemNameElement = itemElement.querySelector('.Item_iconContainer__5z7j4 use');
- const itemQuantityElement = itemElement.querySelector('.Item_count__1HVvv');
-
- if (itemNameElement && itemQuantityElement) {
- const itemName = getItemNameFromElement(itemNameElement);
- const itemQuantity = parseQuantityString(itemQuantityElement.textContent.trim());
-
- const itemData = chestDropData[chestName].item[itemName] || {};
- const itemAskValue = itemData["出售单价"] || 0;
- const itemBidValue = itemData["收购单价"] || 0;
- const color = itemData.Color || '';
-
- itemQuantityElement.style.color = color;
-
- const itemOpenTotalAskValue = itemAskValue * itemQuantity;
- const itemOpenTotalBidValue = itemBidValue * itemQuantity;
-
- chestData["获得物品"][itemName] = chestData["获得物品"][itemName] || {};
- chestData["获得物品"][itemName]["数量"] = (chestData["获得物品"][itemName]["数量"] || 0) + itemQuantity;
- chestData["获得物品"][itemName]["总计Ask价值"] = (chestData["获得物品"][itemName]["总计Ask价值"] || 0) + itemOpenTotalAskValue;
- chestData["获得物品"][itemName]["总计Bid价值"] = (chestData["获得物品"][itemName]["总计Bid价值"] || 0) + itemOpenTotalBidValue;
-
- totalAskValue += itemOpenTotalAskValue;
- totalBidValue += itemOpenTotalBidValue;
- }
- });
-
- chestData["总计开箱Ask"] = (chestData["总计开箱Ask"] || 0) + totalAskValue;
- chestData["总计开箱Bid"] = (chestData["总计开箱Bid"] || 0) + totalBidValue;
-
- // 计算本次开箱的偏差值
- const differenceValue = totalBidValue - chestDropData[chestName]["期望产出Bid"] * chestCount;
-
- // 更新累计偏差值
- chestData["累计偏差值"] = (chestData["累计偏差值"] || 0) + differenceValue;
-
- // 地牢开箱
- let profitRange = null;
- let profitColor = 'lime'; // 默认颜色
- const chestCosts = {
- "Chimerical Chest": {
- keyAsk: getSpecialItemPrice('Chimerical Chest Key', 'ask') || 2700e3,
- keyBid: getSpecialItemPrice('Chimerical Chest Key', 'bid') || 2600e3,
- entryAsk: getSpecialItemPrice('Chimerical Entry Key', 'ask') || 350e3,
- entryBid: getSpecialItemPrice('Chimerical Entry Key', 'bid') || 320e3
- },
- "Sinister Chest": {
- keyAsk: getSpecialItemPrice('Sinister Chest Key', 'ask') || 3800e3,
- keyBid: getSpecialItemPrice('Sinister Chest Key', 'bid') || 3500e3,
- entryAsk: getSpecialItemPrice('Sinister Entry Key', 'ask') || 450e3,
- entryBid: getSpecialItemPrice('Sinister Entry Key', 'bid') || 400e3
- },
- "Enchanted Chest": {
- keyAsk: getSpecialItemPrice('Enchanted Chest Key', 'ask') || 5600e3,
- keyBid: getSpecialItemPrice('Enchanted Chest Key', 'bid') || 5400e3,
- entryAsk: getSpecialItemPrice('Enchanted Entry Key', 'ask') || 420e3,
- entryBid: getSpecialItemPrice('Enchanted Entry Key', 'bid') || 400e3
- }
- };
-
- if (chestCosts[chestName]) {
- const { keyAsk, keyBid, entryAsk, entryBid } = chestCosts[chestName];
- const minProfit = totalBidValue - (keyAsk + entryAsk) * chestCount;
- const maxProfit = totalAskValue - (keyBid + entryBid) * chestCount;
- profitRange = `${formatPrice(minProfit)}~${formatPrice(maxProfit)}`;
-
- if (minProfit > 0 && maxProfit > 0) {
- profitColor = 'lime';
- } else if (minProfit < 0 && maxProfit < 0) {
- profitColor = 'red';
- } else {
- profitColor = 'orange';
- }
- }
-
- // 显示
- const openChestElement = document.querySelector('.Inventory_modalContent__3ObSx');
-
- const displayElement = document.createElement('div');
- displayElement.classList.add('ChestStatistics');
- displayElement.style.position = 'absolute';
- displayElement.style.left = `${openChestElement.offsetLeft}px`;
- displayElement.style.top = `${openChestElement.offsetTop}px`;
- displayElement.style.fontSize = '12px';
- displayElement.innerHTML = `
- 总计开箱次数:<br>
- ${chestData["总计开箱数量"]}<br>
- 本次开箱价值:<br>
- ${formatPrice(totalAskValue)}/${formatPrice(totalBidValue)}<br>
- 总计开箱价值:<br>
- ${formatPrice(chestData["总计开箱Ask"])}/${formatPrice(chestData["总计开箱Bid"])}<br>
- `;
-
- const expectedOutputElement = document.createElement('div');
- expectedOutputElement.classList.add('ExpectedOutput');
- expectedOutputElement.style.position = 'absolute';
- expectedOutputElement.style.left = `${openChestElement.offsetLeft}px`;
- expectedOutputElement.style.bottom = `${openChestElement.offsetTop}px`;
- expectedOutputElement.style.fontSize = '12px';
- expectedOutputElement.innerHTML = `
- 预计产出价值:<br>
- ${formatPrice(chestDropData[chestName]["期望产出Ask"]*chestCount)}/${formatPrice(chestDropData[chestName]["期望产出Bid"]*chestCount)}<br>
- `;
-
- const differenceOutputElement = document.createElement('div');
- differenceOutputElement.classList.add('DifferenceOutput');
- differenceOutputElement.style.position = 'absolute';
- differenceOutputElement.style.right = `${openChestElement.offsetLeft}px`;
- differenceOutputElement.style.bottom = `${openChestElement.offsetTop}px`;
- differenceOutputElement.style.fontSize = '12px';
- differenceOutputElement.style.color = differenceValue > 0 ? 'lime' : 'red';
- differenceOutputElement.innerHTML = `
- ${differenceValue > 0 ? '高于期望价值:' : '低于期望价值:'}<br>
- ${formatPrice(Math.abs(differenceValue))}<br>
- `;
-
- // 创建并显示累计偏差值的元素
- const cumulativeDifferenceElement = document.createElement('div');
- cumulativeDifferenceElement.classList.add('CumulativeDifference');
- cumulativeDifferenceElement.style.position = 'absolute';
- cumulativeDifferenceElement.style.right = `${openChestElement.offsetLeft}px`;
- cumulativeDifferenceElement.style.top = `${openChestElement.offsetTop}px`;
- cumulativeDifferenceElement.style.fontSize = '12px';
- cumulativeDifferenceElement.style.color = chestData["累计偏差值"] > 0 ? 'lime' : 'red';
- cumulativeDifferenceElement.innerHTML = `
- <br><br>
- <span style="color: ${profitColor};">本次开箱利润</span><br>
- ${profitRange ? `<span style="color: ${profitColor};">${profitRange}</span>` : `<span style="color: ${profitColor};">${formatPrice(totalAskValue)}/${formatPrice(totalBidValue)}</span>`}<br>
- 累计${chestData["累计偏差值"] > 0 ? '高于期望:' : '低于期望:'}<br>
- ${formatPrice(Math.abs(chestData["累计偏差值"]))}<br>
- `;
-
- openChestElement.appendChild(displayElement);
- openChestElement.appendChild(expectedOutputElement);
- openChestElement.appendChild(differenceOutputElement);
- openChestElement.appendChild(cumulativeDifferenceElement);
-
- // 保存更新的数据到本地存储
- localStorage.setItem('Edible_Tools', JSON.stringify(edibleTools));
- }
- }
-
-
- function calculateTotalValues(itemElements) {
- let totalAskValue = 0;
- let totalBidValue = 0;
-
- itemElements.forEach(itemElement => {
- const itemNameElement = itemElement.querySelector('.Item_iconContainer__5z7j4 use');
- const itemQuantityElement = itemElement.querySelector('.Item_count__1HVvv');
-
- if (itemNameElement && itemQuantityElement) {
- const itemName = getItemNameFromElement(itemNameElement);
- const itemQuantity = parseQuantityString(itemQuantityElement.textContent.trim());
-
- let askPrice = 0;
- let bidPrice = 0;
- let priceColor = '';
-
- // 获取价格
- if (specialItemPrices[itemName] && specialItemPrices[itemName].ask) {
- askPrice = parseFloat(specialItemPrices[itemName].ask);
- bidPrice = parseFloat(specialItemPrices[itemName].bid);
- priceColor = '';
- } else if (marketData?.market?.[itemName]) {
- bidPrice = marketData.market[itemName].bid;
- askPrice = marketData.market[itemName].ask;
- } else {
- console.log(`${itemName} 的价格未找到`);
- }
- const itemTotalAskValue = askPrice * itemQuantity;
- const itemTotalBidValue = bidPrice * itemQuantity;
- totalAskValue += itemTotalAskValue;
- totalBidValue += itemTotalBidValue;
- }
- });
-
- //console.log(totalAskValue);
- return { totalAskValue, totalBidValue };
- }
-
- //更详细的战斗等级显示
- const updateCombatLevel = () => {
- const elements = document.querySelectorAll(".NavigationBar_currentExperience__3GDeX");
-
- if (elements.length === 17) {
- const levels = Array.from(elements).slice(10, 17).map(el => {
- const levelText = parseInt(el.parentNode.parentNode.querySelector(".NavigationBar_textContainer__7TdaI .NavigationBar_level__3C7eR").textContent);
- const decimalPart = parseFloat(el.style.width) / 100;
- return { integerPart: levelText, decimalPart: decimalPart };
- });
-
- let [endurance, intelligence, attack, strength, defense, ranged, magic] = levels;
-
- let combatTypeMax = Math.max(
- 0.5 * (attack.integerPart + strength.integerPart),
- ranged.integerPart,
- magic.integerPart
- );
-
- if (combatTypeMax !== 0.5 * (attack.integerPart + strength.integerPart)) {
- attack.decimalPart = 0;
- strength.decimalPart = 0;
- }
- if (combatTypeMax !== ranged.integerPart) ranged.decimalPart = 0;
- if (combatTypeMax !== magic.integerPart) magic.decimalPart = 0;
-
- let combatLevel = 0.2 * (endurance.integerPart + intelligence.integerPart + defense.integerPart) + 0.4 * combatTypeMax;
- combatLevel = parseFloat(combatLevel.toFixed(2));
- //console.log("combatLevel",combatLevel)
- const integerPart = Math.floor(combatLevel);
- const decimalPart = combatLevel - integerPart;
- //console.log("integerPart",integerPart)
- const list1 = [
- endurance.decimalPart * 0.2,
- intelligence.decimalPart * 0.2,
- attack.decimalPart * 0.2,
- strength.decimalPart * 0.2,
- defense.decimalPart * 0.2,
- ranged.decimalPart * 0.2,
- magic.decimalPart * 0.2
- ];
-
- const list2 = [
- endurance.decimalPart * 0.2,
- intelligence.decimalPart * 0.2,
- attack.decimalPart * 0.2,
- strength.decimalPart * 0.2,
- defense.decimalPart * 0.2,
- ranged.decimalPart * 0.2,
- magic.decimalPart * 0.2,
- ranged.decimalPart * 0.2,
- magic.decimalPart * 0.2
- ];
- //console.log("list1",list1,"\nlist2",list2)
- list1.sort((a, b) => b - a);
- list2.sort((a, b) => b - a);
-
- if (decimalPart === 0.8) {
- combatLevel += list1[0];
- } else {
- let total = 0;
- const maxIterations = Math.floor((1 - decimalPart) / 0.2);
- let iterations = 0;
-
- for (const i of list2) {
- if (iterations >= maxIterations) break;
-
- if ((decimalPart + total + i) < 1) {
- total += i;
- } else {
- break;
- }
-
- iterations++;
- }
- combatLevel = decimalPart + integerPart + total;
- }
-
- elements[15].parentNode.parentNode.parentNode.parentNode.parentNode.querySelector(".NavigationBar_nav__3uuUl .NavigationBar_level__3C7eR").textContent = combatLevel.toFixed(2);
- }
- };
- window.setInterval(updateCombatLevel, 10000);
-
- function OfflineStatistics(modalElement) {
- const itemsContainer = modalElement.querySelectorAll(".OfflineProgressModal_itemList__26h-Y");
-
- let timeContainer = null;
- let getItemContainer = null;
- let spendItemContainer = null;
-
-
- itemsContainer.forEach(container => {
- const labelElement = container.querySelector('.OfflineProgressModal_label__2HwFG');
- if (labelElement) {
- const textContent = labelElement.textContent.trim();
- if (textContent.startsWith("You were offline for") || textContent.startsWith("你离线了")) {
- timeContainer = container;
- } else if (textContent.startsWith("Items gained:") || textContent.startsWith("获得物品:")) {
- getItemContainer = container;
- } else if (textContent.startsWith("You consumed:") || textContent.startsWith("你消耗了:")) {
- spendItemContainer = container;
- }
- }
- });
-
- let TotalSec = null;
- if (timeContainer) {
- const textContent = timeContainer.textContent;
- const match = textContent.match(/(?:(\d+)d\s*)?(?:(\d+)h\s*)?(?:(\d+)m\s*)?(?:(\d+)s)/);
- if (match) {
- let days = parseInt(match[1], 10) || 0;
- let hours = parseInt(match[2], 10) || 0;
- let minutes = parseInt(match[3], 10) || 0;
- let seconds = parseInt(match[4], 10) || 0;
- TotalSec = days * 86400 + hours * 3600 + minutes * 60 + seconds;
- }
- }
-
- let getitemtotalAskValue = 0;
- let getitemtotalBidValue = 0;
- if (getItemContainer) {
- const getitemElements = getItemContainer.querySelectorAll('.Item_itemContainer__x7kH1');
- const { totalAskValue, totalBidValue } = calculateTotalValues(getitemElements);
- getitemtotalAskValue = totalAskValue;
- getitemtotalBidValue = totalBidValue;
- }
-
-
- let spenditemtotalAskValue = 0;
- let spenditemtotalBidValue = 0;
- if (spendItemContainer) {
- const spenditemElements = spendItemContainer.querySelectorAll('.Item_itemContainer__x7kH1');
- const { totalAskValue, totalBidValue } = calculateTotalValues(spenditemElements);
- spenditemtotalAskValue = totalAskValue;
- spenditemtotalBidValue = totalBidValue;
- }
-
- if (timeContainer) {
- const newElement = document.createElement('span');
- newElement.textContent = `利润: ${formatPrice(getitemtotalBidValue - spenditemtotalAskValue)} [${formatPrice((getitemtotalBidValue - spenditemtotalAskValue) / (TotalSec / 3600) * 24)}/天]`;
- newElement.style.float = 'right';
- newElement.style.color = 'gold';
- timeContainer.querySelector(':first-child').appendChild(newElement);
- }
- if (getItemContainer) {
- const newElement = document.createElement('span');
- newElement.textContent = `产出:[${formatPrice(getitemtotalAskValue)}/${formatPrice(getitemtotalBidValue)}]`;
- newElement.style.float = 'right';
- newElement.style.color = 'gold';
- getItemContainer.querySelector(':first-child').appendChild(newElement);
- }
- if (spendItemContainer) {
- const newElement = document.createElement('span');
- newElement.textContent = `成本:[${formatPrice(spenditemtotalAskValue)}/${formatPrice(spenditemtotalBidValue)}]`;
- newElement.style.float = 'right';
- newElement.style.color = 'gold';
- spendItemContainer.querySelector(':first-child').appendChild(newElement);
- }
- }
-
-
- function initObserver() {
- // 选择要观察的目标节点
- const targetNode = document.body;
-
- // 观察器的配置(需要观察子节点的变化)
- const config = { childList: true, subtree: true };
-
- // 创建一个观察器实例并传入回调函数
- const observer = new MutationObserver(mutationsList => {
- for (let mutation of mutationsList) {
- if (mutation.type === 'childList') {
- // 监听到子节点变化
- mutation.addedNodes.forEach(addedNode => {
- // 检查是否是我们关注的 Modal_modalContainer__3B80m 元素被添加
- if (addedNode.classList && addedNode.classList.contains('Modal_modalContainer__3B80m')) {
- // Modal_modalContainer__3B80m 元素被添加,执行处理函数
- //console.log("箱子被打开")
- ShowChestPrice();
- recordChestOpening(addedNode);
-
- // 开始监听箱子图标的变化
- startIconObserver();
- }
- if (addedNode.classList && addedNode.classList.contains('OfflineProgressModal_modalContainer__knnk7')) {
- OfflineStatistics(addedNode);
- console.log("离线报告已创建!")
- }
- if (addedNode.classList && addedNode.classList.contains('MainPanel_subPanelContainer__1i-H9')) {
- if (addedNode.querySelector(".CombatPanel_combatPanel__QylPo")) {
- addBattlePlayerFoodButton();
- addBattlePlayerLootButton();
- }
- }
- });
-
- mutation.removedNodes.forEach(removedNode => {
- // 检查是否是 Modal_modalContainer__3B80m 元素被移除
- if (removedNode.classList && removedNode.classList.contains('Modal_modalContainer__3B80m')) {
- // Modal_modalContainer__3B80m 元素被移除,停止监听箱子图标的变化
- stopIconObserver();
- }
- });
- }
- }
- });
-
- // 以上述配置开始观察目标节点
- observer.observe(targetNode, config);
-
- // 定义箱子图标变化的观察器
- let iconObserver = null;
-
- // 开始监听箱子图标的变化
- function startIconObserver() {
- const chestNameElem = document.querySelector(chestNameSelector);
- if (!chestNameElem) return;
-
- // 创建一个观察器实例来监听图标的变化
- iconObserver = new MutationObserver(() => {
- // 当箱子图标变化时,执行处理函数
- ShowChestPrice();
- });
-
- // 配置观察器的选项
- const iconConfig = { attributes: true, attributeFilter: ['href'] };
-
- // 以上述配置开始观察箱子图标节点
- iconObserver.observe(chestNameElem, iconConfig);
- }
-
- // 停止监听箱子图标的变化
- function stopIconObserver() {
- if (iconObserver) {
- iconObserver.disconnect();
- iconObserver = null;
- }
- }
- }
-
-
- //公会部分代码
- const userLanguage = navigator.language || navigator.userLanguage;
- const isZH = userLanguage.startsWith("zh");
- const updataDealy = 24*60*60*1000; //数据更新时限
- let rateXPDayMap = {};
-
- function hookWS() {
- const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
- const oriGet = dataProperty.get;
-
- dataProperty.get = hookedGet;
- Object.defineProperty(MessageEvent.prototype, "data", dataProperty);
-
- function hookedGet() {
- const socket = this.currentTarget;
- if (!(socket instanceof WebSocket)) {
- return oriGet.call(this);
- }
- if (socket.url.indexOf("api.milkywayidle.com/ws") <= -1 && socket.url.indexOf("api-test.milkywayidle.com/ws") <= -1) {
- return oriGet.call(this);
- }
-
- const message = oriGet.call(this);
- Object.defineProperty(this, "data", { value: message }); // Anti-loop
-
- return handleMessage(message);
- }
- }
-
- function addStatisticsButton() {
- const waitForNavi = () => {
- const targetNode = document.querySelector("div.NavigationBar_minorNavigationLinks__dbxh7"); // 确认这个选择器是否适合你的环境
- if (targetNode) {
- // 创建统计窗口按钮
- let statsButton = document.createElement("div");
- statsButton.setAttribute("class", "NavigationBar_minorNavigationLink__31K7Y");
- statsButton.style.color = "gold";
- statsButton.innerHTML = isZH ? "开箱统计" : "Chest Statistics";
- statsButton.addEventListener("click", () => {
- const edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {};
- const openChestData = edibleTools.Chest_Open_Data || {};
- createVisualizationWindow(openChestData);
- });
-
- // 创建食用工具按钮
- let edibleToolsButton = document.createElement("div");
- edibleToolsButton.setAttribute("class", "NavigationBar_minorNavigationLink__31K7Y");
- edibleToolsButton.style.color = "gold";
- edibleToolsButton.innerHTML = "食用工具";
- edibleToolsButton.addEventListener("click", () => {
- openSettings();
- });
-
- // 将按钮添加到目标节点
- targetNode.insertAdjacentElement("afterbegin", statsButton);
- targetNode.insertAdjacentElement("afterbegin", edibleToolsButton);
-
- //获取图标url格式模板
- item_icon_url = document.querySelector("div[class^='Item_itemContainer'] use")?.getAttribute("href")?.split("#")[0];
-
- addBattlePlayerFoodButton();
- addBattlePlayerLootButton();
- } else {
- setTimeout(waitForNavi, 200);
- }
- };
-
- waitForNavi(); // 开始等待目标节点出现
- }
-
-
-
- //奶牛钉钉
- function handleMessage(message) {
- try {
- let obj = JSON.parse(message);
- if (obj && obj.type === "new_battle") {
- processCombatConsumables(obj);
- }
- if (obj && obj.type === "init_character_data") {
- processAndPrintData();
- addStatisticsButton();
- update_market_list(obj);
- }
- if (obj && obj.type === "guild_updated") {
- const Guild_ID = obj.guild.id;
- const edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {};
- edibleTools.Guild_Data = edibleTools.Guild_Data || {};
- let storedData = edibleTools.Guild_Data || {};
-
- // 判断是否已经存在旧数据
- if (storedData[Guild_ID] && storedData[Guild_ID].guild_updated && storedData[Guild_ID].guild_updated.old.updatedAt) {
- const oldUpdatedAt = new Date(storedData[Guild_ID].guild_updated.new.updatedAt);
- const newUpdatedAt = new Date(obj.guild.updatedAt);
-
- // 计算时间差(单位:毫秒)
- const timeDifference = newUpdatedAt - oldUpdatedAt;
-
- if (timeDifference >= updataDealy) {
- // 更新老数据为新数据
- storedData[Guild_ID].guild_updated.old = storedData[Guild_ID].guild_updated.new;
- // 更新新数据为当前数据
- storedData[Guild_ID].guild_updated.new = {
- experience: obj.guild.experience,
- level: obj.guild.level,
- updatedAt: obj.guild.updatedAt
- };
- } else {
- // 仅更新新数据
- storedData[Guild_ID].guild_updated.new = {
- experience: obj.guild.experience,
- level: obj.guild.level,
- updatedAt: obj.guild.updatedAt
- };
- }
- //计算Δ
- const Delta = {
- Delta_Xp: storedData[Guild_ID].guild_updated.new.experience - storedData[Guild_ID].guild_updated.old.experience,
- Delta_Level: storedData[Guild_ID].guild_updated.new.level - storedData[Guild_ID].guild_updated.old.level,
- Delta_Time: (newUpdatedAt - new Date(storedData[Guild_ID].guild_updated.old.updatedAt)) / 1000, // 转换为秒
- Rate_XP_Hours: (3600*(obj.guild.experience - storedData[Guild_ID].guild_updated.old.experience)/((newUpdatedAt - new Date(storedData[Guild_ID].guild_updated.old.updatedAt)) / 1000)).toFixed(2)
- };
- storedData[Guild_ID].guild_updated.Delta = Delta;
-
- const Guild_TotalXp_div = document.querySelectorAll(".GuildPanel_value__Hm2I9")[1];
- if (Guild_TotalXp_div) {
- const xpText = isZH ? "经验值 / 小时" : "XP / Hour";
-
- Guild_TotalXp_div.insertAdjacentHTML(
- "afterend",
- `<div>${formatPrice(Delta.Rate_XP_Hours)} ${xpText}</div>`
- );
- const Guild_NeedXp_div = document.querySelectorAll(".GuildPanel_value__Hm2I9")[2];
- if (Guild_NeedXp_div) {
- const Guild_NeedXp = document.querySelectorAll(".GuildPanel_value__Hm2I9")[2].textContent.replace(/,/g, '');
- const Time = TimeReset(Guild_NeedXp/Delta.Rate_XP_Hours);
- Guild_NeedXp_div.insertAdjacentHTML(
- "afterend", // 使用 "afterend" 在元素的后面插入内容
- `<div>${Time}</div>`
- );
- }
- }
- } else {
- // 如果没有旧数据,则直接添加新数据
- storedData[Guild_ID] = {
- guild_name: obj.guild.name,
- guild_updated: {
- old: {
- experience: obj.guild.experience,
- level: obj.guild.level,
- updatedAt: obj.guild.updatedAt
- },
- new: {},
- }
- };
- }
-
- // 存储更新后的数据到 localStorage
- edibleTools.Guild_Data = storedData;
- localStorage.setItem('Edible_Tools', JSON.stringify(edibleTools));
- } else if (obj && obj.type === "guild_characters_updated") {
- const edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {};
- edibleTools.Guild_Data = edibleTools.Guild_Data || {};
- let storedData = edibleTools.Guild_Data || {};
- for (const key in obj.guildSharableCharacterMap) {
- if (obj.guildSharableCharacterMap.hasOwnProperty(key)) {
- const Guild_ID = obj.guildCharacterMap[key].guildID;
- const name = obj.guildSharableCharacterMap[key].name;
- const newUpdatedAt = new Date();
- storedData[Guild_ID].guild_player = storedData[Guild_ID].guild_player || {};
- if (storedData[Guild_ID] && storedData[Guild_ID].guild_player && storedData[Guild_ID].guild_player[name] && storedData[Guild_ID].guild_player[name].old && storedData[Guild_ID].guild_player[name].old.updatedAt) {
- const oldUpdatedAt = new Date(storedData[Guild_ID].guild_player[name].old.updatedAt)
- const timeDifference = newUpdatedAt - oldUpdatedAt
- if (timeDifference >= updataDealy) {
- // 更新老数据为新数据
- storedData[Guild_ID].guild_player[name].old = storedData[Guild_ID].guild_player[name].new;
- // 更新新数据为当前数据
- storedData[Guild_ID].guild_player[name].new = {
- id: key,
- gameMode: obj.guildSharableCharacterMap[key].gameMode,
- guildExperience: obj.guildCharacterMap[key].guildExperience,
- updatedAt: newUpdatedAt,
- };
- } else {
- // 仅更新新数据
- storedData[Guild_ID].guild_player[name].new = {
- id: key,
- gameMode: obj.guildSharableCharacterMap[key].gameMode,
- guildExperience: obj.guildCharacterMap[key].guildExperience,
- updatedAt: newUpdatedAt,
- };
- }
- //计算Δ
- const Delta = {
- Delta_Time:(newUpdatedAt - new Date(storedData[Guild_ID].guild_player[name].old.updatedAt)) / 1000,
- Delta_Xp: storedData[Guild_ID].guild_player[name].new.guildExperience - storedData[Guild_ID].guild_player[name].old.guildExperience,
- Rate_XP_Day: (24*3600*(obj.guildCharacterMap[key].guildExperience - storedData[Guild_ID].guild_player[name].old.guildExperience)/((newUpdatedAt - new Date(storedData[Guild_ID].guild_player[name].old.updatedAt)) / 1000)).toFixed(2)
- };
- storedData[Guild_ID].guild_player[name].Delta = Delta;
- rateXPDayMap[name] = Delta.Rate_XP_Day;
- }else {
- storedData[Guild_ID].guild_player[name] = {
- old: {
- id: key,
- gameMode: obj.guildSharableCharacterMap[key].gameMode,
- guildExperience: obj.guildCharacterMap[key].guildExperience,
- updatedAt: newUpdatedAt,
- },
- new:{}
- };
- }
- }
-
- }
- //console.log("测试数据",storedData);
- //console.log("guild_characters_updated", obj);
- updateExperienceDisplay(rateXPDayMap);
- edibleTools.Guild_Data = storedData;
- localStorage.setItem('Edible_Tools', JSON.stringify(edibleTools));
- } else if (obj && obj.type === "market_listings_updated") {
- update_market_list(obj);
- }
-
-
-
-
- } catch (error) {
- console.error("Error processing message:", error);
- }
- return message;
- }
-
- // 订单数据更新
- function update_market_list(date) {
- if (!date) return;
-
- let market_list = JSON.parse(GM_getValue('market_list', '[]'));
-
- // 通用更新
- function updateOrders(orders) {
- orders.forEach(newOrder => {
- const existingOrderIndex = market_list.findIndex(order => order.id === newOrder.id);
- if (existingOrderIndex !== -1) {
- market_list[existingOrderIndex] = newOrder;
- } else {
- market_list.push(newOrder);
- }
- // 给每个订单添加更新时间戳
- newOrder.lastUpdated = new Date().toISOString();
- });
- }
-
- // 更新市场数据
- if (date.type === "init_character_data" && date.myMarketListings) {
- updateOrders(date.myMarketListings);
- } else if (date.type === "market_listings_updated" && date.endMarketListings) {
- updateOrders(date.endMarketListings);
- }
-
- // 保存更新后的数据
- GM_setValue('market_list', JSON.stringify(market_list));
- }
-
- function deleteOrdersBeforeDate() {
- const userInput = prompt("请输入要删除之前的日期 (格式:YYYY-MM-DD)", "");
-
- if (!userInput) return;
-
- // 转换用户输入的日期为 Date 对象
- const userDate = new Date(userInput);
-
- if (isNaN(userDate)) {
- alert("无效的日期格式,请使用 YYYY-MM-DD");
- return;
- }
-
- let market_list = JSON.parse(GM_getValue('market_list', '[]'));
-
- // 过滤出所有在用户选择日期之前的订单
- const filteredMarketList = market_list.filter(order => {
- const orderDate = new Date(order.lastUpdated);
- return orderDate >= userDate;
- });
-
- // 更新并保存新的数据
- GM_setValue('market_list', JSON.stringify(filteredMarketList));
-
- alert("删除成功,已清理日期之前的数据。");
- }
-
- function TimeReset(hours) {
- const totalMinutes = hours * 60;
- const days = Math.floor(totalMinutes / (24 * 60));
- const yudays = totalMinutes % (24 * 60);
- const hrs = Math.floor(yudays / 60);
- const minutes = Math.floor(yudays % 60);
- const dtext = isZH ? "天" : "d";
- const htext = isZH ? "时" : "h";
- const mtext = isZH ? "分" : "m";
- return `${days}${dtext} ${hrs}${htext} ${minutes}${mtext}`;
- }
-
- function updateExperienceDisplay(rateXPDayMap) {
- const trElements = document.querySelectorAll(".GuildPanel_membersTable__1NwIX tbody tr");
- const idleuser_list = [];
- const dtext = isZH ? "天" : "d";
-
- // 将 rateXPDayMap 转换为数组并排序
- const sortedMembers = Object.entries(rateXPDayMap)
- .map(([name, XPdata]) => ({ name, XPdata }))
- .sort((a, b) => b.XPdata - a.XPdata);
-
- sortedMembers.forEach(({ name, XPdata }) => {
- trElements.forEach(tr => {
- const nameElement = tr.querySelector(".CharacterName_name__1amXp");
- const experienceElement = tr.querySelector("td:nth-child(3) > div");
- const activityElement = tr.querySelector('.GuildPanel_activity__9vshh');
-
- if (nameElement && nameElement.textContent.trim() === name) {
- if (activityElement.childElementCount === 0) {
- idleuser_list.push(nameElement.textContent.trim());
- }
-
- if (experienceElement) {
- const newDiv = document.createElement('div');
- newDiv.textContent = `${formatPrice(XPdata)}/${dtext}`;
-
- // 计算颜色
- const rank = sortedMembers.findIndex(member => member.name === name);
- const hue = 120 - (rank * (120 / (sortedMembers.length - 1)));
- newDiv.style.color = `hsl(${hue}, 100%, 50%)`;
-
- experienceElement.insertAdjacentElement('afterend', newDiv);
- }
- return;
- }
- });
- });
-
- update_idleuser_tb(idleuser_list);
- }
-
- function update_idleuser_tb(idleuser_list) {
- const targetElement = document.querySelector('.GuildPanel_noticeMessage__3Txji');
- if (!targetElement) {
- console.error('公会标语元素未找到!');
- return;
- }
- const clonedElement = targetElement.cloneNode(true);
-
- const namesText = idleuser_list.join(', ');
- clonedElement.innerHTML = '';
- clonedElement.textContent = isZH ? `闲置的成员:${namesText}` : `Idle User : ${namesText}`;
- clonedElement.style.color = '#ffcc00';
-
- // 设置复制元素的高度为原元素的25%
- const originalStyle = window.getComputedStyle(targetElement);
- const originalHeight = originalStyle.height;
- const originalMinHeight = originalStyle.minHeight;
- clonedElement.style.height = `25%`;
- clonedElement.style.minHeight = `25%`; // 也设置最小高度
- targetElement.parentElement.appendChild(clonedElement);
- }
-
-
- //箱子数据获取
- function processAndPrintData() {
- const initClientData = localStorage.getItem('initClientData');
- if (!initClientData) return;
- let obj;
- try {
- obj = JSON.parse(initClientData);
- } catch (error) {
- console.error('数据解析失败:', error);
- return;
- }
- if (obj.type !== 'init_client_data') return;
- const item_hrid_to_name = obj.itemDetailMap;
- for (const key in item_hrid_to_name) {
- if (item_hrid_to_name[key] && typeof item_hrid_to_name[key] === 'object' && item_hrid_to_name[key].name) {
- item_hrid_to_name[key] = item_hrid_to_name[key].name;
- }
- }
- const item_name_to_hrid = Object.fromEntries(
- Object.entries(item_hrid_to_name).map(([key, value]) => [value, key])
- );
- const hrid2name = item_hrid_to_name;
- let formattedShopData = {};
-
- // 处理商店数据
- for (let [key, details] of Object.entries(obj.shopItemDetailMap)) {
- const { itemHrid, costs } = details;
- const itemName = hrid2name[itemHrid] || formatItemName(itemHrid.split('/').pop());
-
- costs.forEach(cost => {
- const costItemName = hrid2name[cost.itemHrid] || formatItemName(cost.itemHrid.split('/').pop());
- if (costItemName === "Coin") return;
-
- const costCount = cost.count;
-
- if (!formattedShopData[costItemName]) {
- formattedShopData[costItemName] = { items: {}, 最挣钱: '', BID单价: 0 };
- }
-
- // 计算每种代币购买每个物品的收益
- let bidValue = getSpecialItemPrice(itemName,"bid") || 0;
- let profit = bidValue / costCount;
-
- formattedShopData[costItemName].items[itemName] = {
- 花费: costCount
- };
-
- // 更新最赚钱的物品信息
- if (profit > formattedShopData[costItemName].BID单价) {
- formattedShopData[costItemName].最挣钱 = itemName;
- formattedShopData[costItemName].BID单价 = profit;
- specialItemPrices[costItemName].ask = profit;
- specialItemPrices[costItemName].bid = profit;
- }
- });
- }
- const mostProfitableItems = Object.values(formattedShopData).map(item => item.最挣钱).filter(Boolean);
- //console.log(mostProfitableItems)
- // 处理箱子掉落物数据
-
- for (let iteration = 0; iteration < 4; iteration++) {
- for (let [key, items] of Object.entries(obj.openableLootDropMap)) {
- const boxName = hrid2name[key] || formatItemName(key.split('/').pop());
-
- if (!formattedChestDropData[boxName]) {
- formattedChestDropData[boxName] = { item: {} };
- }
- let TotalAsk = 0;
- let TotalBid = 0;
- let awa = 0;
- items.forEach(item => {
- const { itemHrid, dropRate, minCount, maxCount } = item;
- const itemName = hrid2name[itemHrid] || formatItemName(itemHrid.split('/').pop());
- const expectedYield = ((minCount + maxCount) / 2) * dropRate;
- let bidPrice = -1;
- let askPrice = -1;
- let priceColor = '';
-
- if (specialItemPrices[itemName] && specialItemPrices[itemName].ask) {
- askPrice = parseFloat(specialItemPrices[itemName].ask);
- bidPrice = parseFloat(specialItemPrices[itemName].bid);
- priceColor = '';
- } else if (marketData?.market?.[itemName]) {
- bidPrice = marketData.market[itemName].bid;
- askPrice = marketData.market[itemName].ask;
- } else {
- console.log(`${itemName} 的价格未找到`);
- }
-
- if (formattedChestDropData[boxName].item[itemName] && iteration === 0) {
- // 如果物品已存在,更新期望掉落和相关价格
- const existingItem = formattedChestDropData[boxName].item[itemName];
- existingItem.期望掉落 += expectedYield;
- } else if (iteration === 0) {
- formattedChestDropData[boxName].item[itemName] = {
- 期望掉落: expectedYield,
- };
- }
-
- // 判断 itemName 是否在最挣钱物品列表中
- if (mostProfitableItems.includes(itemName)) {
- priceColor = '#FFb3E6';
- } else if (askPrice === -1 && bidPrice === -1) {
- priceColor = 'yellow';
- } else if (askPrice === -1) {
- askPrice = bidPrice;
- priceColor = '#D95961';
- } else if (bidPrice === -1) {
- priceColor = '#2FC4A7';
- }
-
- const existingItem = formattedChestDropData[boxName].item[itemName];
- existingItem.出售单价 = askPrice;
- existingItem.收购单价 = bidPrice;
- existingItem.出售总价 = (existingItem.出售单价 * existingItem.期望掉落).toFixed(2);
- existingItem.收购总价 = (existingItem.收购单价 * existingItem.期望掉落).toFixed(2);
- existingItem.Color = priceColor;
-
- // 累计总价
- TotalAsk += (askPrice * expectedYield);
- TotalBid += (bidPrice * expectedYield);
- });
-
- formattedChestDropData[boxName] = {
- ...formattedChestDropData[boxName],
- 期望产出Ask: TotalAsk.toFixed(2),
- 期望产出Bid: TotalBid.toFixed(2),
- };
-
- if (!specialItemPrices[boxName]) {
- specialItemPrices[boxName] = {}
- }
-
- specialItemPrices[boxName].ask = formattedChestDropData[boxName].期望产出Ask;
- specialItemPrices[boxName].bid = formattedChestDropData[boxName].期望产出Bid;
- }
- }
-
- for (let itemName in specialItemPrices) {
- if (specialItemPrices.hasOwnProperty(itemName)) {
- marketData.market[itemName] = {
- ask: specialItemPrices[itemName].ask,
- bid: specialItemPrices[itemName].bid
- };
- }
- }
-
- localStorage.setItem('MWITools_marketAPI_json', JSON.stringify(marketData));
- let edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {};
- edibleTools.Chest_Drop_Data = formattedChestDropData;
- localStorage.setItem('Edible_Tools', JSON.stringify(edibleTools));
- // 打印结果
- //console.log("特殊物品价格表:",specialItemPrices)
- //console.log("箱子掉落物列表:", formattedChestDropData);
- //console.log("地牢商店列表:", formattedShopData);
- }
-
- function ShowChestPrice() {
- const modalContainer = document.querySelector(".Modal_modalContainer__3B80m");
- if (!modalContainer) return; // 如果不存在 Modal_modalContainer__3B80m 元素,则直接返回
-
- const chestNameElem = document.querySelector(chestNameSelector);
- if (!chestNameElem) return;
-
- const chestName = getItemNameFromElement(chestNameElem);
- const items = document.querySelectorAll(itemSelector);
-
- const dropListContainer = document.querySelector('.ItemDictionary_openToLoot__1krnv');
- if (!dropListContainer) return; // 检查 dropListContainer 是否存在
-
- const edibleTools = JSON.parse(localStorage.getItem('Edible_Tools'))
- const formattedChestDropData = edibleTools.Chest_Drop_Data;
-
- items.forEach(item => {
- const itemName = getItemNameFromElement(item.querySelector(iconSelector));
- if (!itemName) return; // 检查 itemName 是否存在
-
- const itemData = formattedChestDropData[chestName].item[itemName];
- if (!itemData) return; // 检查 itemData 是否存在
-
- const itemColor = itemData.Color;
- const itemNameElem = item.querySelector('.Item_name__2C42x');
- if (itemNameElem && itemColor) {
- itemNameElem.style.color = itemColor;
- }
- });
-
- const askPrice = formattedChestDropData[chestName]["期望产出Ask"];
- const bidPrice = formattedChestDropData[chestName]["期望产出Bid"];
- if (askPrice && bidPrice) {
-
- const previousResults = dropListContainer.querySelectorAll('.resultDiv');
- previousResults.forEach(result => result.remove());
-
- const createPriceOutput = (label, price) => {
- const priceOutput = document.createElement('div');
- priceOutput.className = 'resultDiv';
- priceOutput.textContent = `${label}: ${formatPrice(price)}`;
- priceOutput.style.color = 'gold';
- priceOutput.style.fontSize = '14px';
- priceOutput.style.fontWeight = '400';
- priceOutput.style.paddingTop = '10px';
- return priceOutput;
- };
-
- const minPriceOutput = createPriceOutput('期望产出 (最低买入价计算)', askPrice);
- const maxPriceOutput = createPriceOutput('期望产出 (最高收购价计算)', bidPrice);
-
- dropListContainer.appendChild(minPriceOutput);
- dropListContainer.appendChild(maxPriceOutput);
-
- }
- }
-
- function processCombatConsumables(obj) {
- battlePlayerFood = {};
- battlePlayerLoot = {};
- battleDuration = (new Date() - new Date(obj.combatStartTime))/1000
- obj.players.forEach(player => {
- battlePlayerFood[player.character.name] = {};
- battlePlayerLoot[player.character.name] = {};
- let minTimeInDays = Infinity;
- let minItemName = "";
-
- player.combatConsumables.forEach(consumable => {
- const itemname = item_hrid_to_name[consumable.itemHrid];
- const timePerUnit = itemname.includes('Coffee') ? 5 : 1;
- const totalTimeInMinutes = consumable.count * timePerUnit;
- const totalTimeInDays = totalTimeInMinutes / (24 * 60);
-
- if (totalTimeInDays < minTimeInDays) {
- minTimeInDays = totalTimeInDays;
- minItemName = itemname;
- }
-
- battlePlayerFood[player.character.name][itemname] = {
- "数量": consumable.count,
- "剩余时间": totalTimeInDays.toFixed(1) + '天',
- "颜色": "Black"
- };
- });
- Object.keys(battlePlayerFood[player.character.name]).forEach(item => {
- if (item === minItemName) {
- battlePlayerFood[player.character.name][item]["颜色"] = "red";
- }
- });
- battlePlayerFood[player.character.name]['剩余时间'] = {
- "数量": minTimeInDays < 1 ? (minTimeInDays * 24).toFixed(1) + '小时' : minTimeInDays.toFixed(1) + '天',
- "颜色": "Black"
- };
-
- Object.values(player.totalLootMap).forEach(Loot => {
- const itemname = item_hrid_to_name[Loot.itemHrid];
- battlePlayerLoot[player.character.name][itemname] = {
- "数量":Loot.count,
- "ID":Loot.itemHrid
- }
- });
-
- });
- }
-
-
- function addBattlePlayerFoodButton() {
- //出警按钮父元素路径
- var tabsContainer = document.querySelector("#root > div > div > div.GamePage_gamePanel__3uNKN > div.GamePage_contentPanel__Zx4FH > div.GamePage_middlePanel__uDts7 > div.GamePage_mainPanel__2njyb > div > div:nth-child(1) > div > div > div > div.TabsComponent_tabsContainer__3BDUp > div > div > div")
- var referenceTab = tabsContainer ? tabsContainer.children[1] : null;
-
- if (!tabsContainer || !referenceTab) {
- return;
- }
-
- if (tabsContainer.querySelector('.Button_battlePlayerFood__custom')) {
- console.log('按钮已存在');
- return;
- }
-
- var battlePlayerFoodButton = document.createElement('div');
- battlePlayerFoodButton.className = referenceTab.className + ' Button_battlePlayerFood__custom';
- battlePlayerFoodButton.setAttribute('script_translatedfrom', 'New Action');
- battlePlayerFoodButton.textContent = '出警';
-
- battlePlayerFoodButton.addEventListener('click', function() {
- let dataHtml = '<div style="display: flex; flex-wrap: nowrap;">';
- for (let player in battlePlayerFood) {
- dataHtml +=
- `<div style="flex: 1 0 auto; min-width: 100px; margin: 10px; padding: 10px; border: 1px solid black;">
- <h3>${player}</h3>`;
- let consumables = battlePlayerFood[player];
- for (let item in consumables) {
- dataHtml += `<p style="color:${consumables[item].颜色};">${item}: ${consumables[item].数量}</p>`;
- }
- dataHtml += '</div>';
- }
- dataHtml += '</div>';
-
- let popup = document.createElement('div');
- popup.style.position = 'fixed';
- popup.style.top = '50%';
- popup.style.left = '50%';
- popup.style.transform = 'translate(-50%, -50%)';
- popup.style.backgroundColor = 'white';
- popup.style.border = '1px solid black';
- popup.style.padding = '10px';
- popup.style.zIndex = '10000';
- popup.style.maxWidth = '75%';
- popup.style.overflowX = 'auto';
- popup.style.whiteSpace = 'nowrap';
- popup.innerHTML = dataHtml;
-
- let closeButton = document.createElement('button');
- closeButton.textContent = '关闭';
- closeButton.style.display = 'block';
- closeButton.style.margin = '20px auto 0 auto';
- closeButton.onclick = function() {
- document.body.removeChild(popup);
- };
- popup.appendChild(closeButton);
-
- document.body.appendChild(popup);
- });
-
- var lastTab = tabsContainer.children[tabsContainer.children.length - 1];
- tabsContainer.insertBefore(battlePlayerFoodButton, lastTab.nextSibling);
-
- var style = document.createElement('style');
- style.innerHTML = `
- .Button_battlePlayerFood__custom {
- background-color: #546ddb;
- color: white;
- }
- `;
- document.head.appendChild(style);
- }
-
-
- function addBattlePlayerLootButton() {
- // 获取按钮父元素路径
- var tabsContainer = document.querySelector("#root > div > div > div.GamePage_gamePanel__3uNKN > div.GamePage_contentPanel__Zx4FH > div.GamePage_middlePanel__uDts7 > div.GamePage_mainPanel__2njyb > div > div:nth-child(1) > div > div > div > div.TabsComponent_tabsContainer__3BDUp > div > div > div");
- var referenceTab = tabsContainer ? tabsContainer.children[1] : null;
-
- if (!tabsContainer || !referenceTab) {
- return;
- }
-
- // 如果按钮已经存在,直接返回
- if (tabsContainer.querySelector('.Button_battlePlayerLoot__custom')) {
- console.log('分赃按钮已存在');
- return;
- }
-
- // 创建按钮
- var battlePlayerLootButton = document.createElement('div');
- battlePlayerLootButton.className = referenceTab.className + ' Button_battlePlayerLoot__custom';
- battlePlayerLootButton.setAttribute('script_translatedfrom', 'New Action');
- battlePlayerLootButton.textContent = '分赃';
-
- // 按钮点击事件
- battlePlayerLootButton.addEventListener('click', function() {
- let dataHtml = '<div style="display: flex; flex-wrap: nowrap; background-color: #131419; padding: 10px; border-radius: 10px; color: white;">';
- const minPrice = 10000;
-
- // 获取所有玩家的总计价格
- let playerPrices = [];
- for (let player in battlePlayerLoot) {
- let totalPrice = 0;
- let lootItems = battlePlayerLoot[player];
- for (let item in lootItems) {
- let bidPrice = getSpecialItemPrice(item,"bid") || 0;
- totalPrice += bidPrice * lootItems[item].数量;
- }
- playerPrices.push({ player, totalPrice });
- }
-
- // 找到眉笔
- let minTotalPricePlayer = null;
- if (playerPrices.length > 1) {
- minTotalPricePlayer = playerPrices.reduce((min, current) =>
- current.totalPrice < min.totalPrice ? current : min
- ).player;
- }
-
- // 显示高价值物品
- for (let player in battlePlayerLoot) {
- let totalPrice = 0;
- dataHtml += `<div style="flex: 1 0 auto; min-width: 100px; margin: 10px; padding: 10px; border-radius: 10px; background-color: #1e1e2f; border: 1px solid #98a7e9;">`;
- dataHtml += `<h3 style="color: white; margin-bottom: 10px;">${player}</h3>`;
-
- // 计算总价格
- let lootItems = battlePlayerLoot[player];
- for (let item in lootItems) {
- let bidPrice = getSpecialItemPrice(item,"bid") || 0;
- totalPrice += bidPrice * lootItems[item].数量;
- }
-
- // 显示总计价格
- if (totalPrice > 0) {
- let color = '#4CAF50';
- if (player === minTotalPricePlayer) {
- color = '#FF0000';
- }
-
- // 计算每天价格
- const pricePerDay = formatPrice((60 * 60 * 24 * totalPrice) / battleDuration);
-
- dataHtml += `<p style="color: ${color}; font-weight: bold;">
- 总计价值: ${formatPrice(totalPrice)}<br>
- 每天收入: ${pricePerDay}</p>`;
- }
-
- // 获取经过筛选和排序后的物品列表
- let sortedItems = Object.keys(lootItems)
- .map(item => {
- let bidPrice = getSpecialItemPrice(item, "bid") || 0;
- return {
- item,
- bidPrice,
- quantity: lootItems[item].数量
- };
- })
- .filter(item => item.bidPrice >= 10000)
- .sort((a, b) => b.bidPrice - a.bidPrice);
-
- let maxQuantityLength = Math.max(...sortedItems.map(item => item.quantity.toString().length));
-
- // 显示前十个物品
- for (let i = 0; i < Math.min(sortedItems.length, 10); i++) {
- let item = sortedItems[i].item;
- let bidPrice = sortedItems[i].bidPrice;
- let quantity = sortedItems[i].quantity;
-
- // 创建图标
- let svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
- svgIcon.setAttribute('width', '20');
- svgIcon.setAttribute('height', '20');
- svgIcon.style.marginRight = '5px';
- svgIcon.style.verticalAlign = 'middle';
-
- let useElement = document.createElementNS('http://www.w3.org/2000/svg', 'use');
- useElement.setAttribute('href', `${item_icon_url}#${lootItems[item].ID.split('/').pop()}`);
- svgIcon.appendChild(useElement);
-
- // 显示物品数量、图标和名称
- dataHtml += `
- <div style="display: flex; align-items: center; background-color: #2c2e45; border-radius: 5px; padding: 5px; margin-bottom: 5px; border: 1px solid white; white-space: nowrap; flex-shrink: 0;">
- <span style="color: white; margin-right: 5px; min-width: ${maxQuantityLength * 10}px; text-align: center;">${quantity}</span>
- ${svgIcon.outerHTML}
- <span style="color: white; white-space: nowrap;">${item}</span>
- </div>`;
- }
- dataHtml += '</div>';
- }
- dataHtml += '</div>';
-
- // 创建弹窗
- let popup = document.createElement('div');
- popup.style.position = 'fixed';
- popup.style.top = '50%';
- popup.style.left = '50%';
- popup.style.transform = 'translate(-50%, -50%)';
- popup.style.backgroundColor = '#131419';
- popup.style.border = '1px solid #98a7e9';
- popup.style.padding = '20px';
- popup.style.borderRadius = '10px';
- popup.style.zIndex = '10000';
- popup.style.maxWidth = '90%';
- popup.style.overflowX = 'auto';
- popup.style.whiteSpace = 'nowrap';
- popup.innerHTML = dataHtml;
-
- // 添加关闭按钮
- let closeButton = document.createElement('button');
- closeButton.textContent = '关闭';
- closeButton.style.display = 'block';
- closeButton.style.margin = '5px auto 0 auto';
- closeButton.style.backgroundColor = '#4357af';
- closeButton.style.color = 'white';
- closeButton.style.border = 'none';
- closeButton.style.padding = '10px 20px';
- closeButton.style.borderRadius = '5px';
- closeButton.style.cursor = 'pointer';
- closeButton.onclick = function() {
- document.body.removeChild(popup);
- };
- popup.appendChild(closeButton);
-
- document.body.appendChild(popup);
- });
-
- // 将按钮插入到最后一个标签后面
- var lastTab = tabsContainer.children[tabsContainer.children.length - 1];
- tabsContainer.insertBefore(battlePlayerLootButton, lastTab.nextSibling);
-
- // 添加按钮样式
- var style = document.createElement('style');
- style.innerHTML = `
- .Button_battlePlayerLoot__custom {
- background-color: #db5454;
- color: white;
- border-radius: 5px;
- padding: 5px 10px;
- cursor: pointer;
- transition: background-color 0.3s ease;
- }
- .Button_battlePlayerLoot__custom:hover {
- background-color: #ff6b6b;
- }
- `;
- document.head.appendChild(style);
- }
-
- //菜单
- GM_registerMenuCommand('打印所有箱子掉落物', function() {
- console.log('箱子掉落物列表:', formattedChestDropData);
- });
-
- function createWindowBase() {
- let windowDiv = document.createElement('div');
- windowDiv.className = 'visualization-window';
- windowDiv.style.position = 'fixed';
- windowDiv.style.top = '50%';
- windowDiv.style.left = '50%';
- windowDiv.style.transform = 'translate(-50%, -50%)';
- windowDiv.style.height = '60%';
- windowDiv.style.backgroundColor = 'white';
- windowDiv.style.border = '1px solid #000';
- windowDiv.style.zIndex = '10000';
- windowDiv.style.padding = '10px';
- windowDiv.style.boxSizing = 'border-box';
- windowDiv.style.display = 'flex';
- windowDiv.style.flexDirection = 'column';
- return windowDiv;
- }
-
- function createVisualizationWindow(chestData) {
- let oldWindow = document.querySelector('.visualization-window');
- if (oldWindow) {
- oldWindow.remove();
- }
- let windowDiv = createWindowBase();
-
- let title = document.createElement('h1');
- title.innerText = '开箱记录';
- title.style.textAlign = 'center';
- windowDiv.appendChild(title);
-
- let contentDiv = document.createElement('div');
- contentDiv.style.flex = '1';
- contentDiv.style.overflowY = 'auto';
-
- // 添加箱子列表
- for (let chestName in chestData) {
- let chest = chestData[chestName];
-
- // 外部容器(带边框)
- let chestBox = document.createElement('div');
- chestBox.style.display = 'flex';
- chestBox.style.alignItems = 'center';
- chestBox.style.border = '1px solid #000';
- chestBox.style.borderRadius = '5px';
- chestBox.style.marginBottom = '10px';
- chestBox.style.padding = '5px';
- chestBox.style.cursor = 'pointer';
- chestBox.style.backgroundColor = '#f9f9f9';
- chestBox.onmouseenter = () => (chestBox.style.backgroundColor = '#e0e0e0');
- chestBox.onmouseleave = () => (chestBox.style.backgroundColor = '#f9f9f9');
-
- // 点击事件绑定到 chestBox
- chestBox.onclick = () => showChestDetails(chestName, chest);
-
- let svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
- svgIcon.setAttribute('width', '24');
- svgIcon.setAttribute('height', '24');
- svgIcon.style.marginRight = '10px';
-
- let useElement = document.createElementNS('http://www.w3.org/2000/svg', 'use');
- try {
- let iconId = item_name_to_hrid[chestName].split('/').pop();
- useElement.setAttribute('href', `${item_icon_url}#${iconId}`);
- } catch (error) {
- console.error(`无法找到宝箱 "${chestName}" 的图标ID:`, error);
- useElement.setAttribute('href', `${item_icon_url}#coin`);
- }
- svgIcon.appendChild(useElement);
-
- let chestText = document.createElement('span');
- chestText.style.flex = '1';
- chestText.style.textAlign = 'left';
- chestText.innerText = `${chestName}: ${chest['总计开箱数量']}`;
-
- chestBox.appendChild(svgIcon);
- chestBox.appendChild(chestText);
-
- contentDiv.appendChild(chestBox);
- }
-
- windowDiv.appendChild(contentDiv);
-
- let footerDiv = document.createElement('div');
- footerDiv.style.display = 'flex';
- footerDiv.style.justifyContent = 'space-between';
- footerDiv.style.marginTop = '10px';
-
- // 关闭按钮
- let closeButton = document.createElement('button');
- closeButton.innerText = '关闭';
- closeButton.onclick = () => document.body.removeChild(windowDiv);
- footerDiv.appendChild(closeButton);
-
- // 删除数据按钮
- let deleteButton = document.createElement('button');
- deleteButton.innerText = '删除数据';
- deleteButton.onclick = () => {
- if (confirm('确定要删除所有开箱数据吗?')) {
- deleteOpenChestData(chestData);
- document.body.removeChild(windowDiv);
- }
- };
- footerDiv.appendChild(deleteButton);
-
- windowDiv.appendChild(footerDiv);
-
- document.body.appendChild(windowDiv);
- }
-
-
-
- function deleteOpenChestData() {
- let edibleToolsData = JSON.parse(localStorage.getItem('Edible_Tools'));
- if (edibleToolsData && edibleToolsData.Chest_Open_Data) {
- edibleToolsData.Chest_Open_Data = {};
- localStorage.setItem('Edible_Tools', JSON.stringify(edibleToolsData));
- }
- }
-
-
- // 显示箱子详细信息
- function showChestDetails(chestName, chestData) {
- let oldWindow = document.querySelector('.visualization-window');
- if (oldWindow) {
- oldWindow.remove();
- }
-
- let detailsWindow = createWindowBase();
- let title = document.createElement('h1');
- title.innerText = chestName;
- detailsWindow.appendChild(title);
-
- let contentDiv = document.createElement('div');
- contentDiv.style.flex = '1';
- contentDiv.style.overflowY = 'auto';
-
- // 显示总计信息
- let totalStats = document.createElement('p');
- totalStats.innerText = `总计开箱数量: ${chestData['总计开箱数量']}\n总计Ask: ${formatPrice(chestData['总计开箱Ask'])}\n总计Bid: ${formatPrice(chestData['总计开箱Bid'])}`;
- contentDiv.appendChild(totalStats);
-
- // 添加物品信息
- for (let itemName in chestData['获得物品']) {
- let item = chestData['获得物品'][itemName];
-
- let itemBox = document.createElement('div');
- itemBox.style.display = 'flex';
- itemBox.style.alignItems = 'center';
- itemBox.style.border = '1px solid #000';
- itemBox.style.borderRadius = '5px';
- itemBox.style.marginBottom = '5px';
- itemBox.style.padding = '5px';
-
- // 添加图标
- let svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
- svgIcon.setAttribute('width', '24');
- svgIcon.setAttribute('height', '24');
- svgIcon.style.marginRight = '10px';
-
- let useElement = document.createElementNS('http://www.w3.org/2000/svg', 'use');
- try {
- let iconId = item_name_to_hrid[itemName].split('/').pop();
- useElement.setAttribute('href', `${item_icon_url}#${iconId}`);
- } catch (error) {
- console.error(`无法找到物品 "${itemName}" 的图标ID:`, error);
- useElement.setAttribute('href', `${item_icon_url}#coin`);
- }
- svgIcon.appendChild(useElement);
-
- // 添加物品名称和数量
- let itemText = document.createElement('span');
- itemText.innerText = `${itemName}: ${formatPrice(item['数量'])}`;
- itemText.style.flex = '1';
-
- itemBox.appendChild(svgIcon);
- itemBox.appendChild(itemText);
-
- contentDiv.appendChild(itemBox);
- }
-
- detailsWindow.appendChild(contentDiv);
-
- let footerDiv = document.createElement('div');
- footerDiv.style.display = 'flex';
- footerDiv.style.justifyContent = 'space-between';
- footerDiv.style.marginTop = '10px';
-
- // 返回按钮
- let backButton = document.createElement('button');
- backButton.innerText = '返回';
- backButton.onclick = () => {
- detailsWindow.remove();
- createVisualizationWindow(JSON.parse(localStorage.getItem('Edible_Tools')).Chest_Open_Data);
- };
- footerDiv.appendChild(backButton);
-
- // 关闭按钮
- let closeButton = document.createElement('button');
- closeButton.innerText = '关闭';
- closeButton.onclick = () => detailsWindow.remove();
- footerDiv.appendChild(closeButton);
-
- detailsWindow.appendChild(footerDiv);
-
- document.body.appendChild(detailsWindow);
- }
-
-
- GM_registerMenuCommand('打印全部开箱记录', function() {
- const edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {};
- const openChestData = edibleTools.Chest_Open_Data || {};
- createVisualizationWindow(openChestData);
- });
-
- GM_registerMenuCommand('打印掉落物列表', function() {
- let dataHtml = '<div style="display: flex; flex-wrap: nowrap;">';
- const minPrice = 10000;
- for (let player in battlePlayerLoot) {
- let totalPrice = 0;
- dataHtml += `<div style="flex: 1 0 auto; min-width: 100px; margin: 10px; padding: 10px; border: 1px solid black;">`;
- dataHtml += `<h3>${player}</h3>`;
-
- let lootItems = battlePlayerLoot[player];
- for (let item in lootItems) {
- let bidPrice = getSpecialItemPrice(item,"bid") || 0;
- totalPrice += bidPrice*lootItems[item].数量
- if (bidPrice > minPrice) {
- dataHtml += `<p>${item}: ${lootItems[item].数量}</p>`;
- }
- }
- if (totalPrice > 0) {
- dataHtml += `<p>总计价格: ${formatPrice(totalPrice)}</p>`;
- }
- dataHtml += '</div>';
- }
- dataHtml += '</div>';
-
- let popup = document.createElement('div');
- popup.style.position = 'fixed';
- popup.style.top = '50%';
- popup.style.left = '50%';
- popup.style.transform = 'translate(-50%, -50%)';
- popup.style.backgroundColor = 'white';
- popup.style.border = '1px solid black';
- popup.style.padding = '10px';
- popup.style.zIndex = '10000';
- popup.style.maxWidth = '75%';
- popup.style.overflowX = 'auto';
- popup.style.whiteSpace = 'nowrap';
- popup.innerHTML = dataHtml;
-
- let closeButton = document.createElement('button');
- closeButton.textContent = '关闭';
- closeButton.style.display = 'block';
- closeButton.style.margin = '20px auto 0 auto';
- closeButton.onclick = function() {
- document.body.removeChild(popup);
- };
- popup.appendChild(closeButton);
-
- document.body.appendChild(popup);
- });
-
- function formatToChinesetime(timestamp) {
- const date = new Date(timestamp);
- const beijingOffset = 8 * 60;
- date.setMinutes(date.getMinutes() + date.getTimezoneOffset() + beijingOffset);
-
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, '0');
- const day = String(date.getDate()).padStart(2, '0');
- const hours = String(date.getHours()).padStart(2, '0');
- const minutes = String(date.getMinutes()).padStart(2, '0');
-
- return `${year}/${month}/${day} ${hours}:${minutes}`;
- }
-
- function openSettings() {
- const tran_market_list = {
- "/market_listing_status/filled": "已完成",
- "/market_listing_status/active": "进行中",
- "/market_listing_status/cancelled": "取消",
- "/market_listing_status/expired":"超时",
- };
- const market_List_Data = JSON.parse(GM_getValue('market_list', '[]'));
- const hrid2name = item_hrid_to_name;
-
- // 格式化数据
- market_List_Data.forEach(item => {
- item.itemName = hrid2name[item.itemHrid] || item.itemHrid;
- if (item.enhancementLevel > 0) {
- item.itemName = `${item.itemName} +${item.enhancementLevel}`;
- }
- item.status = tran_market_list[item.status] || item.status;
- if (item.lastUpdated) {
- item.format_lastUpdated = formatToChinesetime(item.lastUpdated);
- }
- });
-
- const settingsContainer = document.createElement('div');
- settingsContainer.style.position = 'fixed';
- settingsContainer.style.top = '0';
- settingsContainer.style.left = '0';
- settingsContainer.style.width = '100%';
- settingsContainer.style.height = '100%';
- settingsContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
- settingsContainer.style.zIndex = '9999';
- settingsContainer.style.display = 'flex';
- settingsContainer.style.flexDirection = 'column';
-
- // 页面内容
- const Edible_Tools_HTML = `
- <div style="flex: 1; overflow-y: auto; background-color: #fff; padding: 20px;">
- <header style="background-color: #4CAF50; color: white; padding: 10px 20px; text-align: center;">
- <h1>银河奶牛数据库</h1>
- </header>
- <div style="display: flex; flex: 1;">
- <div style="width: 200px; background-color: #f4f4f4; padding: 10px;">
- <button id="showMarketDataBtn" style="width: 100%; padding: 10px; margin: 5px 0; background-color: #ddd; border: none;">市场数据</button>
- <button id="showOpenChestDataBtn" style="width: 100%; padding: 10px; margin: 5px 0; background-color: #ddd; border: none;">开箱数据</button>
- <button id="showEnhancementDataBtn" style="width: 100%; padding: 10px; margin: 5px 0; background-color: #ddd; border: none;">强化数据</button>
- </div>
- <div style="flex: 1; padding: 20px; overflow-y: auto; display: block;" id="showMarketDataPage">
- <h2 style="text-align: center;">市场数据</h2>
- <table class="marketList-table" style="width: 100%; border-collapse: collapse;">
- <thead>
- <tr>
- <th data-sort="id">订单ID</th>
- <th data-sort="characterID">角色ID</th>
- <th data-sort="status">状态</th>
- <th data-sort="isSell">类型</th>
- <th data-sort="itemName">物品</th>
- <th data-sort="orderQuantity">数量</th>
- <th data-sort="filledQuantity">已交易数量</th>
- <th data-sort="price">单价</th>
- <th data-sort="total">贸易额</th>
- <th data-sort="format_lastUpdated">更新时间</th>
- <th>操作</th>
- </tr>
- </thead>
- <tbody id="marketDataTableBody">
- <!-- 数据表会在这里插入 -->
- </tbody>
- </table>
- </div>
- <div style="flex: 1; padding: 20px; overflow-y: auto; display: none;" id="OpenChestDataPage">
- <h2 style="text-align: center;">开箱数据(咕?)</h2>
- </div>
- <div style="flex: 1; padding: 20px; overflow-y: auto; display: none;" id="EnhancementDataPage">
- <h2 style="text-align: center;">强化数据(咕咕~)</h2>
- </div>
- </div>
- </div>
- <button id="closeSettingsBtn" style="position: absolute; top: 10px; right: 10px; padding: 10px 20px; background-color: red; color: white; border: none;">关闭</button>
- `;
- settingsContainer.innerHTML = Edible_Tools_HTML;
- document.body.appendChild(settingsContainer);
- const marketDataPage = document.getElementById('showMarketDataPage');
- const OpenChestDataPage = document.getElementById('OpenChestDataPage');
- const EnhancementDataPage = document.getElementById('EnhancementDataPage');
-
-
- function showMarketData() {
- marketDataPage.style.display = 'block';
- OpenChestDataPage.style.display = 'none';
- EnhancementDataPage.style.display = 'none';
-
- const tableBody = document.getElementById('marketDataTableBody');
- tableBody.innerHTML = market_List_Data.map((row, index) => {
- // 创建图标
- let svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
- svgIcon.setAttribute('width', '20');
- svgIcon.setAttribute('height', '20');
- svgIcon.style.marginRight = '10px';
- svgIcon.style.verticalAlign = 'middle';
-
- let useElement = document.createElementNS('http://www.w3.org/2000/svg', 'use');
- try {
- let iconId = row.itemHrid.split('/').pop();
- useElement.setAttribute('href', `${item_icon_url}#${iconId}`);
- } catch (error) {
- console.error(`无法找到物品的图标ID:`, error);
- useElement.setAttribute('href', `${item_icon_url}#coin`);
- }
-
- svgIcon.appendChild(useElement);
-
- let itemNameWithIcon = `${svgIcon.outerHTML}${row.itemName}`;
-
- return `
- <tr data-index="${index}">
- <td>${row.id}</td>
- <td>${row.characterID}</td>
- <td>${row.status}</td>
- <td>${row.isSell ? '出售' : '收购'}</td>
- <td>${itemNameWithIcon}</td>
- <td>${(row.orderQuantity).toLocaleString()}</td>
- <td>${(row.filledQuantity).toLocaleString()}</td>
- <td>${(row.price).toLocaleString()}</td>
- <td>${(row.price * row.filledQuantity).toLocaleString()}</td>
- <td>${row.format_lastUpdated}</td>
- <td><button class="delete-btn">删除</button></td>
- </tr>
- `;
- }).join('');
- }
-
-
- function ShowOpenChestData() {
- marketDataPage.style.display = 'none';
- OpenChestDataPage.style.display = 'block';
- EnhancementDataPage.style.display = 'none';
- }
-
- function ShowEnhancementData() {
- marketDataPage.style.display = 'none';
- OpenChestDataPage.style.display = 'none';
- EnhancementDataPage.style.display = 'block';
- }
-
- showMarketData();
-
- // 删除单行
- function attachDeleteListeners() {
- document.querySelectorAll('.delete-btn').forEach(button => {
- button.addEventListener('click', (event) => {
- const row = event.target.closest('tr');
- const index = row.getAttribute('data-index');
- market_List_Data.splice(index, 1);
-
- GM_setValue('market_list', JSON.stringify(market_List_Data));// 更新存储的数据
- showMarketData();// 重新渲染表格
- attachDeleteListeners();// 重新绑定删除按钮事件
- });
- });
- }
-
- attachDeleteListeners();// 初始绑定删除按钮事件
-
- // 排序功能
- let sortOrder = { field: null, direction: 1 };// 1 是升序,-1 是降序
-
- function sortTable(column) {
- const field = column.getAttribute('data-sort');
- const direction = sortOrder.field === field && sortOrder.direction === 1 ? -1 : 1;// 切换排序方向
-
- market_List_Data.sort((a, b) => {
- if (field === 'total') {
- return (a.price * a.filledQuantity - b.price * b.filledQuantity) * direction;
- }
- if (typeof a[field] === 'string') {
- return (a[field].localeCompare(b[field])) * direction;
- }
- return (a[field] - b[field]) * direction;
- });
-
- // 更新排序状态
- document.querySelectorAll('th').forEach(th => {
- th.classList.remove('sort-asc', 'sort-desc');
- });
- column.classList.add(direction === 1 ? 'sort-asc' : 'sort-desc');
-
- sortOrder = { field, direction };
-
- showMarketData();
- attachDeleteListeners();
- }
-
- // 给每个表头添加点击事件监听器
- document.querySelectorAll('th').forEach(th => {
- th.addEventListener('click', () => {
- sortTable(th);
- });
- });
- // 切换数据库页面
- document.getElementById('showMarketDataBtn').addEventListener('click', showMarketData);
- document.getElementById('showOpenChestDataBtn').addEventListener('click', ShowOpenChestData);
- document.getElementById('showEnhancementDataBtn').addEventListener('click', ShowEnhancementData);
- // 关闭按钮
- document.getElementById('closeSettingsBtn').addEventListener('click', () => {
- document.body.removeChild(settingsContainer);
- });
-
- // 表格样式
- const style = document.createElement('style');
- style.innerHTML = `
- .marketList-table {
- width: 100%;
- border-collapse: collapse;
- }
-
- .marketList-table, .marketList-table th, .marketList-table td {
- border: 1px solid #ddd;
- }
-
- .marketList-table th, .marketList-table td {
- padding: 10px;
- text-align: center;
- }
-
- .marketList-table th {
- background-color: #f2f2f2;
- cursor: pointer;
- }
-
- .marketList-table th.sort-asc::after {
- content: ' ▲';
- }
-
- .marketList-table th.sort-desc::after {
- content: ' ▼';
- }
- `;
- document.head.appendChild(style);
- }
-
-
-
- GM_registerMenuCommand('删除过时市场数据', deleteOrdersBeforeDate);
- })();