// ==UserScript== // @name [银河奶牛]食用工具 // @namespace http://tampermonkey.net/ // @version 0.463 // @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 // @downloadURL none // ==/UserScript== (async function() { 'use strict'; const isCN = !['en'].some(lang =>localStorage.getItem("i18nextLng")?.toLowerCase()?.startsWith(lang)); 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 battlePlayerData = {}; let battleDuration; let battleRunCount; let now_battle_map; let enhancementLevel; let currentEnhancingIndex = 1; let enhancementData = { [currentEnhancingIndex]: { "强化数据": {}, "其他数据": {} } }; let currentPlayerID = null; let currentPlayerName = null; 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]) ); const e2c = { "Coin": "金币", "Task Token": "任务代币", "Chimerical Token": "奇幻代币", "Sinister Token": "阴森代币", "Enchanted Token": "秘法代币", "Pirate Token": "海盗代币", "Cowbell": "牛铃", "Bag Of 10 Cowbells": "牛铃袋 (10个)", "Purple's Gift": "小紫牛的礼物", "Small Meteorite Cache": "小陨石舱", "Medium Meteorite Cache": "中陨石舱", "Large Meteorite Cache": "大陨石舱", "Small Artisan's Crate": "小工匠匣", "Medium Artisan's Crate": "中工匠匣", "Large Artisan's Crate": "大工匠匣", "Small Treasure Chest": "小宝箱", "Medium Treasure Chest": "中宝箱", "Large Treasure Chest": "大宝箱", "Chimerical Chest": "奇幻宝箱", "Sinister Chest": "阴森宝箱", "Enchanted Chest": "秘法宝箱", "Pirate Chest": "海盗宝箱", "Blue Key Fragment": "蓝色钥匙碎片", "Green Key Fragment": "绿色钥匙碎片", "Purple Key Fragment": "紫色钥匙碎片", "White Key Fragment": "白色钥匙碎片", "Orange Key Fragment": "橙色钥匙碎片", "Brown Key Fragment": "棕色钥匙碎片", "Stone Key Fragment": "石头钥匙碎片", "Dark Key Fragment": "黑暗钥匙碎片", "Burning Key Fragment": "燃烧钥匙碎片", "Chimerical Entry Key": "奇幻钥匙", "Chimerical Chest Key": "奇幻宝箱钥匙", "Sinister Entry Key": "阴森钥匙", "Sinister Chest Key": "阴森宝箱钥匙", "Enchanted Entry Key": "秘法钥匙", "Enchanted Chest Key": "秘法宝箱钥匙", "Pirate Entry Key": "海盗钥匙", "Pirate Chest Key": "海盗宝箱钥匙", "Donut": "甜甜圈", "Blueberry Donut": "蓝莓甜甜圈", "Blackberry Donut": "黑莓甜甜圈", "Strawberry Donut": "草莓甜甜圈", "Mooberry Donut": "哞莓甜甜圈", "Marsberry Donut": "火星莓甜甜圈", "Spaceberry Donut": "太空莓甜甜圈", "Cupcake": "纸杯蛋糕", "Blueberry Cake": "蓝莓蛋糕", "Blackberry Cake": "黑莓蛋糕", "Strawberry Cake": "草莓蛋糕", "Mooberry Cake": "哞莓蛋糕", "Marsberry Cake": "火星莓蛋糕", "Spaceberry Cake": "太空莓蛋糕", "Gummy": "软糖", "Apple Gummy": "苹果软糖", "Orange Gummy": "橙子软糖", "Plum Gummy": "李子软糖", "Peach Gummy": "桃子软糖", "Dragon Fruit Gummy": "火龙果软糖", "Star Fruit Gummy": "杨桃软糖", "Yogurt": "酸奶", "Apple Yogurt": "苹果酸奶", "Orange Yogurt": "橙子酸奶", "Plum Yogurt": "李子酸奶", "Peach Yogurt": "桃子酸奶", "Dragon Fruit Yogurt": "火龙果酸奶", "Star Fruit Yogurt": "杨桃酸奶", "Milking Tea": "挤奶茶", "Foraging Tea": "采摘茶", "Woodcutting Tea": "伐木茶", "Cooking Tea": "烹饪茶", "Brewing Tea": "冲泡茶", "Alchemy Tea": "炼金茶", "Enhancing Tea": "强化茶", "Cheesesmithing Tea": "奶酪锻造茶", "Crafting Tea": "制作茶", "Tailoring Tea": "缝纫茶", "Super Milking Tea": "超级挤奶茶", "Super Foraging Tea": "超级采摘茶", "Super Woodcutting Tea": "超级伐木茶", "Super Cooking Tea": "超级烹饪茶", "Super Brewing Tea": "超级冲泡茶", "Super Alchemy Tea": "超级炼金茶", "Super Enhancing Tea": "超级强化茶", "Super Cheesesmithing Tea": "超级奶酪锻造茶", "Super Crafting Tea": "超级制作茶", "Super Tailoring Tea": "超级缝纫茶", "Ultra Milking Tea": "究极挤奶茶", "Ultra Foraging Tea": "究极采摘茶", "Ultra Woodcutting Tea": "究极伐木茶", "Ultra Cooking Tea": "究极烹饪茶", "Ultra Brewing Tea": "究极冲泡茶", "Ultra Alchemy Tea": "究极炼金茶", "Ultra Enhancing Tea": "究极强化茶", "Ultra Cheesesmithing Tea": "究极奶酪锻造茶", "Ultra Crafting Tea": "究极制作茶", "Ultra Tailoring Tea": "究极缝纫茶", "Gathering Tea": "采集茶", "Gourmet Tea": "美食茶", "Wisdom Tea": "经验茶", "Processing Tea": "加工茶", "Efficiency Tea": "效率茶", "Artisan Tea": "工匠茶", "Catalytic Tea": "催化茶", "Blessed Tea": "福气茶", "Stamina Coffee": "耐力咖啡", "Intelligence Coffee": "智力咖啡", "Defense Coffee": "防御咖啡", "Attack Coffee": "攻击咖啡", "Power Coffee": "力量咖啡", "Ranged Coffee": "远程咖啡", "Magic Coffee": "魔法咖啡", "Super Stamina Coffee": "超级耐力咖啡", "Super Intelligence Coffee": "超级智力咖啡", "Super Defense Coffee": "超级防御咖啡", "Super Attack Coffee": "超级攻击咖啡", "Super Power Coffee": "超级力量咖啡", "Super Ranged Coffee": "超级远程咖啡", "Super Magic Coffee": "超级魔法咖啡", "Ultra Stamina Coffee": "究极耐力咖啡", "Ultra Intelligence Coffee": "究极智力咖啡", "Ultra Defense Coffee": "究极防御咖啡", "Ultra Attack Coffee": "究极攻击咖啡", "Ultra Power Coffee": "究极力量咖啡", "Ultra Ranged Coffee": "究极远程咖啡", "Ultra Magic Coffee": "究极魔法咖啡", "Wisdom Coffee": "经验咖啡", "Lucky Coffee": "幸运咖啡", "Swiftness Coffee": "迅捷咖啡", "Channeling Coffee": "吟唱咖啡", "Critical Coffee": "暴击咖啡", "Poke": "破胆之刺", "Impale": "透骨之刺", "Puncture": "破甲之刺", "Penetrating Strike": "贯心之刺", "Scratch": "爪影斩", "Cleave": "分裂斩", "Maim": "血刃斩", "Crippling Slash": "致残斩", "Smack": "重碾", "Sweep": "重扫", "Stunning Blow": "重锤", "Fracturing Impact": "碎裂冲击", "Shield Bash": "盾击", "Quick Shot": "快速射击", "Aqua Arrow": "流水箭", "Flame Arrow": "烈焰箭", "Rain Of Arrows": "箭雨", "Silencing Shot": "沉默之箭", "Steady Shot": "稳定射击", "Pestilent Shot": "疫病射击", "Penetrating Shot": "贯穿射击", "Water Strike": "流水冲击", "Ice Spear": "冰枪术", "Frost Surge": "冰霜爆裂", "Mana Spring": "法力喷泉", "Entangle": "缠绕", "Toxic Pollen": "剧毒粉尘", "Nature's Veil": "自然菌幕", "Life Drain": "生命吸取", "Fireball": "火球", "Flame Blast": "熔岩爆裂", "Firestorm": "火焰风暴", "Smoke Burst": "烟爆灭影", "Minor Heal": "初级自愈术", "Heal": "自愈术", "Quick Aid": "快速治疗术", "Rejuvenate": "群体治疗术", "Taunt": "嘲讽", "Provoke": "挑衅", "Toughness": "坚韧", "Elusiveness": "闪避", "Precision": "精确", "Berserk": "狂暴", "Elemental Affinity": "元素增幅", "Frenzy": "狂速", "Spike Shell": "尖刺防护", "Arcane Reflection": "奥术反射", "Vampirism": "吸血", "Revive": "复活", "Insanity": "疯狂", "Invincible": "无敌", "Fierce Aura": "物理光环", "Aqua Aura": "流水光环", "Sylvan Aura": "自然光环", "Flame Aura": "火焰光环", "Speed Aura": "速度光环", "Critical Aura": "暴击光环", "Gobo Stabber": "哥布林长剑", "Gobo Slasher": "哥布林关刀", "Gobo Smasher": "哥布林狼牙棒", "Spiked Bulwark": "尖刺重盾", "Werewolf Slasher": "狼人关刀", "Griffin Bulwark": "狮鹫重盾", "Gobo Shooter": "哥布林弹弓", "Vampiric Bow": "吸血弓", "Cursed Bow": "咒怨之弓", "Gobo Boomstick": "哥布林火棍", "Cheese Bulwark": "奶酪重盾", "Verdant Bulwark": "翠绿重盾", "Azure Bulwark": "蔚蓝重盾", "Burble Bulwark": "深紫重盾", "Crimson Bulwark": "绛红重盾", "Rainbow Bulwark": "彩虹重盾", "Holy Bulwark": "神圣重盾", "Wooden Bow": "木弓", "Birch Bow": "桦木弓", "Cedar Bow": "雪松弓", "Purpleheart Bow": "紫心弓", "Ginkgo Bow": "银杏弓", "Redwood Bow": "红杉弓", "Arcane Bow": "神秘弓", "Stalactite Spear": "石钟长枪", "Granite Bludgeon": "花岗岩大棒", "Furious Spear": "狂怒长枪", "Regal Sword": "君王之剑", "Chaotic Flail": "混沌连枷", "Soul Hunter Crossbow": "灵魂猎手弩", "Sundering Crossbow": "裂空之弩", "Frost Staff": "冰霜法杖", "Infernal Battlestaff": "炼狱法杖", "Jackalope Staff": "鹿角兔之杖", "Rippling Trident": "涟漪三叉戟", "Blooming Trident": "绽放三叉戟", "Blazing Trident": "炽焰三叉戟", "Cheese Sword": "奶酪剑", "Verdant Sword": "翠绿剑", "Azure Sword": "蔚蓝剑", "Burble Sword": "深紫剑", "Crimson Sword": "绛红剑", "Rainbow Sword": "彩虹剑", "Holy Sword": "神圣剑", "Cheese Spear": "奶酪长枪", "Verdant Spear": "翠绿长枪", "Azure Spear": "蔚蓝长枪", "Burble Spear": "深紫长枪", "Crimson Spear": "绛红长枪", "Rainbow Spear": "彩虹长枪", "Holy Spear": "神圣长枪", "Cheese Mace": "奶酪钉头锤", "Verdant Mace": "翠绿钉头锤", "Azure Mace": "蔚蓝钉头锤", "Burble Mace": "深紫钉头锤", "Crimson Mace": "绛红钉头锤", "Rainbow Mace": "彩虹钉头锤", "Holy Mace": "神圣钉头锤", "Wooden Crossbow": "木弩", "Birch Crossbow": "桦木弩", "Cedar Crossbow": "雪松弩", "Purpleheart Crossbow": "紫心弩", "Ginkgo Crossbow": "银杏弩", "Redwood Crossbow": "红杉弩", "Arcane Crossbow": "神秘弩", "Wooden Water Staff": "木制水法杖", "Birch Water Staff": "桦木水法杖", "Cedar Water Staff": "雪松水法杖", "Purpleheart Water Staff": "紫心水法杖", "Ginkgo Water Staff": "银杏水法杖", "Redwood Water Staff": "红杉水法杖", "Arcane Water Staff": "神秘水法杖", "Wooden Nature Staff": "木制自然法杖", "Birch Nature Staff": "桦木自然法杖", "Cedar Nature Staff": "雪松自然法杖", "Purpleheart Nature Staff": "紫心自然法杖", "Ginkgo Nature Staff": "银杏自然法杖", "Redwood Nature Staff": "红杉自然法杖", "Arcane Nature Staff": "神秘自然法杖", "Wooden Fire Staff": "木制火法杖", "Birch Fire Staff": "桦木火法杖", "Cedar Fire Staff": "雪松火法杖", "Purpleheart Fire Staff": "紫心火法杖", "Ginkgo Fire Staff": "银杏火法杖", "Redwood Fire Staff": "红杉火法杖", "Arcane Fire Staff": "神秘火法杖", "Eye Watch": "掌上监工", "Snake Fang Dirk": "蛇牙短剑", "Vision Shield": "视觉盾", "Gobo Defender": "哥布林防御者", "Vampire Fang Dirk": "吸血鬼短剑", "Knight's Aegis": "骑士盾", "Treant Shield": "树人盾", "Manticore Shield": "蝎狮盾", "Tome Of Healing": "治疗之书", "Tome Of The Elements": "元素之书", "Watchful Relic": "警戒遗物", "Bishop's Codex": "主教法典", "Cheese Buckler": "奶酪圆盾", "Verdant Buckler": "翠绿圆盾", "Azure Buckler": "蔚蓝圆盾", "Burble Buckler": "深紫圆盾", "Crimson Buckler": "绛红圆盾", "Rainbow Buckler": "彩虹圆盾", "Holy Buckler": "神圣圆盾", "Wooden Shield": "木盾", "Birch Shield": "桦木盾", "Cedar Shield": "雪松盾", "Purpleheart Shield": "紫心盾", "Ginkgo Shield": "银杏盾", "Redwood Shield": "红杉盾", "Arcane Shield": "神秘盾", "Sinister Cape": "阴森斗篷", "Chimerical Quiver": "奇幻箭袋", "Enchanted Cloak": "秘法披风", "Red Culinary Hat": "红色厨师帽", "Snail Shell Helmet": "蜗牛壳头盔", "Vision Helmet": "视觉头盔", "Fluffy Red Hat": "蓬松红帽子", "Corsair Helmet": "掠夺者头盔", "Acrobatic Hood": "杂技师兜帽", "Magician's Hat": "魔术师帽", "Cheese Helmet": "奶酪头盔", "Verdant Helmet": "翠绿头盔", "Azure Helmet": "蔚蓝头盔", "Burble Helmet": "深紫头盔", "Crimson Helmet": "绛红头盔", "Rainbow Helmet": "彩虹头盔", "Holy Helmet": "神圣头盔", "Rough Hood": "粗糙兜帽", "Reptile Hood": "爬行动物兜帽", "Gobo Hood": "哥布林兜帽", "Beast Hood": "野兽兜帽", "Umbral Hood": "暗影兜帽", "Cotton Hat": "棉帽", "Linen Hat": "亚麻帽", "Bamboo Hat": "竹帽", "Silk Hat": "丝帽", "Radiant Hat": "光辉帽", "Dairyhand's Top": "挤奶工上衣", "Forager's Top": "采摘者上衣", "Lumberjack's Top": "伐木工上衣", "Cheesemaker's Top": "奶酪师上衣", "Crafter's Top": "工匠上衣", "Tailor's Top": "裁缝上衣", "Chef's Top": "厨师上衣", "Brewer's Top": "饮品师上衣", "Alchemist's Top": "炼金师上衣", "Enhancer's Top": "强化师上衣", "Gator Vest": "鳄鱼马甲", "Turtle Shell Body": "龟壳胸甲", "Colossus Plate Body": "巨像胸甲", "Demonic Plate Body": "恶魔胸甲", "Anchorbound Plate Body": "锚定胸甲", "Maelstrom Plate Body": "怒涛胸甲", "Marine Tunic": "海洋皮衣", "Revenant Tunic": "亡灵皮衣", "Griffin Tunic": "狮鹫皮衣", "Kraken Tunic": "克拉肯皮衣", "Icy Robe Top": "冰霜袍服", "Flaming Robe Top": "烈焰袍服", "Luna Robe Top": "月神袍服", "Royal Water Robe Top": "皇家水系袍服", "Royal Nature Robe Top": "皇家自然系袍服", "Royal Fire Robe Top": "皇家火系袍服", "Cheese Plate Body": "奶酪胸甲", "Verdant Plate Body": "翠绿胸甲", "Azure Plate Body": "蔚蓝胸甲", "Burble Plate Body": "深紫胸甲", "Crimson Plate Body": "绛红胸甲", "Rainbow Plate Body": "彩虹胸甲", "Holy Plate Body": "神圣胸甲", "Rough Tunic": "粗糙皮衣", "Reptile Tunic": "爬行动物皮衣", "Gobo Tunic": "哥布林皮衣", "Beast Tunic": "野兽皮衣", "Umbral Tunic": "暗影皮衣", "Cotton Robe Top": "棉布袍服", "Linen Robe Top": "亚麻袍服", "Bamboo Robe Top": "竹袍服", "Silk Robe Top": "丝绸袍服", "Radiant Robe Top": "光辉袍服", "Dairyhand's Bottoms": "挤奶工下装", "Forager's Bottoms": "采摘者下装", "Lumberjack's Bottoms": "伐木工下装", "Cheesemaker's Bottoms": "奶酪师下装", "Crafter's Bottoms": "工匠下装", "Tailor's Bottoms": "裁缝下装", "Chef's Bottoms": "厨师下装", "Brewer's Bottoms": "饮品师下装", "Alchemist's Bottoms": "炼金师下装", "Enhancer's Bottoms": "强化师下装", "Turtle Shell Legs": "龟壳腿甲", "Colossus Plate Legs": "巨像腿甲", "Demonic Plate Legs": "恶魔腿甲", "Anchorbound Plate Legs": "锚定腿甲", "Maelstrom Plate Legs": "怒涛腿甲", "Marine Chaps": "航海皮裤", "Revenant Chaps": "亡灵皮裤", "Griffin Chaps": "狮鹫皮裤", "Kraken Chaps": "克拉肯皮裤", "Icy Robe Bottoms": "冰霜袍裙", "Flaming Robe Bottoms": "烈焰袍裙", "Luna Robe Bottoms": "月神袍裙", "Royal Water Robe Bottoms": "皇家水系袍裙", "Royal Nature Robe Bottoms": "皇家自然系袍裙", "Royal Fire Robe Bottoms": "皇家火系袍裙", "Cheese Plate Legs": "奶酪腿甲", "Verdant Plate Legs": "翠绿腿甲", "Azure Plate Legs": "蔚蓝腿甲", "Burble Plate Legs": "深紫腿甲", "Crimson Plate Legs": "绛红腿甲", "Rainbow Plate Legs": "彩虹腿甲", "Holy Plate Legs": "神圣腿甲", "Rough Chaps": "粗糙皮裤", "Reptile Chaps": "爬行动物皮裤", "Gobo Chaps": "哥布林皮裤", "Beast Chaps": "野兽皮裤", "Umbral Chaps": "暗影皮裤", "Cotton Robe Bottoms": "棉袍裙", "Linen Robe Bottoms": "亚麻袍裙", "Bamboo Robe Bottoms": "竹袍裙", "Silk Robe Bottoms": "丝绸袍裙", "Radiant Robe Bottoms": "光辉袍裙", "Enchanted Gloves": "附魔手套", "Pincer Gloves": "蟹钳手套", "Panda Gloves": "熊猫手套", "Magnetic Gloves": "磁力手套", "Dodocamel Gauntlets": "渡渡驼护手", "Sighted Bracers": "瞄准护腕", "Marksman Bracers": "神射护腕", "Chrono Gloves": "时空手套", "Cheese Gauntlets": "奶酪护手", "Verdant Gauntlets": "翠绿护手", "Azure Gauntlets": "蔚蓝护手", "Burble Gauntlets": "深紫护手", "Crimson Gauntlets": "绛红护手", "Rainbow Gauntlets": "彩虹护手", "Holy Gauntlets": "神圣护手", "Rough Bracers": "粗糙护腕", "Reptile Bracers": "爬行动物护腕", "Gobo Bracers": "哥布林护腕", "Beast Bracers": "野兽护腕", "Umbral Bracers": "暗影护腕", "Cotton Gloves": "棉手套", "Linen Gloves": "亚麻手套", "Bamboo Gloves": "竹手套", "Silk Gloves": "丝手套", "Radiant Gloves": "光辉手套", "Collector's Boots": "收藏家靴", "Shoebill Shoes": "鲸头鹳鞋", "Black Bear Shoes": "黑熊鞋", "Grizzly Bear Shoes": "棕熊鞋", "Polar Bear Shoes": "北极熊鞋", "Centaur Boots": "半人马靴", "Sorcerer Boots": "巫师靴", "Cheese Boots": "奶酪靴", "Verdant Boots": "翠绿靴", "Azure Boots": "蔚蓝靴", "Burble Boots": "深紫靴", "Crimson Boots": "绛红靴", "Rainbow Boots": "彩虹靴", "Holy Boots": "神圣靴", "Rough Boots": "粗糙靴", "Reptile Boots": "爬行动物靴", "Gobo Boots": "哥布林靴", "Beast Boots": "野兽靴", "Umbral Boots": "暗影靴", "Cotton Boots": "棉靴", "Linen Boots": "亚麻靴", "Bamboo Boots": "竹靴", "Silk Boots": "丝靴", "Radiant Boots": "光辉靴", "Small Pouch": "小袋子", "Medium Pouch": "中袋子", "Large Pouch": "大袋子", "Giant Pouch": "巨大袋子", "Gluttonous Pouch": "贪食之袋", "Guzzling Pouch": "暴饮之囊", "Necklace Of Efficiency": "效率项链", "Fighter Necklace": "战士项链", "Ranger Necklace": "射手项链", "Wizard Necklace": "巫师项链", "Necklace Of Wisdom": "经验项链", "Necklace Of Speed": "速度项链", "Philosopher's Necklace": "贤者项链", "Earrings Of Gathering": "采集耳环", "Earrings Of Essence Find": "精华发现耳环", "Earrings Of Armor": "护甲耳环", "Earrings Of Regeneration": "恢复耳环", "Earrings Of Resistance": "抗性耳环", "Earrings Of Rare Find": "稀有发现耳环", "Earrings Of Critical Strike": "暴击耳环", "Philosopher's Earrings": "贤者耳环", "Ring Of Gathering": "采集戒指", "Ring Of Essence Find": "精华发现戒指", "Ring Of Armor": "护甲戒指", "Ring Of Regeneration": "恢复戒指", "Ring Of Resistance": "抗性戒指", "Ring Of Rare Find": "稀有发现戒指", "Ring Of Critical Strike": "暴击戒指", "Philosopher's Ring": "贤者戒指", "Basic Task Badge": "基础任务徽章", "Advanced Task Badge": "高级任务徽章", "Expert Task Badge": "专家任务徽章", "Celestial Brush": "星空刷子", "Cheese Brush": "奶酪刷子", "Verdant Brush": "翠绿刷子", "Azure Brush": "蔚蓝刷子", "Burble Brush": "深紫刷子", "Crimson Brush": "绛红刷子", "Rainbow Brush": "彩虹刷子", "Holy Brush": "神圣刷子", "Celestial Shears": "星空剪刀", "Cheese Shears": "奶酪剪刀", "Verdant Shears": "翠绿剪刀", "Azure Shears": "蔚蓝剪刀", "Burble Shears": "深紫剪刀", "Crimson Shears": "绛红剪刀", "Rainbow Shears": "彩虹剪刀", "Holy Shears": "神圣剪刀", "Celestial Hatchet": "星空斧头", "Cheese Hatchet": "奶酪斧头", "Verdant Hatchet": "翠绿斧头", "Azure Hatchet": "蔚蓝斧头", "Burble Hatchet": "深紫斧头", "Crimson Hatchet": "绛红斧头", "Rainbow Hatchet": "彩虹斧头", "Holy Hatchet": "神圣斧头", "Celestial Hammer": "星空锤子", "Cheese Hammer": "奶酪锤子", "Verdant Hammer": "翠绿锤子", "Azure Hammer": "蔚蓝锤子", "Burble Hammer": "深紫锤子", "Crimson Hammer": "绛红锤子", "Rainbow Hammer": "彩虹锤子", "Holy Hammer": "神圣锤子", "Celestial Chisel": "星空凿子", "Cheese Chisel": "奶酪凿子", "Verdant Chisel": "翠绿凿子", "Azure Chisel": "蔚蓝凿子", "Burble Chisel": "深紫凿子", "Crimson Chisel": "绛红凿子", "Rainbow Chisel": "彩虹凿子", "Holy Chisel": "神圣凿子", "Celestial Needle": "星空针", "Cheese Needle": "奶酪针", "Verdant Needle": "翠绿针", "Azure Needle": "蔚蓝针", "Burble Needle": "深紫针", "Crimson Needle": "绛红针", "Rainbow Needle": "彩虹针", "Holy Needle": "神圣针", "Celestial Spatula": "星空锅铲", "Cheese Spatula": "奶酪锅铲", "Verdant Spatula": "翠绿锅铲", "Azure Spatula": "蔚蓝锅铲", "Burble Spatula": "深紫锅铲", "Crimson Spatula": "绛红锅铲", "Rainbow Spatula": "彩虹锅铲", "Holy Spatula": "神圣锅铲", "Celestial Pot": "星空壶", "Cheese Pot": "奶酪壶", "Verdant Pot": "翠绿壶", "Azure Pot": "蔚蓝壶", "Burble Pot": "深紫壶", "Crimson Pot": "绛红壶", "Rainbow Pot": "彩虹壶", "Holy Pot": "神圣壶", "Celestial Alembic": "星空蒸馏器", "Cheese Alembic": "奶酪蒸馏器", "Verdant Alembic": "翠绿蒸馏器", "Azure Alembic": "蔚蓝蒸馏器", "Burble Alembic": "深紫蒸馏器", "Crimson Alembic": "绛红蒸馏器", "Rainbow Alembic": "彩虹蒸馏器", "Holy Alembic": "神圣蒸馏器", "Celestial Enhancer": "星空强化器", "Cheese Enhancer": "奶酪强化器", "Verdant Enhancer": "翠绿强化器", "Azure Enhancer": "蔚蓝强化器", "Burble Enhancer": "深紫强化器", "Crimson Enhancer": "绛红强化器", "Rainbow Enhancer": "彩虹强化器", "Holy Enhancer": "神圣强化器", "Milk": "牛奶", "Verdant Milk": "翠绿牛奶", "Azure Milk": "蔚蓝牛奶", "Burble Milk": "深紫牛奶", "Crimson Milk": "绛红牛奶", "Rainbow Milk": "彩虹牛奶", "Holy Milk": "神圣牛奶", "Cheese": "奶酪", "Verdant Cheese": "翠绿奶酪", "Azure Cheese": "蔚蓝奶酪", "Burble Cheese": "深紫奶酪", "Crimson Cheese": "绛红奶酪", "Rainbow Cheese": "彩虹奶酪", "Holy Cheese": "神圣奶酪", "Log": "原木", "Birch Log": "白桦原木", "Cedar Log": "雪松原木", "Purpleheart Log": "紫心原木", "Ginkgo Log": "银杏原木", "Redwood Log": "红杉原木", "Arcane Log": "神秘原木", "Lumber": "木板", "Birch Lumber": "白桦木板", "Cedar Lumber": "雪松木板", "Purpleheart Lumber": "紫心木板", "Ginkgo Lumber": "银杏木板", "Redwood Lumber": "红杉木板", "Arcane Lumber": "神秘木板", "Rough Hide": "粗糙兽皮", "Reptile Hide": "爬行动物皮", "Gobo Hide": "哥布林皮", "Beast Hide": "野兽皮", "Umbral Hide": "暗影皮", "Rough Leather": "粗糙皮革", "Reptile Leather": "爬行动物皮革", "Gobo Leather": "哥布林皮革", "Beast Leather": "野兽皮革", "Umbral Leather": "暗影皮革", "Cotton": "棉花", "Flax": "亚麻", "Bamboo Branch": "竹子", "Cocoon": "蚕茧", "Radiant Fiber": "光辉纤维", "Cotton Fabric": "棉花布料", "Linen Fabric": "亚麻布料", "Bamboo Fabric": "竹子布料", "Silk Fabric": "丝绸", "Radiant Fabric": "光辉布料", "Egg": "鸡蛋", "Wheat": "小麦", "Sugar": "糖", "Blueberry": "蓝莓", "Blackberry": "黑莓", "Strawberry": "草莓", "Mooberry": "哞莓", "Marsberry": "火星莓", "Spaceberry": "太空莓", "Apple": "苹果", "Orange": "橙子", "Plum": "李子", "Peach": "桃子", "Dragon Fruit": "火龙果", "Star Fruit": "杨桃", "Arabica Coffee Bean": "低级咖啡豆", "Robusta Coffee Bean": "中级咖啡豆", "Liberica Coffee Bean": "高级咖啡豆", "Excelsa Coffee Bean": "特级咖啡豆", "Fieriosa Coffee Bean": "火山咖啡豆", "Spacia Coffee Bean": "太空咖啡豆", "Green Tea Leaf": "绿茶叶", "Black Tea Leaf": "黑茶叶", "Burble Tea Leaf": "紫茶叶", "Moolong Tea Leaf": "哞龙茶叶", "Red Tea Leaf": "红茶叶", "Emp Tea Leaf": "虚空茶叶", "Catalyst Of Coinification": "点金催化剂", "Catalyst Of Decomposition": "分解催化剂", "Catalyst Of Transmutation": "转化催化剂", "Prime Catalyst": "至高催化剂", "Snake Fang": "蛇牙", "Shoebill Feather": "鲸头鹳羽毛", "Snail Shell": "蜗牛壳", "Crab Pincer": "蟹钳", "Turtle Shell": "乌龟壳", "Marine Scale": "海洋鳞片", "Treant Bark": "树皮", "Centaur Hoof": "半人马蹄", "Luna Wing": "月神翼", "Gobo Rag": "哥布林抹布", "Goggles": "护目镜", "Magnifying Glass": "放大镜", "Eye Of The Watcher": "观察者之眼", "Icy Cloth": "冰霜织物", "Flaming Cloth": "烈焰织物", "Sorcerer's Sole": "魔法师鞋底", "Chrono Sphere": "时空球", "Frost Sphere": "冰霜球", "Panda Fluff": "熊猫绒", "Black Bear Fluff": "黑熊绒", "Grizzly Bear Fluff": "棕熊绒", "Polar Bear Fluff": "北极熊绒", "Red Panda Fluff": "小熊猫绒", "Magnet": "磁铁", "Stalactite Shard": "钟乳石碎片", "Living Granite": "花岗岩", "Colossus Core": "巨像核心", "Vampire Fang": "吸血鬼之牙", "Werewolf Claw": "狼人之爪", "Revenant Anima": "亡者之魂", "Soul Fragment": "灵魂碎片", "Infernal Ember": "地狱余烬", "Demonic Core": "恶魔核心", "Griffin Leather": "狮鹫之皮", "Manticore Sting": "蝎狮之刺", "Jackalope Antler": "鹿角兔之角", "Dodocamel Plume": "渡渡驼之翎", "Griffin Talon": "狮鹫之爪", "Acrobat's Ribbon": "杂技师彩带", "Magician's Cloth": "魔术师织物", "Chaotic Chain": "混沌锁链", "Cursed Ball": "诅咒之球", "Royal Cloth": "皇家织物", "Knight's Ingot": "骑士之锭", "Bishop's Scroll": "主教卷轴", "Regal Jewel": "君王宝石", "Sundering Jewel": "裂空宝石", "Marksman Brooch": "神射胸针", "Corsair Crest": "掠夺者徽章", "Damaged Anchor": "破损船锚", "Maelstrom Plating": "怒涛甲片", "Kraken Leather": "克拉肯皮革", "Kraken Fang": "克拉肯之牙", "Butter Of Proficiency": "精通之油", "Thread Of Expertise": "专精之线", "Branch Of Insight": "洞察之枝", "Gluttonous Energy": "贪食能量", "Guzzling Energy": "暴饮能量", "Milking Essence": "挤奶精华", "Foraging Essence": "采摘精华", "Woodcutting Essence": "伐木精华", "Cheesesmithing Essence": "奶酪锻造精华", "Crafting Essence": "制作精华", "Tailoring Essence": "缝纫精华", "Cooking Essence": "烹饪精华", "Brewing Essence": "冲泡精华", "Alchemy Essence": "炼金精华", "Enhancing Essence": "强化精华", "Swamp Essence": "沼泽精华", "Aqua Essence": "海洋精华", "Jungle Essence": "丛林精华", "Gobo Essence": "哥布林精华", "Eyessence": "眼精华", "Sorcerer Essence": "法师精华", "Bear Essence": "熊熊精华", "Golem Essence": "魔像精华", "Twilight Essence": "暮光精华", "Abyssal Essence": "地狱精华", "Chimerical Essence": "奇幻精华", "Sinister Essence": "阴森精华", "Enchanted Essence": "秘法精华", "Pirate Essence": "海盗精华", "Task Crystal": "任务水晶", "Star Fragment": "星光碎片", "Pearl": "珍珠", "Amber": "琥珀", "Garnet": "石榴石", "Jade": "翡翠", "Amethyst": "紫水晶", "Moonstone": "月亮石", "Sunstone": "太阳石", "Philosopher's Stone": "贤者之石", "Crushed Pearl": "珍珠碎片", "Crushed Amber": "琥珀碎片", "Crushed Garnet": "石榴石碎片", "Crushed Jade": "翡翠碎片", "Crushed Amethyst": "紫水晶碎片", "Crushed Moonstone": "月亮石碎片", "Crushed Sunstone": "太阳石碎片", "Crushed Philosopher's Stone": "贤者之石碎片", "Shard Of Protection": "保护碎片", "Mirror Of Protection": "保护之镜" } let specialItemPrices = { 'Coin': { ask: 1, bid: 1 }, // 默认的特殊物品价值,包括 ask 和 bid 价值 'Cowbell': { ask: getSpecialItemPrice('Bag Of 10 Cowbells', 'ask') / 10 || 32000, bid: getSpecialItemPrice('Bag Of 10 Cowbells', 'bid') / 10 || 30000 }, 'Chimerical Token': { ask: getSpecialItemPrice('Chimerical Essence', 'ask') || 600, bid: getSpecialItemPrice('Chimerical Essence', 'bid') || 600 }, 'Sinister Token': { ask: getSpecialItemPrice('Sinister Essence', 'ask') || 1100, bid: getSpecialItemPrice('Sinister Essence', 'bid') || 1000 }, 'Enchanted Token': { ask: getSpecialItemPrice('Enchanted Essence', 'ask') || 1800, bid: getSpecialItemPrice('Enchanted Essence', 'bid') || 1700 }, }; const auraAbilities = new Set([ 'revive', 'insanity', 'invincible', 'fierce_aura', 'aqua_aura', 'sylvan_aura', 'flame_aura', 'speed_aura', 'critical_aura' ]); //公会部分代码 const updataDealy = 24*60*60*1000; //数据更新时限 let rateXPDayMap = {}; 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(); marketData.market.Coin.ask = 1; marketData.market.Coin.bid = 1; } 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; } 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,n = 1) { const isNegative = value < 0; value = Math.abs(value); if (value >= 1e13 / n) { return (isNegative ? '-' : '') + (value / 1e12).toFixed(1) + 'T'; } else if (value >= 1e10 / n) { return (isNegative ? '-' : '') + (value / 1e9).toFixed(1) + 'B'; } else if (value >= 1e7 / n) { return (isNegative ? '-' : '') + (value / 1e6).toFixed(1) + 'M'; } else if (value >= 1e4 / n) { 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 || {}; // 确保当前玩家的开箱数据结构存在 if (!currentPlayerID || !currentPlayerName) { console.error("无法获取当前玩家的 ID 或昵称"); return; } edibleTools.Chest_Open_Data[currentPlayerID] = edibleTools.Chest_Open_Data[currentPlayerID] || { 玩家昵称: currentPlayerName, 开箱数据: {} }; let chestOpenData = edibleTools.Chest_Open_Data[currentPlayerID].开箱数据; 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') || 3000e3, keyBid: getSpecialItemPrice('Chimerical Chest Key', 'bid') || 3000e3, entryAsk: getSpecialItemPrice('Chimerical Entry Key', 'ask') || 280e3, entryBid: getSpecialItemPrice('Chimerical Entry Key', 'bid') || 280e3 }, "Sinister Chest": { keyAsk: getSpecialItemPrice('Sinister Chest Key', 'ask') || 6000e3, keyBid: getSpecialItemPrice('Sinister Chest Key', 'bid') || 5400e3, entryAsk: getSpecialItemPrice('Sinister Entry Key', 'ask') || 300e3, entryBid: getSpecialItemPrice('Sinister Entry Key', 'bid') || 280e3 }, "Enchanted Chest": { keyAsk: getSpecialItemPrice('Enchanted Chest Key', 'ask') || 7600e3, keyBid: getSpecialItemPrice('Enchanted Chest Key', 'bid') || 7200e3, entryAsk: getSpecialItemPrice('Enchanted Entry Key', 'ask') || 360e3, entryBid: getSpecialItemPrice('Enchanted Entry Key', 'bid') || 360e3 }, "Enchanted Chest": { keyAsk: getSpecialItemPrice('Pirate Chest Key', 'ask') || 10000e3, keyBid: getSpecialItemPrice('Pirate Chest Key', 'bid') || 10000e3, entryAsk: getSpecialItemPrice('Pirate Entry Key', 'ask') || 460e3, entryBid: getSpecialItemPrice('Pirate Entry Key', 'bid') || 440e3 } }; 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 = ` 总计开箱次数:
${chestData["总计开箱数量"]}
本次开箱价值:
${formatPrice(totalAskValue)}/${formatPrice(totalBidValue)}
总计开箱价值:
${formatPrice(chestData["总计开箱Ask"])}/${formatPrice(chestData["总计开箱Bid"])}
`; 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 = ` 预计产出价值:
${formatPrice(chestDropData[chestName]["期望产出Ask"]*chestCount)}/${formatPrice(chestDropData[chestName]["期望产出Bid"]*chestCount)}
`; 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 ? '高于期望价值:' : '低于期望价值:'}
${formatPrice(Math.abs(differenceValue))}
`; // 创建并显示累计偏差值的元素 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 = `

本次开箱利润
${profitRange ? `${profitRange}` : `${formatPrice(totalAskValue)}/${formatPrice(totalBidValue)}`}
累计${chestData["累计偏差值"] > 0 ? '高于期望:' : '低于期望:'}
${formatPrice(Math.abs(chestData["累计偏差值"]))}
`; 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("Offline duration") || textContent.startsWith("你离线了") || textContent.startsWith("离线时间")) { timeContainer = container; } else if (textContent.startsWith("Items gained") || textContent.startsWith("获得物品:") || textContent.startsWith("获得物品")) { getItemContainer = container; } else if (textContent.startsWith("Items consumed") || textContent.startsWith("你消耗了:") || 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,10)} [${formatPrice((getitemtotalBidValue - spenditemtotalAskValue) / (TotalSec / 3600) * 24,10)}/天]`; newElement.style.color = 'gold'; newElement.style.whiteSpace = 'nowrap'; newElement.style.marginLeft = 'auto'; 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'; newElement.style.whiteSpace = 'nowrap'; 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'; newElement.style.whiteSpace = 'nowrap'; 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(); } else if (addedNode.querySelector('.EnhancingPanel_enhancingPanel__ysWpV')) { updateEnhancementUI(); } } }); 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; } } } 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 = isCN ? "开箱统计" : "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 = isCN ? "食用工具" : "Edible Tools"; 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); } else if (obj && obj.type === "init_character_data") { now_battle_map = undefined; processCharacterData(obj); addStatisticsButton(); update_market_list(obj); } else if (obj && obj.type === "action_completed" && obj.endCharacterAction) { const actionHrid = obj.endCharacterAction.actionHrid; if (actionHrid === "/actions/enhancing/enhance") { processEnhancementData(obj); } else if (actionHrid.startsWith("/actions/combat/")) { now_battle_map = actionHrid; } } else 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 = isCN ? "经验值 / 小时" : "XP / Hour"; Guild_TotalXp_div.insertAdjacentHTML( "afterend", `
${formatPrice(Delta.Rate_XP_Hours)} ${xpText}
` ); 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" 在元素的后面插入内容 `
${Time}
` ); } } } 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 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 = isCN ? "天" : "d"; const htext = isCN ? "时" : "h"; const mtext = isCN ? "分" : "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 = isCN ? "天" : "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 = isCN ? `闲置的成员:${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 processCharacterData(init_character_data) { const initClientData = localStorage.getItem('initClientData'); if (!initClientData) return; let init_client_data try { init_client_data = JSON.parse(initClientData); } 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]) ); const hrid2name = item_hrid_to_name; const character = init_character_data.character; if (character) { currentPlayerID = character.id; currentPlayerName = character.name; } let formattedShopData = {}; if (init_character_data?.characterActions[0]?.actionHrid?.startsWith("/actions/combat/")) {now_battle_map = init_character_data.characterActions[0].actionHrid} // 处理商店数据 for (let [key, details] of Object.entries(init_client_data.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(init_client_data.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)); //处理战斗地图数据 const combatMaps = {}; const actionDetailMap = init_client_data.actionDetailMap; for (const [actionHrid, actionDetail] of Object.entries(actionDetailMap)) { if (!actionHrid.startsWith("/actions/combat/")) continue; if (!actionDetail.combatZoneInfo || actionDetail.combatZoneInfo.isDungeon) continue; const fightInfo = actionDetail.combatZoneInfo.fightInfo; const randomSpawnInfo = fightInfo?.randomSpawnInfo; const spawns = randomSpawnInfo?.spawns; if (!spawns || spawns.length === 0) continue; // 确定地图类型 let mapType = "群战"; if (spawns.length === 1) { mapType = "单怪"; } if (actionHrid.includes("_elite") && mapType === "群战") { mapType = "群战(精英)"; } const monsterGen = {}; const maxSpawnCount = randomSpawnInfo.maxSpawnCount; const maxTotalStrength = randomSpawnInfo.maxTotalStrength; const expectedCounts = calculateExpectedSpawns(spawns, maxSpawnCount, maxTotalStrength); spawns.forEach(spawn => { monsterGen[spawn.combatMonsterHrid] = { 期望数量: expectedCounts[spawn.combatMonsterHrid], 精英等级: spawn.eliteTier }; }); // 处理BOSS数据 const bossData = {}; const bossSpawns = fightInfo.bossSpawns; const battlesPerBoss = fightInfo.battlesPerBoss; if (bossSpawns && bossSpawns.length > 0) { bossSpawns.forEach(boss => { if (boss.combatMonsterHrid) { bossData[boss.combatMonsterHrid] = { 精英等级: boss.eliteTier }; } }); } combatMaps[actionHrid] = { 地图类型: mapType, BOSS波次: battlesPerBoss || 0, 小怪生成: monsterGen, BOSS数据: Object.keys(bossData).length > 0 ? bossData : "" }; } const combatMobDropData = {}; const monsterMap = init_client_data.combatMonsterDetailMap; for (const [monsterHrid, monsterData] of Object.entries(monsterMap)) { const formattedDrops = { 怪物名称: monsterData.name, 普通掉落: [], 稀有掉落: [] }; // 处理普通掉落表 if (monsterData.dropTable) { monsterData.dropTable.forEach(drop => { formattedDrops.普通掉落.push({ 掉落物名称: item_hrid_to_name[drop.itemHrid] || drop.itemHrid, 掉落物Hrid: drop.itemHrid, 掉落几率: drop.dropRate, 掉落数量: (drop.minCount + drop.maxCount) / 2, 精英门槛: drop.minEliteTier }); }); } // 处理稀有掉落表 if (monsterData.rareDropTable) { monsterData.rareDropTable.forEach(drop => { formattedDrops.稀有掉落.push({ 掉落物名称: item_hrid_to_name[drop.itemHrid] || drop.itemHrid, 掉落物Hrid: drop.itemHrid, 掉落几率: drop.dropRate, 掉落数量: (drop.minCount + drop.maxCount) / 2, 精英门槛: drop.minEliteTier }); }); } combatMobDropData[monsterHrid] = formattedDrops; } let edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {}; edibleTools = { ...edibleTools, Chest_Drop_Data: formattedChestDropData, Combat_Data: { Combat_Map_Data: combatMaps ,Combat_Mob_Drop_Data: combatMobDropData} }; edibleTools.Chest_Open_Data = edibleTools.Chest_Open_Data || {}; if (edibleTools.Chest_Open_Data && !edibleTools.Chest_Open_Data[0]) { const oldData = { ...edibleTools.Chest_Open_Data }; edibleTools.Chest_Open_Data = {}; edibleTools.Chest_Open_Data[0] = { 玩家昵称: "老版本开箱数据", 开箱数据: oldData }; } edibleTools.Chest_Open_Data[currentPlayerID] = edibleTools.Chest_Open_Data[currentPlayerID] || { 玩家昵称: currentPlayerName, 开箱数据: {} }; try { localStorage.setItem('Edible_Tools', JSON.stringify(edibleTools)); } catch (error) { console.error('保存数据时发生错误:', error); } // 打印结果 //console.log("特殊物品价格表:",specialItemPrices) //console.log("箱子掉落物列表:", formattedChestDropData); //console.log("地牢商店列表:", formattedShopData); //console.log("战斗地图列表",combatMaps) //console.log("怪物掉落列表",combatMobDropData) } function calculateExpectedSpawns(spawns, maxSpawnCount, maxTotalStrength) { const monsterList = spawns.map(s => ({ hrid: s.combatMonsterHrid, strength: s.strength })); const spawnProbability = 1 / spawns.length; const dp = Array.from({ length: maxSpawnCount + 1 }, () => ({})); dp[0][0] = 1; const expectedCounts = {}; monsterList.forEach(m => { expectedCounts[m.hrid] = 0; }); for (let pos = 0; pos < maxSpawnCount; pos++) { const currentDP = dp[pos]; const nextDP = dp[pos + 1] = {}; for (const [currentStrengthStr, prob] of Object.entries(currentDP)) { const currentStrength = parseInt(currentStrengthStr); for (const monster of monsterList) { const newStrength = currentStrength + monster.strength; if (newStrength > maxTotalStrength) continue; const transitionProb = prob * spawnProbability; nextDP[newStrength] = (nextDP[newStrength] || 0) + transitionProb; expectedCounts[monster.hrid] += transitionProb; } } } return expectedCounts; } 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(isCN ? '期望产出 (最低买入价计算)' : 'Expected Output (Ask Price)', askPrice); const maxPriceOutput = createPriceOutput(isCN ? '期望产出 (最高收购价计算)' : 'Expected Output (Bid Price)', bidPrice); dropListContainer.appendChild(minPriceOutput); dropListContainer.appendChild(maxPriceOutput); } } function processEnhancementData(obj) { const now_enhancementLevel = parseInt(obj.endCharacterAction.primaryItemHash.match(/::(\d+)$/)[1]); const currentCount = obj.endCharacterAction.currentCount; // 开始新的物品的强化 if (enhancementData[currentEnhancingIndex]["强化次数"] && currentCount <= enhancementData[currentEnhancingIndex]["强化次数"]) { currentEnhancingIndex++; enhancementData[currentEnhancingIndex] = { "强化数据": {}, "其他数据": {} }; enhancementLevel = undefined; } //初始化数据 if (!enhancementData[currentEnhancingIndex]["其他数据"]["物品名称"]) { const itemName = item_hrid_to_name[obj.endCharacterAction.primaryItemHash.match(/::([^:]+)::[^:]*$/)[1]]; enhancementData[currentEnhancingIndex]["其他数据"] = { "物品名称": itemName, "目标强化等级": obj.endCharacterAction.enhancingMaxLevel, "保护消耗总数": 0, } const filteredItems = obj.endCharacterItems.filter( item => item.hash !== obj.endCharacterAction.primaryItemHash ); const candidateItems = filteredItems.filter( item => item.itemHrid === obj.endCharacterAction.primaryItemHash.split('::')[2] ); let prevLevelItem; if (candidateItems.length === 1) { prevLevelItem = candidateItems[0]; } else if (candidateItems.length > 1) { prevLevelItem = candidateItems.find( item => item.hash !== obj.endCharacterAction.secondaryItemHash ); } enhancementLevel = prevLevelItem?.enhancementLevel ?? 0; } //统计强化次数 const currentItem = enhancementData[currentEnhancingIndex]["强化数据"]; if (!currentItem[enhancementLevel]) { currentItem[enhancementLevel] = {"祝福次数": 0, "成功次数": 0, "失败次数": 0, "成功率": 0 }; } if (enhancementLevel < now_enhancementLevel) { currentItem[enhancementLevel]["成功次数"]++; if (now_enhancementLevel - enhancementLevel == 2) { currentItem[enhancementLevel]["祝福次数"]++; } } else { currentItem[enhancementLevel]["失败次数"]++; if (obj.endCharacterAction.enhancingProtectionMinLevel >= 2 && enhancementLevel >= obj.endCharacterAction.enhancingProtectionMinLevel) { enhancementData[currentEnhancingIndex]["其他数据"]["保护消耗总数"]++; } } const success = currentItem[enhancementLevel]["成功次数"]; const failure = currentItem[enhancementLevel]["失败次数"]; currentItem[enhancementLevel]["成功率"] = success / (success + failure); // 计算强化状态 const highestSuccessLevel = Math.max(...Object.keys(currentItem).filter(level => currentItem[level]["成功次数"] > 0)); const enhancementState = (highestSuccessLevel + 1 >= enhancementData[currentEnhancingIndex]["其他数据"]["目标强化等级"]) ? "强化成功" : "强化失败"; enhancementData[currentEnhancingIndex]["强化状态"] = enhancementState; enhancementLevel = now_enhancementLevel; //console.log(enhancementData) enhancementData[currentEnhancingIndex]["强化次数"] = currentCount; updateEnhancementUI(); } function updateEnhancementUI() { const targetElement = document.querySelector(".SkillActionDetail_enhancingComponent__17bOx"); if (!targetElement) return; // 创建父容器 let parentContainer = document.querySelector("#enhancementParentContainer"); if (!parentContainer) { parentContainer = document.createElement("div"); parentContainer.id = "enhancementParentContainer"; parentContainer.style.display = "block"; // 设置为纵向布局(块级元素) parentContainer.style.borderLeft = "2px solid var(--color-divider)"; parentContainer.style.padding = "0 4px"; // 创建并添加标题 const title = document.createElement("div"); title.textContent = isCN ? "强化数据" : "Enhancement Data"; title.style.fontWeight = "bold"; title.style.marginBottom = "10px"; // 标题与下拉框之间的间距 title.style.textAlign = "center"; title.style.color = "var(--color-space-300)"; parentContainer.appendChild(title); // 创建并添加下拉框 const dropdownContainer = document.createElement("div"); dropdownContainer.style.marginBottom = "10px"; // 下拉框与表格之间的间距 const dropdown = document.createElement("select"); dropdown.id = "enhancementDropdown"; dropdown.addEventListener("change", function () { renderEnhancementUI(this.value); updateDropdownColor(); }); dropdownContainer.appendChild(dropdown); parentContainer.appendChild(dropdownContainer); // 创建并添加表格容器 const enhancementStatsContainer = document.createElement("div"); enhancementStatsContainer.id = "enhancementStatsContainer"; enhancementStatsContainer.style.display = "grid"; enhancementStatsContainer.style.gridTemplateColumns = "repeat(4, 1fr)"; enhancementStatsContainer.style.gap = "10px"; enhancementStatsContainer.style.textAlign = "center"; enhancementStatsContainer.style.marginTop = "10px"; parentContainer.appendChild(enhancementStatsContainer); targetElement.appendChild(parentContainer); } // 更新下拉框内容 const dropdown = document.querySelector("#enhancementDropdown"); const previousSelectedValue = dropdown.value; dropdown.innerHTML = ""; // 清空下拉框内容 Object.keys(enhancementData).forEach(key => { const item = enhancementData[key]; const option = document.createElement("option"); const itemName = item["其他数据"]["物品名称"]; const transferName = isCN && e2c[itemName] ? e2c[itemName] : itemName const targetLevel = item["其他数据"]["目标强化等级"]; const currentLevel = Math.max(...Object.keys(item["强化数据"])); const enhancementState = item["强化状态"]; option.text = isCN ? `${transferName} (目标: ${targetLevel}, 总计: ${item["强化次数"]}${item["其他数据"]["保护消耗总数"] > 0 ? `, 垫子: ${item["其他数据"]["保护消耗总数"]}` : ""})` : `${transferName} (Target: ${targetLevel}, Total: ${item["强化次数"]}${item["其他数据"]["保护消耗总数"] > 0 ? `, PU: ${item["其他数据"]["保护消耗总数"]}` : ""})`; option.value = key; option.style.color = enhancementState === "强化成功" ? "green" : (currentLevel < targetLevel && Object.keys(enhancementData).indexOf(key) === Object.keys(enhancementData).length - 1) ? "orange" : "red"; dropdown.appendChild(option); }); // 设置默认选中项并渲染表格数据 if (Object.keys(enhancementData).length > 0) { dropdown.value = previousSelectedValue || Object.keys(enhancementData)[0]; updateDropdownColor(); renderEnhancementUI(dropdown.value); } function updateDropdownColor() { const selectedOption = dropdown.options[dropdown.selectedIndex]; dropdown.style.color = selectedOption ? selectedOption.style.color : "black"; } } function renderEnhancementUI(selectedKey) { const enhancementStatsContainer = document.querySelector("#enhancementStatsContainer"); enhancementStatsContainer.innerHTML = ""; // 清空现有内容 const item = enhancementData[selectedKey]; // 表头 const headers = ["等级", "成功", "失败", "概率"]; headers.forEach(headerText => { const headerDiv = document.createElement("div"); headerDiv.style.fontWeight = "bold"; headerDiv.textContent = isCN ? headerText : (headerText === "等级" ? "Level" : headerText === "成功" ? "Success" : headerText === "失败" ? "Failure" : "Rate"); enhancementStatsContainer.appendChild(headerDiv); }); // 总计信息 const totalSuccess = Object.values(item["强化数据"]).reduce((acc, val) => acc + val["成功次数"], 0); const totalFailure = Object.values(item["强化数据"]).reduce((acc, val) => acc + val["失败次数"], 0); const totalCount = totalSuccess + totalFailure; const totalRate = totalCount > 0 ? (totalSuccess / totalCount * 100).toFixed(2) : "0.00"; // 将总计信息添加到表格中 ["总计", totalSuccess, totalFailure, `${totalRate}%`].forEach((totalText, index) => { const totalDiv = document.createElement("div"); totalDiv.textContent = isCN ? totalText : index === 0 ? "Total" : totalText; enhancementStatsContainer.appendChild(totalDiv); }); // 渲染各个强化等级的数据 Object.keys(item["强化数据"]).sort((a, b) => b - a).forEach(level => { const levelData = item["强化数据"][level]; const levelDivs = [ level, levelData["祝福次数"] > 0 ? `${levelData["成功次数"]}(${levelData["祝福次数"]})` : `${levelData["成功次数"]}`, levelData["失败次数"], `${(levelData["成功率"] * 100).toFixed(2)}%` ]; levelDivs.forEach(data => { const dataDiv = document.createElement("div"); dataDiv.textContent = data; enhancementStatsContainer.appendChild(dataDiv); }); }); } function processCombatConsumables(obj) { battlePlayerFood = {}; battlePlayerLoot = {}; battlePlayerData = {}; battleDuration = (new Date() - new Date(obj.combatStartTime)) / 1000; battleRunCount = obj.battleId || 1; obj.players.forEach(player => { const playerName = player.character.name; // 初始化玩家数据 battlePlayerFood[playerName] = { drinkConcentration: player.combatDetails.combatStats.drinkConcentration }; battlePlayerLoot[playerName] = {}; battlePlayerData[playerName] = { aura: null, skillexp: {} ,combatDropQuantity: player.combatDetails.combatStats.combatDropQuantity ,combatDropRate: player.combatDetails.combatStats.combatDropRate, combatRareFind: player.combatDetails.combatStats.combatRareFind}; // 处理消耗品 player.combatConsumables.forEach(consumable => { const itemname = item_hrid_to_name[consumable.itemHrid]; battlePlayerFood[playerName][itemname] = { "数量": consumable.count, "颜色": "white", "ID": consumable.itemHrid }; }); // 处理战利品 Object.values(player.totalLootMap).forEach(Loot => { const itemname = item_hrid_to_name[Loot.itemHrid]; battlePlayerLoot[playerName][itemname] = { "数量": Loot.count, "ID": Loot.itemHrid }; }); // 处理光环 player.combatAbilities.forEach(ability => { const isAura = Array.from(auraAbilities).some(aura => ability.abilityHrid.endsWith(aura)); if (isAura) { battlePlayerData[playerName].aura = ability.abilityHrid; } }); Object.keys(player.totalSkillExperienceMap).forEach(skillPath => { const skillname = skillPath.replace('/skills/', ''); battlePlayerData[playerName].skillexp[skillname] = player.totalSkillExperienceMap[skillPath]; }); }); } 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')) return; // 创建按钮 var battlePlayerFoodButton = document.createElement('div'); battlePlayerFoodButton.className = referenceTab.className + ' Button_battlePlayerFood__custom'; battlePlayerFoodButton.setAttribute('script_translatedfrom', 'New Action'); battlePlayerFoodButton.textContent = isCN ? "出警" : "Dispatch"; battlePlayerFoodButton.addEventListener('click', function() { // 计算最大数量字符长度 let maxQuantityLength = 0; Object.values(battlePlayerFood).forEach(playerData => { Object.entries(playerData).forEach(([itemName, itemData]) => { if (itemName === 'drinkConcentration') return; const length = formatPrice(itemData.数量).length; if (length > maxQuantityLength) maxQuantityLength = length; }); }); // 计算所有玩家的最短剩余时间 let minTimeOverall = Infinity; let minTimePlayer = null; Object.keys(battlePlayerFood).forEach(playerName => { const playerData = battlePlayerFood[playerName]; const drinkConcentration = playerData.drinkConcentration || 0; let minTime = Infinity; Object.entries(playerData).forEach(([itemName, itemData]) => { if (itemName === 'drinkConcentration') return; let unitTime = itemName.includes('Coffee') ? 300 / (1 + drinkConcentration) : 60; const totalDays = (itemData.数量 * unitTime) / 86400; if (totalDays < minTime) minTime = totalDays; }); if (minTime < minTimeOverall) { minTimeOverall = minTime; minTimePlayer = playerName; } }); // 弹窗 let dataHtml = `
`; Object.keys(battlePlayerFood).forEach(playerName => { const playerData = battlePlayerFood[playerName]; const isMinTimePlayer = Object.keys(battlePlayerFood).length > 1 && playerName === minTimePlayer; dataHtml += `

${playerName}

`; // 计算物品时间 const drinkConcentration = playerData.drinkConcentration || 0; let minTime = Infinity; const items = []; Object.entries(playerData).forEach(([itemName, itemData]) => { if (itemName === 'drinkConcentration') return; let unitTime = itemName.includes('Coffee') ? 300 / (1 + drinkConcentration) : 60; const totalDays = (itemData.数量 * unitTime) / 86400; items.push({ itemName, itemData, totalDays }); if (totalDays < minTime) minTime = totalDays; }); // 物品显示 items.forEach(({ itemName, itemData, totalDays }) => { const isMinItem = totalDays === minTime; const svgIcon = ` `; dataHtml += `
${formatPrice(itemData.数量)} ${svgIcon} ${isCN && e2c[itemName] ? e2c[itemName] : itemName}
`; }); // 时间显示 const timeDisplay = minTime < 1 ? `${(minTime * 24).toFixed(1)}小时` : `${minTime.toFixed(1)}天`; dataHtml += `

${isCN ? "剩余时间" : "Duration"}: ${timeDisplay}

`; // 光环显示 const playerAura = battlePlayerData[playerName]?.aura; if (playerAura) { const auraHrid = playerAura.split('/').pop(); const auraItemHrid = `/items/${auraHrid}`; const auraName = item_hrid_to_name[auraItemHrid] || auraHrid; const transferAuraName = isCN && e2c[auraName] ? e2c[auraName] : auraName; dataHtml += `

${isCN ? "光环" : "Aura"}: ${transferAuraName}

`; } dataHtml += `
`; }); dataHtml += '
'; // 弹窗容器 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.borderRadius = '10px'; popup.style.zIndex = '10000'; popup.style.maxWidth = '90%'; // 水平容器 let scrollWrapper = document.createElement('div'); scrollWrapper.style.overflowX = 'auto'; scrollWrapper.style.padding = '20px'; scrollWrapper.innerHTML = dataHtml; // 关闭按钮 let closeButton = document.createElement('button'); closeButton.textContent = '关闭'; closeButton.style.display = 'block'; closeButton.style.width = 'calc(100% - 40px)'; closeButton.style.margin = '0 20px 15px'; closeButton.style.backgroundColor = '#4357af'; closeButton.style.color = 'white'; closeButton.style.border = 'none'; closeButton.style.padding = '10px'; closeButton.style.borderRadius = '5px'; closeButton.style.cursor = 'pointer'; closeButton.onclick = () => document.body.removeChild(popup); popup.appendChild(scrollWrapper); 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; border-radius: 5px; padding: 5px 10px; cursor: pointer; transition: background-color 0.3s; } .Button_battlePlayerFood__custom:hover { background-color: #6b84ff; }`; 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 = isCN ? "分赃" : "Loot Distribution"; // 按钮点击事件 battlePlayerLootButton.addEventListener('click', function() { const isMobile = window.innerWidth < 768; // 判断是否为移动设备 const playerCount = Object.keys(battlePlayerLoot).length; let maxItemsToShow = 10; // 默认显示10个物品 const EPH = (60 * 60 * (battleRunCount - 1) / battleDuration) const skillTranslation = { attack: isCN ? '攻击' : 'Attack', defense: isCN ? '防御' : 'Defense', intelligence: isCN ? '智力' : 'Intelligence', power: isCN ? '力量' : 'Power', stamina: isCN ? '耐力' : 'Stamina', magic: isCN ? '魔法' : 'Magic', ranged: isCN ? '远程' : 'Ranged', }; if (isMobile) { if (playerCount === 3) { maxItemsToShow = 3; } else if (playerCount === 2) { maxItemsToShow = 5; } else if (playerCount === 1) { maxItemsToShow = 10; } else if (playerCount > 3) { maxItemsToShow = 1; } } const edibleTools = JSON.parse(localStorage.getItem('Edible_Tools')) || {}; const combatData = edibleTools.Combat_Data || {}; const currentMapData = combatData.Combat_Map_Data?.[now_battle_map]; const combatDropData = combatData.Combat_Mob_Drop_Data || {}; const Mob_Kill_List = {}; if (currentMapData && combatDropData) { const bossWave = currentMapData.BOSS波次; if (bossWave === 0) { Object.entries(currentMapData.小怪生成).forEach(([monsterHrid, data]) => { Mob_Kill_List[monsterHrid] = { 击杀数量: data.期望数量 * (battleRunCount - 1), 精英等级: data.精英等级 }; }); } else { const fullCycles = Math.floor((battleRunCount - 1) / bossWave); const remainingWaves = (battleRunCount - 1) % bossWave; const normalWaves = fullCycles * (bossWave - 1) + remainingWaves; Object.entries(currentMapData.小怪生成).forEach(([monsterHrid, data]) => { Mob_Kill_List[monsterHrid] = { 击杀数量: data.期望数量 * normalWaves, 精英等级: data.精英等级 }; }); if (currentMapData.BOSS数据 && typeof currentMapData.BOSS数据 === 'object') { Object.entries(currentMapData.BOSS数据).forEach(([bossHrid, bossData]) => { const existing = Mob_Kill_List[bossHrid] || { 击杀数量: 0 }; Mob_Kill_List[bossHrid] = { 击杀数量: existing.击杀数量 + fullCycles, 精英等级: bossData.精英等级 }; }); } } console.log(Mob_Kill_List) } let dataHtml = '
'; 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) { const PlayerBonusData = battlePlayerData[player]; const playerExpectDrops = {}; const commonDropRateMultiplier = 1 + (PlayerBonusData.combatDropRate || 0); const rareDropRateMultiplier = 1 + (PlayerBonusData.combatRareFind || 0); const dropQuantityMultiplier = 1 + (PlayerBonusData.combatDropQuantity || 0); for (const [monsterHrid, killInfo] of Object.entries(Mob_Kill_List)) { const monsterDrops = combatDropData[monsterHrid]; if (!monsterDrops) continue; const processDrops = (drops, isRare) => { for (const drop of drops) { if (killInfo.精英等级 < drop.精英门槛) continue; const rateMultiplier = isRare ? rareDropRateMultiplier : commonDropRateMultiplier; const actualRate = Math.min(drop.掉落几率 * rateMultiplier, 1); const actualQuantity = drop.掉落数量 * dropQuantityMultiplier / playerCount; const expected = killInfo.击杀数量 * actualRate * actualQuantity; if (expected > 0) { const key = drop.掉落物名称; playerExpectDrops[key] = (playerExpectDrops[key] || 0) + expected; } } } if (monsterDrops.普通掉落) processDrops(monsterDrops.普通掉落, false); if (monsterDrops.稀有掉落) processDrops(monsterDrops.稀有掉落, true); } let totalExpectPrice = 0; for (const [itemName, expectedQuantity] of Object.entries(playerExpectDrops)) { const unitPrice = getSpecialItemPrice(itemName, 'bid'); if (unitPrice !== null) { totalExpectPrice += unitPrice * expectedQuantity; } } const formattedExpectDrops = {}; for (const [itemHrid, value] of Object.entries(playerExpectDrops)) { formattedExpectDrops[itemHrid] = Number(value.toFixed(2)); } console.log(formattedExpectDrops) let totalPrice = 0; dataHtml += `
`; dataHtml += `

${player}

`; // 计算总价格 let lootItems = battlePlayerLoot[player]; for (let item in lootItems) { let bidPrice = getSpecialItemPrice(item,"bid") || 0; totalPrice += bidPrice * lootItems[item].数量; } // 显示总计价格 if (totalPrice > 0 && playerCount <= 3) { let color = '#4CAF50'; if (player === minTotalPricePlayer) { color = '#FF0000'; } let maxSkill = null; let maxXp = 0; if (battlePlayerData[player]?.skillexp) { for (let skill in battlePlayerData[player].skillexp) { let xp = battlePlayerData[player].skillexp[skill]; if (xp > maxXp) { maxXp = xp; maxSkill = skill; } } } // 计算每天价格 const pricePerDay = formatPrice((60 * 60 * 24 * totalPrice) / battleDuration); const xpPerHours = formatPrice((60 * 60 * maxXp) / battleDuration); const translatedSkillName = skillTranslation[maxSkill] || maxSkill; const ExpectPricePerDay = formatPrice((60 * 60 * 24 * totalExpectPrice) / battleDuration); dataHtml += `
${isCN ? '总计价值' : 'Total Revenue'}: ${formatPrice(totalPrice)}
${isCN ? '每天收入' : 'Daily Revenue'}: ${pricePerDay}/d
${totalExpectPrice > 0 ? `
${(!isMobile) ? `${isCN ? '期望产值' : 'Expected Revenue'}: ${formatPrice(totalExpectPrice)}
` : ''} ${isCN ? '期望日入' : 'NoRNG Daily'}: ${ExpectPricePerDay}/d
` : ''}
${isCN ? `${translatedSkillName}经验` : `${translatedSkillName} EXP`}: ${xpPerHours}/h
`; } 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, maxItemsToShow); 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', isMobile ? '12' : '20'); svgIcon.setAttribute('height', isMobile ? '12' : '20'); svgIcon.style.marginRight = '3px'; 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 += `
${quantity} ${svgIcon.outerHTML} ${isCN && e2c[item] ? e2c[item] : item}
`; } dataHtml += '
'; } dataHtml += '
'; // 创建弹窗 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 = isMobile ? '10px 10px 10px' : '20px 20px 20px'; popup.style.borderRadius = '10px'; popup.style.zIndex = '10000'; popup.style.maxWidth = '90%'; popup.style.maxHeight = '90%'; popup.style.overflowX = 'auto'; popup.style.overflowY = 'auto'; popup.style.whiteSpace = 'nowrap'; popup.innerHTML = dataHtml; const newElement = document.createElement('div'); newElement.textContent = `${EPH.toFixed(1)} EPH`; newElement.style.position = 'absolute'; newElement.style.top = '0'; newElement.style.left = '50%'; newElement.style.transform = 'translateX(-50%)'; newElement.style.height = isMobile ? '10px' : '20px'; newElement.style.minWidth = isMobile ? '80px' : '160px'; newElement.style.display = 'flex'; newElement.style.alignItems = 'center'; newElement.style.justifyContent = 'center'; newElement.style.backgroundColor = '#4357af'; newElement.style.borderRadius = '0 0 5px 5px'; newElement.style.fontSize = isMobile ? '8px' : '16px'; newElement.style.color = 'white'; newElement.style.fontWeight = 'bold'; newElement.style.lineHeight = '1'; newElement.style.zIndex = '1'; // 添加关闭按钮 let closeButton = document.createElement('button'); closeButton.textContent = '关闭'; closeButton.style.position = 'sticky'; closeButton.style.bottom = '0'; 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 = isMobile ? '5px 10px' : '10px 20px'; closeButton.style.borderRadius = '5px'; closeButton.style.cursor = 'pointer'; closeButton.style.fontSize = isMobile ? '12px' : '14px'; closeButton.onclick = function() { document.body.removeChild(popup); }; popup.appendChild(newElement); 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.minWidth = '300px'; windowDiv.style.maxWidth = 'min(400px, 90vw)'; windowDiv.style.maxHeight = '80vh'; windowDiv.style.backgroundColor = '#131419'; windowDiv.style.border = '1px solid #98a7e9'; windowDiv.style.borderRadius = '10px'; windowDiv.style.zIndex = '10000'; windowDiv.style.padding = '20px'; windowDiv.style.boxSizing = 'border-box'; windowDiv.style.display = 'flex'; windowDiv.style.flexDirection = 'column'; windowDiv.style.gap = '15px'; windowDiv.style.color = '#ffffff'; windowDiv.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.25)'; windowDiv.style.overflow = 'hidden'; return windowDiv; } function createVisualizationWindow(chestData) { let oldWindow = document.querySelector('.visualization-window'); if (oldWindow) oldWindow.remove(); let windowDiv = createWindowBase(); windowDiv.style.minHeight = '300px'; windowDiv.style.maxWidth = '400px'; // 标题 let title = document.createElement('h1'); title.innerText = isCN ? '选择角色' : 'Select Character'; title.style.color = '#98a7e9'; title.style.margin = '0'; title.style.fontSize = '1.5em'; title.style.textAlign = 'center'; windowDiv.appendChild(title); // 内容区域 let contentDiv = document.createElement('div'); contentDiv.style.flex = '1'; contentDiv.style.overflowY = 'auto'; contentDiv.style.paddingRight = '8px'; contentDiv.style.display = 'flex'; contentDiv.style.flexDirection = 'column'; contentDiv.style.gap = '10px'; // 玩家列表 for (let playerID in chestData) { const playerData = chestData[playerID]; const playerName = playerData.玩家昵称; let playerBox = document.createElement('div'); playerBox.style.display = 'flex'; playerBox.style.alignItems = 'center'; playerBox.style.border = '1px solid #98a7e9'; playerBox.style.borderRadius = '8px'; playerBox.style.padding = '12px'; playerBox.style.cursor = 'pointer'; playerBox.style.backgroundColor = '#1e1e2f'; playerBox.style.transition = 'all 0.3s ease'; // 悬停效果 playerBox.onmouseenter = () => { playerBox.style.backgroundColor = '#2c2e45'; playerBox.style.transform = 'translateX(5px)'; }; playerBox.onmouseleave = () => { playerBox.style.backgroundColor = '#1e1e2f'; playerBox.style.transform = 'none'; }; playerBox.onclick = () => showChestList(playerID, playerName, playerData.开箱数据); // 玩家名称 let playerText = document.createElement('span'); playerText.style.flex = '1'; playerText.style.fontSize = '1.1em'; playerText.style.color = '#ffffff'; playerText.textContent = playerName; // 删除按钮 let deleteButton = document.createElement('button'); deleteButton.textContent = '×'; deleteButton.style.backgroundColor = 'red'; deleteButton.style.color = 'white'; deleteButton.style.border = 'none'; deleteButton.style.borderRadius = '50%'; deleteButton.style.width = '24px'; deleteButton.style.height = '24px'; deleteButton.style.cursor = 'pointer'; deleteButton.onclick = (e) => { e.stopPropagation(); // 防止触发父元素的点击事件 if (confirm(`是否删除 ${playerName} 的全部开箱数据?`)) { deletePlayerChestData(playerID); createVisualizationWindow(JSON.parse(localStorage.getItem('Edible_Tools')).Chest_Open_Data); } }; playerBox.appendChild(playerText); playerBox.appendChild(deleteButton); contentDiv.appendChild(playerBox); } windowDiv.appendChild(contentDiv); // 关闭按钮 let closeButton = document.createElement('button'); closeButton.textContent = isCN ? '关闭' : 'Close'; closeButton.style.marginTop = '10px'; closeButton.style.padding = '10px'; closeButton.style.backgroundColor = '#4357af'; closeButton.style.color = 'white'; closeButton.style.border = 'none'; closeButton.style.borderRadius = '5px'; closeButton.style.cursor = 'pointer'; closeButton.onclick = () => document.body.removeChild(windowDiv); windowDiv.appendChild(closeButton); document.body.appendChild(windowDiv); } function deletePlayerChestData(playerID) { let edibleToolsData = JSON.parse(localStorage.getItem('Edible_Tools')); if (edibleToolsData && edibleToolsData.Chest_Open_Data) { delete edibleToolsData.Chest_Open_Data[playerID]; localStorage.setItem('Edible_Tools', JSON.stringify(edibleToolsData)); } } function showChestList(playerID, playerName, chestData) { let oldWindow = document.querySelector('.visualization-window'); if (oldWindow) oldWindow.remove(); let windowDiv = createWindowBase(); windowDiv.style.minHeight = '300px'; windowDiv.style.maxWidth = '400px'; // 标题 let title = document.createElement('h1'); title.innerText = isCN ? '开箱记录' : 'Chest Records'; title.style.color = '#98a7e9'; title.style.margin = '0'; title.style.fontSize = '1.5em'; title.style.textAlign = 'center'; windowDiv.appendChild(title); // 内容区域 let contentDiv = document.createElement('div'); contentDiv.style.flex = '1'; contentDiv.style.overflowY = 'auto'; contentDiv.style.paddingRight = '8px'; contentDiv.style.display = 'flex'; contentDiv.style.flexDirection = 'column'; contentDiv.style.gap = '10px'; // 箱子列表 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 #98a7e9'; chestBox.style.borderRadius = '8px'; chestBox.style.padding = '12px'; chestBox.style.cursor = 'pointer'; chestBox.style.backgroundColor = '#1e1e2f'; chestBox.style.transition = 'all 0.3s ease'; // 悬停效果 chestBox.onmouseenter = () => { chestBox.style.backgroundColor = '#2c2e45'; chestBox.style.transform = 'translateX(5px)'; }; chestBox.onmouseleave = () => { chestBox.style.backgroundColor = '#1e1e2f'; chestBox.style.transform = 'none'; }; chestBox.onclick = () => showChestDetails(playerID, playerName, chestName, chest); // 图标 let svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svgIcon.setAttribute('width', '20'); svgIcon.setAttribute('height', '20'); svgIcon.style.marginRight = '12px'; svgIcon.style.flexShrink = '0'; 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) { useElement.setAttribute('href', `${item_icon_url}#coin`); } svgIcon.appendChild(useElement); // 文字 let chestText = document.createElement('span'); chestText.style.flex = '1'; chestText.style.fontSize = '0.95em'; chestText.innerHTML = `
${isCN && e2c[chestName] ? e2c[chestName] : 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.gap = '10px'; footerDiv.style.marginTop = '10px'; const buttonStyle = { flex: '1', backgroundColor: '#4357af', color: 'white', border: 'none', padding: '10px', borderRadius: '6px', cursor: 'pointer', transition: 'background-color 0.3s', fontSize: '0.95em' }; // 返回按钮 let backButton = document.createElement('button'); Object.assign(backButton.style, buttonStyle); backButton.innerText = isCN ? '返回' : 'Back'; backButton.onclick = () => { windowDiv.remove(); createVisualizationWindow(JSON.parse(localStorage.getItem('Edible_Tools')).Chest_Open_Data); }; // 关闭按钮 let closeButton = document.createElement('button'); Object.assign(closeButton.style, buttonStyle); closeButton.innerText = isCN ? '关闭' : 'Close'; closeButton.onclick = () => windowDiv.remove(); footerDiv.appendChild(backButton); footerDiv.appendChild(closeButton); windowDiv.appendChild(footerDiv); document.body.appendChild(windowDiv); } function showChestDetails(playerID, playerName, chestName, chestData) { let oldWindow = document.querySelector('.visualization-window'); if (oldWindow) oldWindow.remove(); let detailsWindow = createWindowBase(); detailsWindow.style.minWidth = '300px'; detailsWindow.style.maxWidth = '400px'; // 标题 let title = document.createElement('div'); title.style.display = 'flex'; title.style.alignItems = 'center'; title.style.justifyContent = 'center'; title.style.gap = '10px'; title.style.margin = '0 0 15px 0'; let titleSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); titleSvg.setAttribute('width', '28'); titleSvg.setAttribute('height', '28'); let iconId = item_name_to_hrid[chestName].split('/').pop(); titleSvg.innerHTML = ``; let titleText = document.createElement('span'); titleText.style.color = '#98a7e9'; titleText.style.fontSize = '1.4em'; titleText.textContent = isCN && e2c[chestName] ? e2c[chestName] : chestName; title.appendChild(titleSvg); title.appendChild(titleText); detailsWindow.appendChild(title); // 内容区域 let contentDiv = document.createElement('div'); contentDiv.style.flex = '1'; contentDiv.style.overflowY = 'auto'; contentDiv.style.display = 'flex'; contentDiv.style.flexDirection = 'column'; contentDiv.style.gap = '12px'; contentDiv.style.paddingRight = '8px'; // 统计卡片 let statsCard = document.createElement('div'); statsCard.style.backgroundColor = '#1e1e2f'; statsCard.style.borderRadius = '8px'; statsCard.style.padding = '15px'; statsCard.innerHTML = `
📋 ${isCN ? "统计概览" : "Statistics Overview"}
${isCN ? "开箱总数" : "Total Open"}
${chestData['总计开箱数量']}
${isCN ? "Ask 总值" : "Total Ask"}
${formatPrice(chestData['总计开箱Ask'])}
${isCN ? "Bid 总值" : "Total Bid"}
${formatPrice(chestData['总计开箱Bid'])}
${isCN ? (chestData['累计偏差值'] < 0 ? "低于期望" : "高于期望") : (chestData['累计偏差值'] < 0 ? "Below Expectation" : "Above Expectation")}
${formatPrice(Math.abs(chestData['累计偏差值'] || 0))}
`; contentDiv.appendChild(statsCard); // 物品列表 let itemListHeader = document.createElement('div'); itemListHeader.style.color = '#98a7e9'; itemListHeader.innerText = isCN ? '🎁 获得物品' : "🎁 Get Item"; contentDiv.appendChild(itemListHeader); const sortedItems = Object.entries(chestData['获得物品']).sort((a, b) => { const getValidValue = (val) => val === -1 ? 0 : val; const aAsk = getValidValue(a[1]['总计Ask价值']); const aBid = getValidValue(a[1]['总计Bid价值']); const bAsk = getValidValue(b[1]['总计Ask价值']); const bBid = getValidValue(b[1]['总计Bid价值']); return (bAsk + bBid) - (aAsk + aBid); }); sortedItems.forEach(([itemName, item]) => { let itemBox = document.createElement('div'); itemBox.style.display = 'flex'; itemBox.style.alignItems = 'center'; itemBox.style.backgroundColor = '#1e1e2f'; itemBox.style.border = '1px solid #98a7e9'; itemBox.style.borderRadius = '8px'; itemBox.style.padding = '12px'; itemBox.style.gap = '10px'; // 图标 let svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svgIcon.setAttribute('width', '24'); svgIcon.setAttribute('height', '24'); 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) { useElement.setAttribute('href', `${item_icon_url}#coin`); } svgIcon.appendChild(useElement); // 文字 let itemText = document.createElement('div'); itemText.style.flex = '1'; itemText.innerHTML = `
${isCN && e2c[itemName] ? e2c[itemName] : itemName}
${isCN ? "数量" : "Count"}: ${formatPrice(item['数量'])}
`; itemBox.appendChild(svgIcon); itemBox.appendChild(itemText); contentDiv.appendChild(itemBox); }); detailsWindow.appendChild(contentDiv); // 底部按钮 let footerDiv = document.createElement('div'); footerDiv.style.display = 'flex'; footerDiv.style.gap = '10px'; footerDiv.style.marginTop = '10px'; const buttonStyle = { flex: '1', backgroundColor: '#4357af', color: 'white', border: 'none', padding: '10px', borderRadius: '6px', cursor: 'pointer', transition: 'background-color 0.3s' }; // 返回按钮 let backButton = document.createElement('button'); Object.assign(backButton.style, buttonStyle); backButton.innerText = isCN ? '返回' : 'Back'; backButton.onclick = () => { detailsWindow.remove(); showChestList(playerID, playerName, JSON.parse(localStorage.getItem('Edible_Tools')).Chest_Open_Data[playerID].开箱数据); }; // 关闭按钮 let closeButton = document.createElement('button'); Object.assign(closeButton.style, buttonStyle); closeButton.innerText = isCN ? '关闭' : 'Close'; closeButton.onclick = () => detailsWindow.remove(); footerDiv.appendChild(backButton); 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 = '
'; const minPrice = 10000; for (let player in battlePlayerLoot) { let totalPrice = 0; dataHtml += `
`; dataHtml += `

${player}

`; let lootItems = battlePlayerLoot[player]; for (let item in lootItems) { let bidPrice = getSpecialItemPrice(item,"bid") || 0; totalPrice += bidPrice*lootItems[item].数量 if (bidPrice > minPrice) { dataHtml += `

${item}: ${lootItems[item].数量}

`; } } if (totalPrice > 0) { dataHtml += `

总计价格: ${formatPrice(totalPrice)}

`; } dataHtml += '
'; } dataHtml += '
'; 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.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 = `

银河奶牛数据库

市场数据

订单ID 角色ID 状态 类型 物品 数量 已交易数量 单价 贸易额 更新时间 操作
`; 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 translatedName = isCN && e2c[row.itemName] ? e2c[row.itemName] : row.itemName; if (row.enhancementLevel > 0) { translatedName = `${translatedName} +${row.enhancementLevel}`; } let itemNameWithIcon = `${svgIcon.outerHTML}${translatedName}`; return ` ${row.id} ${row.characterID} ${tran_market_list[row.status] || row.status} ${row.isSell ? '出售' : '收购'} ${itemNameWithIcon} ${(row.orderQuantity).toLocaleString()} ${(row.filledQuantity).toLocaleString()} ${(row.price).toLocaleString()} ${(row.price * row.filledQuantity).toLocaleString()} ${row.format_lastUpdated} `; }).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); }); // 删除过时市场数据 document.getElementById('deleteOldDataBtn').addEventListener('click', () => { 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("删除成功,已清理日期之前的数据。"); document.body.removeChild(settingsContainer); }); document.getElementById('deleteSpecificStatusDataBtn').addEventListener('click', () => { let market_list = JSON.parse(GM_getValue('market_list', '[]')); const statusToDelete = ["/market_listing_status/active","进行中","/market_listing_status/cancelled","取消","/market_listing_status/expired","超时"]; const deleteCount = market_list.filter(order => statusToDelete.includes(order.status)).length; if (deleteCount === 0) { alert("没有需要删除的数据。"); return; } const isConfirmed = confirm(`即将删除 ${deleteCount} 条数据,是否继续?`); if (!isConfirmed) { return; } const filteredMarketList = market_list.filter(order => !statusToDelete.includes(order.status)); GM_setValue('market_list', JSON.stringify(filteredMarketList)); alert("删除成功"); 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); } })();