koishi-plugin-warframe 1.7.11 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -1285,6 +1285,7 @@ var messages = {
1285
1285
  "relic.dataLoading": "遗物数据未加载完成,请稍后再试",
1286
1286
  "relic.notFound": "未找到对应遗物信息",
1287
1287
  "arbitration.invalidDayRange": "天数需小于等于14且大于0",
1288
+ "bounty.unavailable": "当前该地点暂无可用赏金",
1288
1289
  "voidTrader.drifting": "虚空商人仍在未知地带漂流...",
1289
1290
  "voidTrader.arriving": "距离虚空商人到达还有: {time}",
1290
1291
  "riven.imageNotFound": "未检测到图片",
@@ -1607,7 +1608,7 @@ async function getHotRivenWeapons2() {
1607
1608
  __name(getHotRivenWeapons2, "getHotRivenWeapons");
1608
1609
 
1609
1610
  // src/warframe/services/wf-service.ts
1610
- var import_warframe_public_export_plus6 = require("warframe-public-export-plus");
1611
+ var import_warframe_public_export_plus7 = require("warframe-public-export-plus");
1611
1612
 
1612
1613
  // src/warframe/assets/index.ts
1613
1614
  var {
@@ -1632,14 +1633,29 @@ var arbitrationSchedule = arbitrationScheduleText.split("\n").map((line) => line
1632
1633
  };
1633
1634
  });
1634
1635
 
1635
- // src/warframe/data/wf/globalWorldState.ts
1636
- var import_warframe_public_export_plus3 = require("warframe-public-export-plus");
1637
-
1638
1636
  // src/warframe/infrastructure/wf/wf-api.ts
1639
1637
  var apiBase = "https://api.warframe.com/cdn/";
1638
+ var oracleBountyCycleUrl = "https://oracle.browse.wf/bounty-cycle";
1639
+ function extractSyndicateMissionsRaw(json) {
1640
+ try {
1641
+ const data = JSON.parse(json);
1642
+ return Array.isArray(data.SyndicateMissions) ? data.SyndicateMissions : [];
1643
+ } catch {
1644
+ return [];
1645
+ }
1646
+ }
1647
+ __name(extractSyndicateMissionsRaw, "extractSyndicateMissionsRaw");
1648
+ async function fetchWorldStateJson() {
1649
+ return fetchAsyncText(`${apiBase}worldState.php`);
1650
+ }
1651
+ __name(fetchWorldStateJson, "fetchWorldStateJson");
1652
+ async function fetchOracleBountyCycle() {
1653
+ return fetchAsyncData(oracleBountyCycleUrl);
1654
+ }
1655
+ __name(fetchOracleBountyCycle, "fetchOracleBountyCycle");
1640
1656
  async function getWorldState(json) {
1641
1657
  if (!json) {
1642
- json = await fetchAsyncText(`${apiBase}worldState.php`);
1658
+ json = await fetchWorldStateJson();
1643
1659
  }
1644
1660
  if (!json) {
1645
1661
  throw new Error("获取游戏信息失败");
@@ -1807,6 +1823,19 @@ async function getVoidTraderHistory(data) {
1807
1823
  }
1808
1824
  __name(getVoidTraderHistory, "getVoidTraderHistory");
1809
1825
 
1826
+ // src/warframe/data/wf/globalOracleBountyCycle.ts
1827
+ async function globalOracleBountyCycleFactory() {
1828
+ return fetchOracleBountyCycle();
1829
+ }
1830
+ __name(globalOracleBountyCycleFactory, "globalOracleBountyCycleFactory");
1831
+ var globalOracleBountyCycle = createAsyncCache(
1832
+ globalOracleBountyCycleFactory,
1833
+ 6e4
1834
+ );
1835
+
1836
+ // src/warframe/data/wf/globalWorldState.ts
1837
+ var import_warframe_public_export_plus3 = require("warframe-public-export-plus");
1838
+
1810
1839
  // src/warframe/infrastructure/wf/wf-export-adapter.ts
1811
1840
  var import_warframe_public_export_plus = require("warframe-public-export-plus");
1812
1841
  function regionToShort(region, dict) {
@@ -1954,7 +1983,12 @@ async function adaptFissure(fissure) {
1954
1983
  }
1955
1984
  __name(adaptFissure, "adaptFissure");
1956
1985
  var globalWorldState = createAsyncCache(async () => {
1957
- const worldState = await getWorldState();
1986
+ const json = await fetchWorldStateJson();
1987
+ if (!json) {
1988
+ throw new Error("获取游戏信息失败");
1989
+ }
1990
+ const syndicateMissionsRaw = extractSyndicateMissionsRaw(json);
1991
+ const worldState = await getWorldState(json);
1958
1992
  const fissures = [];
1959
1993
  const rjFissures = [];
1960
1994
  const spFissures = [];
@@ -1971,7 +2005,13 @@ var globalWorldState = createAsyncCache(async () => {
1971
2005
  fissures.sort((a, b) => a.tierNum - b.tierNum);
1972
2006
  spFissures.sort((a, b) => a.tierNum - b.tierNum);
1973
2007
  rjFissures.sort((a, b) => a.tierNum - b.tierNum);
1974
- return { raw: worldState, fissures, spFissures, rjFissures };
2008
+ return {
2009
+ raw: worldState,
2010
+ syndicateMissionsRaw,
2011
+ fissures,
2012
+ spFissures,
2013
+ rjFissures
2014
+ };
1975
2015
  }, -1);
1976
2016
 
1977
2017
  // src/warframe/data/wf/relics.ts
@@ -2278,6 +2318,414 @@ async function extractTextFromImage(image, secret) {
2278
2318
  }
2279
2319
  __name(extractTextFromImage, "extractTextFromImage");
2280
2320
 
2321
+ // src/warframe/infrastructure/wf/bounty-adapter.ts
2322
+ var import_warframe_public_export_plus6 = require("warframe-public-export-plus");
2323
+ var bountyLocationTag = {
2324
+ cetus: "CetusSyndicate",
2325
+ fortuna: "SolarisSyndicate",
2326
+ deimos: "EntratiSyndicate",
2327
+ zariman: "ZarimanSyndicate",
2328
+ cavia: "EntratiLabSyndicate",
2329
+ hex: "HexSyndicate"
2330
+ };
2331
+ var oracleBountyLocations = /* @__PURE__ */ new Set([
2332
+ "zariman",
2333
+ "cavia",
2334
+ "hex"
2335
+ ]);
2336
+ var locationFallbackTitle = {
2337
+ cetus: "希图斯赏金",
2338
+ fortuna: "福尔图娜赏金",
2339
+ deimos: "火卫二赏金",
2340
+ zariman: "坚守者赏金",
2341
+ cavia: "科维兽赏金",
2342
+ hex: "六人组赏金"
2343
+ };
2344
+ var hexNodesWithoutMissionSuffix = /* @__PURE__ */ new Set([
2345
+ "SolNode850",
2346
+ "SolNode853",
2347
+ "SolNode854",
2348
+ "SolNode856"
2349
+ ]);
2350
+ var hexAllyNames = {
2351
+ "/Lotus/Types/Gameplay/1999Wf/ProtoframeAllies/AmirAllyAgent": "Amir",
2352
+ "/Lotus/Types/Gameplay/1999Wf/ProtoframeAllies/AoiAllyAgent": "Aoi",
2353
+ "/Lotus/Types/Gameplay/1999Wf/ProtoframeAllies/ArthurAllyAgent": "Arthur",
2354
+ "/Lotus/Types/Gameplay/1999Wf/ProtoframeAllies/EleanorAllyAgent": "Eleanor",
2355
+ "/Lotus/Types/Gameplay/1999Wf/ProtoframeAllies/LettieAllyAgent": "Lettie",
2356
+ "/Lotus/Types/Gameplay/1999Wf/ProtoframeAllies/QuincyAllyAgent": "Quincy"
2357
+ };
2358
+ var oracleTierTables = {
2359
+ zariman: [
2360
+ {
2361
+ levels: [50, 55],
2362
+ standing: [1, 2],
2363
+ rewards: "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierATableRewards"
2364
+ },
2365
+ {
2366
+ levels: [60, 65],
2367
+ standing: [2, 3],
2368
+ rewards: "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierBTableRewards"
2369
+ },
2370
+ {
2371
+ levels: [70, 75],
2372
+ standing: [3, 5],
2373
+ rewards: "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierCTableARewards"
2374
+ },
2375
+ {
2376
+ levels: [90, 95],
2377
+ standing: [4, 6],
2378
+ rewards: "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierDTableRewards"
2379
+ },
2380
+ {
2381
+ levels: [110, 115],
2382
+ standing: [5, 8],
2383
+ rewards: "/Lotus/Types/Game/MissionDecks/ZarimanJobMissionRewards/TierETableRewards"
2384
+ }
2385
+ ],
2386
+ cavia: [
2387
+ {
2388
+ levels: [55, 60],
2389
+ standing: [1e3, 1500],
2390
+ rewards: "/Lotus/Types/Game/MissionDecks/EntratiLabJobMissionReward/TierATableRewards"
2391
+ },
2392
+ {
2393
+ levels: [65, 70],
2394
+ standing: [2e3, 3e3],
2395
+ rewards: "/Lotus/Types/Game/MissionDecks/EntratiLabJobMissionReward/TierBTableRewards"
2396
+ },
2397
+ {
2398
+ levels: [75, 80],
2399
+ standing: [3e3, 4500],
2400
+ rewards: "/Lotus/Types/Game/MissionDecks/EntratiLabJobMissionReward/TierCTableRewards"
2401
+ },
2402
+ {
2403
+ levels: [95, 100],
2404
+ standing: [4e3, 6e3],
2405
+ rewards: "/Lotus/Types/Game/MissionDecks/EntratiLabJobMissionReward/TierDTableRewards"
2406
+ },
2407
+ {
2408
+ levels: [115, 120],
2409
+ standing: [5e3, 7500],
2410
+ rewards: "/Lotus/Types/Game/MissionDecks/EntratiLabJobMissionReward/TierETableRewards"
2411
+ }
2412
+ ],
2413
+ hex: [
2414
+ {
2415
+ levels: [65, 70],
2416
+ standing: [1e3, 1500],
2417
+ rewards: "/Lotus/Types/Game/MissionDecks/1999MissionRewards/TierABountyRewards"
2418
+ },
2419
+ {
2420
+ levels: [75, 80],
2421
+ standing: [2e3, 3e3],
2422
+ rewards: "/Lotus/Types/Game/MissionDecks/1999MissionRewards/TierBBountyRewards"
2423
+ },
2424
+ {
2425
+ levels: [85, 90],
2426
+ standing: [3e3, 4500],
2427
+ rewards: "/Lotus/Types/Game/MissionDecks/1999MissionRewards/TierCBountyRewards"
2428
+ },
2429
+ {
2430
+ levels: [95, 100],
2431
+ standing: [4e3, 6e3],
2432
+ rewards: "/Lotus/Types/Game/MissionDecks/1999MissionRewards/TierDBountyRewards"
2433
+ },
2434
+ {
2435
+ levels: [105, 110],
2436
+ standing: [5e3, 7500],
2437
+ rewards: "/Lotus/Types/Game/MissionDecks/1999MissionRewards/TierEBountyRewards"
2438
+ },
2439
+ {
2440
+ levels: [115, 120],
2441
+ standing: [6e3, 9e3],
2442
+ rewards: "/Lotus/Types/Game/MissionDecks/1999MissionRewards/TierFBountyRewards"
2443
+ },
2444
+ {
2445
+ levels: [125, 130],
2446
+ standing: [7500, 11250],
2447
+ rewards: "/Lotus/Types/Game/MissionDecks/1999MissionRewards/InfestedLichBountyRewards"
2448
+ }
2449
+ ]
2450
+ };
2451
+ function mongoDateMs(value) {
2452
+ const raw = value?.$date?.$numberLong;
2453
+ return raw ? Number(raw) : 0;
2454
+ }
2455
+ __name(mongoDateMs, "mongoDateMs");
2456
+ function rarityFromStageProbabilities(probability, uniqueSortedDesc) {
2457
+ if (uniqueSortedDesc.length <= 1) {
2458
+ return "bronze";
2459
+ }
2460
+ const idx = uniqueSortedDesc.indexOf(probability);
2461
+ if (idx <= 0) {
2462
+ return "bronze";
2463
+ }
2464
+ if (uniqueSortedDesc.length === 2) {
2465
+ return "silver";
2466
+ }
2467
+ if (idx === uniqueSortedDesc.length - 1) {
2468
+ return "gold";
2469
+ }
2470
+ return "silver";
2471
+ }
2472
+ __name(rarityFromStageProbabilities, "rarityFromStageProbabilities");
2473
+ var blueprintNameCache = /* @__PURE__ */ new Map();
2474
+ function resolveBlueprintNameViaDictZh(pathLeaf) {
2475
+ if (!/Blueprint$/i.test(pathLeaf)) {
2476
+ return void 0;
2477
+ }
2478
+ const base = pathLeaf.replace(/Blueprint$/i, "");
2479
+ if (!base) {
2480
+ return void 0;
2481
+ }
2482
+ if (blueprintNameCache.has(base)) {
2483
+ return blueprintNameCache.get(base) ?? void 0;
2484
+ }
2485
+ const needle = `${base}Name`.toLowerCase();
2486
+ let translated;
2487
+ for (const key of Object.keys(import_warframe_public_export_plus6.dict_zh)) {
2488
+ if (!key.toLowerCase().endsWith(needle)) {
2489
+ continue;
2490
+ }
2491
+ const boundary = key.length - needle.length;
2492
+ if (boundary === 0 || key[boundary - 1] === "/" || key[boundary - 1] === "_") {
2493
+ translated = import_warframe_public_export_plus6.dict_zh[key];
2494
+ break;
2495
+ }
2496
+ }
2497
+ if (!translated) {
2498
+ blueprintNameCache.set(base, null);
2499
+ return void 0;
2500
+ }
2501
+ const withBlueprint = translated.includes("蓝图") ? translated : `${translated} 蓝图`;
2502
+ blueprintNameCache.set(base, withBlueprint);
2503
+ return withBlueprint;
2504
+ }
2505
+ __name(resolveBlueprintNameViaDictZh, "resolveBlueprintNameViaDictZh");
2506
+ function resolveExportItemNameZh(sourceKey) {
2507
+ const creditMatch = sourceKey.match(/\/(\d+)Credits(?:$|\?)/);
2508
+ if (creditMatch) {
2509
+ return `${creditMatch[1]} 现金`;
2510
+ }
2511
+ const fixedKey = sourceKey.replace("/StoreItems", "");
2512
+ const flavour = import_warframe_public_export_plus6.ExportFlavour[fixedKey];
2513
+ if (flavour?.name) {
2514
+ return import_warframe_public_export_plus6.dict_zh[flavour.name] ?? flavour.name;
2515
+ }
2516
+ const weapon = import_warframe_public_export_plus6.ExportWeapons[fixedKey];
2517
+ if (weapon?.name) {
2518
+ return import_warframe_public_export_plus6.dict_zh[weapon.name] ?? weapon.name;
2519
+ }
2520
+ const mod = import_warframe_public_export_plus6.ExportUpgrades[fixedKey];
2521
+ if (mod?.name) {
2522
+ return import_warframe_public_export_plus6.dict_zh[mod.name] ?? mod.name;
2523
+ }
2524
+ const arcane = import_warframe_public_export_plus6.ExportArcanes[fixedKey];
2525
+ if (arcane?.name) {
2526
+ return import_warframe_public_export_plus6.dict_zh[arcane.name] ?? arcane.name;
2527
+ }
2528
+ const fusion = import_warframe_public_export_plus6.ExportFusionBundles[fixedKey];
2529
+ if (fusion?.name) {
2530
+ return import_warframe_public_export_plus6.dict_zh[fusion.name] ?? fusion.name;
2531
+ }
2532
+ const relic = import_warframe_public_export_plus6.ExportRelics[fixedKey];
2533
+ if (relic) {
2534
+ const era = import_warframe_public_export_plus6.dict_zh[relicEraToTransKey(relic.era)] ?? toPascalCase(relic.era);
2535
+ return `${era} ${relic.category} 遗物`;
2536
+ }
2537
+ const skin = import_warframe_public_export_plus6.ExportCustoms[fixedKey];
2538
+ if (skin?.name) {
2539
+ return import_warframe_public_export_plus6.dict_zh[skin.name] ?? skin.name;
2540
+ }
2541
+ const recipe = import_warframe_public_export_plus6.ExportRecipes[fixedKey];
2542
+ if (recipe?.resultType) {
2543
+ const recipeResult = import_warframe_public_export_plus6.ExportKeys[recipe.resultType] ?? import_warframe_public_export_plus6.ExportResources[recipe.resultType] ?? import_warframe_public_export_plus6.ExportWeapons[recipe.resultType] ?? import_warframe_public_export_plus6.ExportWarframes[recipe.resultType];
2544
+ if (recipeResult?.name) {
2545
+ const translated = import_warframe_public_export_plus6.dict_zh[recipeResult.name] ?? recipeResult.name;
2546
+ return translated.includes("蓝图") ? translated : `${translated} 蓝图`;
2547
+ }
2548
+ }
2549
+ const virtual = import_warframe_public_export_plus6.ExportVirtuals[fixedKey];
2550
+ if (virtual?.name) {
2551
+ return import_warframe_public_export_plus6.dict_zh[virtual.name] ?? virtual.name;
2552
+ }
2553
+ const resource = import_warframe_public_export_plus6.ExportResources[fixedKey];
2554
+ if (resource?.name) {
2555
+ return import_warframe_public_export_plus6.dict_zh[resource.name] ?? resource.name;
2556
+ }
2557
+ const gear = import_warframe_public_export_plus6.ExportGear[fixedKey];
2558
+ if (gear?.name) {
2559
+ return import_warframe_public_export_plus6.dict_zh[gear.name] ?? gear.name;
2560
+ }
2561
+ const bundle = import_warframe_public_export_plus6.ExportBundles[sourceKey] ?? import_warframe_public_export_plus6.ExportBundles[fixedKey];
2562
+ if (bundle?.name) {
2563
+ return import_warframe_public_export_plus6.dict_zh[bundle.name] ?? bundle.name;
2564
+ }
2565
+ const boosterPack = import_warframe_public_export_plus6.ExportBoosterPacks[fixedKey];
2566
+ if (boosterPack?.name) {
2567
+ return import_warframe_public_export_plus6.dict_zh[boosterPack.name] ?? boosterPack.name;
2568
+ }
2569
+ const pathLeaf = fixedKey.split("/").pop() ?? sourceKey;
2570
+ return resolveBlueprintNameViaDictZh(pathLeaf) ?? pathLeaf;
2571
+ }
2572
+ __name(resolveExportItemNameZh, "resolveExportItemNameZh");
2573
+ function rewardsFromDeck(rewardsKey) {
2574
+ const deck = import_warframe_public_export_plus6.ExportRewards[rewardsKey];
2575
+ if (!deck?.length) {
2576
+ return [];
2577
+ }
2578
+ return deck.map((tier) => {
2579
+ const uniqueSortedDesc = [...new Set(
2580
+ tier.map((reward) => reward.probability).filter((value) => typeof value === "number")
2581
+ )].sort((a, b) => b - a);
2582
+ const seen = /* @__PURE__ */ new Set();
2583
+ const rewards = [];
2584
+ for (const reward of tier) {
2585
+ const name2 = resolveExportItemNameZh(reward.type);
2586
+ const rarity = rarityFromStageProbabilities(
2587
+ reward.probability ?? uniqueSortedDesc[0] ?? 0,
2588
+ uniqueSortedDesc
2589
+ );
2590
+ const key = `${rarity}:${name2}`;
2591
+ if (seen.has(key)) {
2592
+ continue;
2593
+ }
2594
+ seen.add(key);
2595
+ rewards.push({ name: name2, rarity });
2596
+ }
2597
+ return rewards;
2598
+ });
2599
+ }
2600
+ __name(rewardsFromDeck, "rewardsFromDeck");
2601
+ function jobName(job) {
2602
+ if (job.isVault) {
2603
+ const chamber = (job.locationTag || "").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").trim();
2604
+ return chamber ? `隔离库 ${chamber}` : "隔离库";
2605
+ }
2606
+ if (job.jobType) {
2607
+ const bounty = import_warframe_public_export_plus6.ExportBounties[job.jobType];
2608
+ if (bounty?.name) {
2609
+ return import_warframe_public_export_plus6.dict_zh[bounty.name] ?? bounty.name;
2610
+ }
2611
+ return job.jobType.split("/").pop() ?? "未知赏金";
2612
+ }
2613
+ return "未知赏金";
2614
+ }
2615
+ __name(jobName, "jobName");
2616
+ function boardTitle(location, tag) {
2617
+ const syndicate = import_warframe_public_export_plus6.ExportSyndicates[tag];
2618
+ if (syndicate?.name) {
2619
+ const name2 = import_warframe_public_export_plus6.dict_zh[syndicate.name] ?? syndicate.name;
2620
+ return name2.endsWith("赏金") ? name2 : `${name2}赏金`;
2621
+ }
2622
+ return locationFallbackTitle[location];
2623
+ }
2624
+ __name(boardTitle, "boardTitle");
2625
+ function adaptJob(job) {
2626
+ return {
2627
+ name: jobName(job),
2628
+ enemyLevels: [job.minEnemyLevel, job.maxEnemyLevel],
2629
+ standingStages: job.xpAmounts ?? [],
2630
+ minMR: job.masteryReq ?? 0,
2631
+ ...job.isVault ? { isVault: true } : {},
2632
+ ...job.locationTag ? { locationTag: job.locationTag } : {},
2633
+ ...job.jobType?.includes("Narmer") ? { isNarmer: true } : {},
2634
+ stages: rewardsFromDeck(job.rewards)
2635
+ };
2636
+ }
2637
+ __name(adaptJob, "adaptJob");
2638
+ function adaptBountyBoard(location, mission) {
2639
+ if (!mission?.Jobs?.length) {
2640
+ return void 0;
2641
+ }
2642
+ return {
2643
+ location,
2644
+ title: boardTitle(location, mission.Tag),
2645
+ expiry: mongoDateMs(mission.Expiry),
2646
+ jobs: mission.Jobs.map(adaptJob)
2647
+ };
2648
+ }
2649
+ __name(adaptBountyBoard, "adaptBountyBoard");
2650
+ function findRawSyndicateMission(missions, location) {
2651
+ const tag = bountyLocationTag[location];
2652
+ return missions.find((mission) => mission.Tag === tag);
2653
+ }
2654
+ __name(findRawSyndicateMission, "findRawSyndicateMission");
2655
+ function formatOracleMission(nodeKey) {
2656
+ const region = import_warframe_public_export_plus6.ExportRegions[nodeKey];
2657
+ if (!region?.name) {
2658
+ return nodeKey;
2659
+ }
2660
+ const name2 = import_warframe_public_export_plus6.dict_zh[region.name] ?? region.name;
2661
+ if (hexNodesWithoutMissionSuffix.has(nodeKey) || !region.missionName) {
2662
+ return name2;
2663
+ }
2664
+ const mission = import_warframe_public_export_plus6.dict_zh[region.missionName] ?? region.missionName;
2665
+ if (!mission || mission === name2) {
2666
+ return name2;
2667
+ }
2668
+ return `${name2}(${mission})`;
2669
+ }
2670
+ __name(formatOracleMission, "formatOracleMission");
2671
+ function formatOracleChallenge(challengePath) {
2672
+ const challenge = import_warframe_public_export_plus6.ExportChallenges[challengePath];
2673
+ if (!challenge?.description) {
2674
+ return challengePath.split("/").pop() ?? challengePath;
2675
+ }
2676
+ const raw = import_warframe_public_export_plus6.dict_zh[challenge.description] ?? challenge.description;
2677
+ const lastLine = raw.split(/\r?\n/).pop() ?? raw;
2678
+ return lastLine.split("|COUNT|").join(String(challenge.requiredCount ?? 0));
2679
+ }
2680
+ __name(formatOracleChallenge, "formatOracleChallenge");
2681
+ function zarimanFactionZh(faction) {
2682
+ if (faction === "FC_GRINEER") {
2683
+ return import_warframe_public_export_plus6.dict_zh["/Lotus/Language/Game/Faction_GrineerUC"] ?? "Grineer";
2684
+ }
2685
+ if (faction === "FC_CORPUS") {
2686
+ return import_warframe_public_export_plus6.dict_zh["/Lotus/Language/Game/Faction_CorpusUC"] ?? "Corpus";
2687
+ }
2688
+ return void 0;
2689
+ }
2690
+ __name(zarimanFactionZh, "zarimanFactionZh");
2691
+ function adaptOracleJob(location, entry, index) {
2692
+ const tiers = oracleTierTables[location];
2693
+ const tier = tiers[Math.min(index, tiers.length - 1)];
2694
+ const ally = entry.ally ? hexAllyNames[entry.ally] : void 0;
2695
+ return {
2696
+ name: formatOracleMission(entry.node),
2697
+ enemyLevels: tier.levels,
2698
+ standingStages: tier.standing,
2699
+ minMR: 0,
2700
+ stages: rewardsFromDeck(tier.rewards),
2701
+ challenge: formatOracleChallenge(entry.challenge),
2702
+ ...ally ? { ally } : {},
2703
+ ...location === "zariman" ? { standingUnit: "vq" } : {}
2704
+ };
2705
+ }
2706
+ __name(adaptOracleJob, "adaptOracleJob");
2707
+ function adaptOracleBountyBoard(location, cycle) {
2708
+ if (!cycle) {
2709
+ return void 0;
2710
+ }
2711
+ const tag = bountyLocationTag[location];
2712
+ const entries = cycle.bounties?.[tag];
2713
+ if (!entries?.length) {
2714
+ return void 0;
2715
+ }
2716
+ return {
2717
+ location,
2718
+ title: boardTitle(location, tag),
2719
+ expiry: cycle.expiry,
2720
+ jobs: entries.map((entry, index) => adaptOracleJob(location, entry, index)),
2721
+ source: "oracle",
2722
+ rotation: cycle.rot,
2723
+ vaultRotation: cycle.vaultRot,
2724
+ ...location === "zariman" ? { zarimanFaction: zarimanFactionZh(cycle.zarimanFaction) } : {}
2725
+ };
2726
+ }
2727
+ __name(adaptOracleBountyBoard, "adaptOracleBountyBoard");
2728
+
2281
2729
  // src/warframe/services/wf-service.ts
2282
2730
  async function getRelic(input) {
2283
2731
  if (!input) {
@@ -2339,7 +2787,7 @@ function getArbitrations(day = 3) {
2339
2787
  return {
2340
2788
  ok: true,
2341
2789
  data: weekArbys.filter((a) => arbyRewards[a.node]).map((a) => {
2342
- const obj = regionToShort(import_warframe_public_export_plus6.ExportRegions[a.node], import_warframe_public_export_plus6.dict_zh);
2790
+ const obj = regionToShort(import_warframe_public_export_plus7.ExportRegions[a.node], import_warframe_public_export_plus7.dict_zh);
2343
2791
  return {
2344
2792
  ...obj,
2345
2793
  time: new Date(a.time * 1e3).toLocaleString("zh-cn", {
@@ -2366,7 +2814,7 @@ async function getWeekly() {
2366
2814
  return failure("common.fetchFailed", true);
2367
2815
  }
2368
2816
  const archon = {
2369
- name: import_warframe_public_export_plus6.dict_zh[`/Lotus/Language/Narmer/${removeSpace(worldState.archonHunt.boss)}`],
2817
+ name: import_warframe_public_export_plus7.dict_zh[`/Lotus/Language/Narmer/${removeSpace(worldState.archonHunt.boss)}`],
2370
2818
  missions: []
2371
2819
  };
2372
2820
  const stringToDebuff = /* @__PURE__ */ __name((key, name2, prefix) => {
@@ -2391,7 +2839,7 @@ async function getWeekly() {
2391
2839
  const deepArchimMissions = await Promise.all(
2392
2840
  deepArchim.missions.map(async (m) => {
2393
2841
  const receivedType = await getMissionTypeKey(m.missionType);
2394
- const type = import_warframe_public_export_plus6.dict_zh[import_warframe_public_export_plus6.ExportMissionTypes[receivedType]?.name ?? ""] ?? m.missionType;
2842
+ const type = import_warframe_public_export_plus7.dict_zh[import_warframe_public_export_plus7.ExportMissionTypes[receivedType]?.name ?? ""] ?? m.missionType;
2395
2843
  const deviation = stringToDebuff(
2396
2844
  m.deviation.key,
2397
2845
  m.deviation.name,
@@ -2419,7 +2867,7 @@ async function getWeekly() {
2419
2867
  const temporalArchimMissions = await Promise.all(
2420
2868
  temporalArchim.missions.map(async (m) => {
2421
2869
  const receivedType = await getMissionTypeKey(m.missionType);
2422
- const type = import_warframe_public_export_plus6.dict_zh[import_warframe_public_export_plus6.ExportMissionTypes[receivedType]?.name ?? ""] ?? receivedType;
2870
+ const type = import_warframe_public_export_plus7.dict_zh[import_warframe_public_export_plus7.ExportMissionTypes[receivedType]?.name ?? ""] ?? receivedType;
2423
2871
  const deviation = stringToDebuff(
2424
2872
  m.deviation.key,
2425
2873
  m.deviation.name,
@@ -2483,13 +2931,43 @@ ${duviri}
2483
2931
  ${zariman}`;
2484
2932
  }
2485
2933
  __name(getEnvironment, "getEnvironment");
2934
+ async function getBounty(location) {
2935
+ if (oracleBountyLocations.has(location)) {
2936
+ const cycle = await globalOracleBountyCycle.get();
2937
+ if (!cycle) {
2938
+ return failure("common.fetchFailed", true);
2939
+ }
2940
+ const board2 = adaptOracleBountyBoard(
2941
+ location,
2942
+ cycle
2943
+ );
2944
+ if (!board2) {
2945
+ return failure("bounty.unavailable");
2946
+ }
2947
+ return { ok: true, data: board2 };
2948
+ }
2949
+ const { syndicateMissionsRaw } = await globalWorldState.get();
2950
+ if (!syndicateMissionsRaw) {
2951
+ return failure("common.fetchFailed", true);
2952
+ }
2953
+ const mission = findRawSyndicateMission(syndicateMissionsRaw, location);
2954
+ if (!mission) {
2955
+ return failure("common.fetchFailed", true);
2956
+ }
2957
+ const board = adaptBountyBoard(location, mission);
2958
+ if (!board) {
2959
+ return failure("bounty.unavailable");
2960
+ }
2961
+ return { ok: true, data: board };
2962
+ }
2963
+ __name(getBounty, "getBounty");
2486
2964
  function getCircuitWeek() {
2487
2965
  const EPOCH = 1734307200 * 1e3;
2488
2966
  const week = Math.trunc((Date.now() - EPOCH) / 6048e5);
2489
2967
  const index1 = (week + 1) % incarnons.length;
2490
2968
  const index2 = (week + 8) % warframes.length;
2491
- const incarnons2 = incarnons.map((v) => v.map((i) => import_warframe_public_export_plus6.dict_zh[i]));
2492
- const warframes2 = warframes.map((v) => v.map((i) => import_warframe_public_export_plus6.dict_zh[i]));
2969
+ const incarnons2 = incarnons.map((v) => v.map((i) => import_warframe_public_export_plus7.dict_zh[i]));
2970
+ const warframes2 = warframes.map((v) => v.map((i) => import_warframe_public_export_plus7.dict_zh[i]));
2493
2971
  return {
2494
2972
  currentIncarnons: index1,
2495
2973
  currentWarframes: index2,
@@ -2876,7 +3354,7 @@ function analyzeRivenStat(parseResult) {
2876
3354
  __name(analyzeRivenStat, "analyzeRivenStat");
2877
3355
 
2878
3356
  // src/warframe/services/wfm-service/index.ts
2879
- var import_warframe_public_export_plus7 = require("warframe-public-export-plus");
3357
+ var import_warframe_public_export_plus8 = require("warframe-public-export-plus");
2880
3358
 
2881
3359
  // src/warframe/data/wfm/globalDucatnator.ts
2882
3360
  var globalDucatnatorIDDict = createAsyncCache(async () => {
@@ -3610,7 +4088,7 @@ async function getRivenOrders(input) {
3610
4088
  }
3611
4089
  __name(getRivenOrders, "getRivenOrders");
3612
4090
  async function applyRelicData(relic) {
3613
- const tier = import_warframe_public_export_plus7.dict_zh[relic.tierKey] ?? relic.tier;
4091
+ const tier = import_warframe_public_export_plus8.dict_zh[relic.tierKey] ?? relic.tier;
3614
4092
  const { globalItemGameRefDict } = await globalItemData.get();
3615
4093
  const wfmDict = await globalDucatnatorIDDict.get();
3616
4094
  const loadedItems = relic.items.map((element) => {
@@ -3698,7 +4176,7 @@ var primedModHistory = createAsyncCache(async () => {
3698
4176
  }, 432e5);
3699
4177
 
3700
4178
  // src/warframe/services/world-state-refresh.ts
3701
- var import_warframe_public_export_plus8 = require("warframe-public-export-plus");
4179
+ var import_warframe_public_export_plus9 = require("warframe-public-export-plus");
3702
4180
  var ALLOWED_FISSURE_MISSION_TYPES = /* @__PURE__ */ new Set(["MT_EXTERMINATION", "MT_DEFENSE", "MT_ARTIFACT"]);
3703
4181
  function time(value) {
3704
4182
  return value?.getTime() ?? 0;
@@ -3717,7 +4195,7 @@ function fissureId(value) {
3717
4195
  __name(fissureId, "fissureId");
3718
4196
  async function fissureMissionType(fissure) {
3719
4197
  const nodeKey = await getSolNodeKey(fissure.nodeKey);
3720
- return import_warframe_public_export_plus8.ExportRegions[nodeKey]?.missionType;
4198
+ return import_warframe_public_export_plus9.ExportRegions[nodeKey]?.missionType;
3721
4199
  }
3722
4200
  __name(fissureMissionType, "fissureMissionType");
3723
4201
  function dailyDealId(value) {
@@ -4343,6 +4821,85 @@ function FissureComponent(fissures, type) {
4343
4821
  ] });
4344
4822
  }
4345
4823
  __name(FissureComponent, "FissureComponent");
4824
+ function BountyComponent(board) {
4825
+ const timeLeft = board.expiry - Date.now();
4826
+ const timeColor = timeLeft > 36e5 ? "var(--wf-success)" : timeLeft > 6e5 ? "var(--wf-info)" : "var(--wf-danger)";
4827
+ const rarityColor = {
4828
+ bronze: "var(--wf-rarity-common)",
4829
+ silver: "var(--wf-rarity-uncommon)",
4830
+ gold: "var(--wf-rarity-rare)"
4831
+ };
4832
+ const isOracle = board.source === "oracle";
4833
+ const metaParts = [];
4834
+ if (board.zarimanFaction) {
4835
+ metaParts.push(`阵营 ${board.zarimanFaction}`);
4836
+ }
4837
+ if (board.rotation) {
4838
+ metaParts.push(`轮换 ${board.rotation}`);
4839
+ }
4840
+ if (board.vaultRotation) {
4841
+ metaParts.push(`隔离库 ${board.vaultRotation}`);
4842
+ }
4843
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
4844
+ "div",
4845
+ {
4846
+ style: "width:640px;background-color:var(--wf-bg-card);border-radius:var(--wf-radius);padding:16px;box-shadow:var(--wf-shadow-card);border:1px solid var(--wf-border);font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;color:var(--wf-text-body);",
4847
+ children: [
4848
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { style: "font-size:22px;font-weight:bold;color:var(--wf-text-primary);margin:0 0 8px 0;text-align:center;", children: board.title }),
4849
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: `text-align:center;font-size:13px;margin-bottom:8px;color:${timeColor};`, children: [
4850
+ "剩余",
4851
+ msToHumanReadable(Math.max(timeLeft, 0))
4852
+ ] }),
4853
+ metaParts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: "text-align:center;font-size:12px;color:var(--wf-text-secondary);margin-bottom:12px;", children: metaParts.join(" · ") }) : null,
4854
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: "display:flex;flex-direction:column;gap:10px;", children: board.jobs.map((job) => {
4855
+ const tags = [];
4856
+ if (job.isVault)
4857
+ tags.push("隔离库");
4858
+ if (job.isNarmer)
4859
+ tags.push("合一众");
4860
+ if (job.ally)
4861
+ tags.push(job.ally);
4862
+ const hasRewards = job.stages.some((stage) => stage.length > 0);
4863
+ const standingLabel = job.standingUnit === "vq" ? "VQ" : "声望";
4864
+ const metaLine = [
4865
+ `等级 ${job.enemyLevels[0]}-${job.enemyLevels[1]}`,
4866
+ job.minMR > 0 ? `段位 ${job.minMR}+` : void 0,
4867
+ job.standingStages.length > 0 ? `${standingLabel} ${job.standingStages.join("/")}` : void 0
4868
+ ].filter(Boolean).join(" · ");
4869
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
4870
+ "div",
4871
+ {
4872
+ style: "padding:10px 12px;background-color:var(--wf-bg-subtle);border-radius:var(--wf-radius-sm);border-left:3px solid var(--wf-accent);",
4873
+ children: [
4874
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: "display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:6px;", children: [
4875
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: "font-size:15px;font-weight:700;color:var(--wf-text-primary);", children: job.name }),
4876
+ tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
4877
+ "span",
4878
+ {
4879
+ style: "font-size:11px;color:var(--wf-accent);background-color:rgba(71,181,165,0.12);padding:1px 6px;border-radius:var(--wf-radius-sm);",
4880
+ children: tag
4881
+ }
4882
+ ))
4883
+ ] }),
4884
+ metaLine ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: "font-size:12px;color:var(--wf-text-secondary);margin-bottom:6px;", children: metaLine }) : null,
4885
+ job.challenge ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: "font-size:12px;line-height:1.45;color:var(--wf-text-body);margin-bottom:4px;", children: job.challenge }) : null,
4886
+ hasRewards ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: "display:flex;flex-direction:column;gap:6px;", children: job.stages.map((stage, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: "font-size:12px;line-height:1.45;", children: [
4887
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: "color:var(--wf-text-secondary);margin-right:6px;", children: `阶段${index + 1}` }),
4888
+ stage.map((reward, rewardIndex) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
4889
+ rewardIndex > 0 ? "、" : "",
4890
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: `color:${rarityColor[reward.rarity]};`, children: reward.name })
4891
+ ] }))
4892
+ ] })) }) : !isOracle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: "font-size:12px;color:var(--wf-text-body);", children: "奖励未知" }) : null
4893
+ ]
4894
+ }
4895
+ );
4896
+ }) }),
4897
+ isOracle ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: "margin-top:12px;font-size:11px;color:var(--wf-text-muted);text-align:right;", children: "数据来源: browse.wf" }) : null
4898
+ ]
4899
+ }
4900
+ );
4901
+ }
4902
+ __name(BountyComponent, "BountyComponent");
4346
4903
  function WeeklyRivenComponent(items, minPrice) {
4347
4904
  const formatPrice = /* @__PURE__ */ __name((value) => Number.isInteger(value) ? value.toString() : value.toFixed(1), "formatPrice");
4348
4905
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
@@ -5446,6 +6003,13 @@ __name(VoidTraderComponent, "VoidTraderComponent");
5446
6003
  // src/commands/wf.ts
5447
6004
  function createWfCommands(deps) {
5448
6005
  const { config, render } = deps;
6006
+ const bountyCommand = /* @__PURE__ */ __name(async (location) => {
6007
+ const result = await getBounty(location);
6008
+ if (!result.ok) {
6009
+ return t(result);
6010
+ }
6011
+ return render(BountyComponent(result.data));
6012
+ }, "bountyCommand");
5449
6013
  return {
5450
6014
  arbitrationCommand: /* @__PURE__ */ __name(async (_action, input) => {
5451
6015
  const result = getArbitrations(input);
@@ -5550,7 +6114,13 @@ function createWfCommands(deps) {
5550
6114
  }, "weeklyRivenCommand"),
5551
6115
  environmentCommand: /* @__PURE__ */ __name(async () => {
5552
6116
  return getEnvironment();
5553
- }, "environmentCommand")
6117
+ }, "environmentCommand"),
6118
+ bountyCetusCommand: /* @__PURE__ */ __name(async () => bountyCommand("cetus"), "bountyCetusCommand"),
6119
+ bountyFortunaCommand: /* @__PURE__ */ __name(async () => bountyCommand("fortuna"), "bountyFortunaCommand"),
6120
+ bountyDeimosCommand: /* @__PURE__ */ __name(async () => bountyCommand("deimos"), "bountyDeimosCommand"),
6121
+ bountyZarimanCommand: /* @__PURE__ */ __name(async () => bountyCommand("zariman"), "bountyZarimanCommand"),
6122
+ bountyCaviaCommand: /* @__PURE__ */ __name(async () => bountyCommand("cavia"), "bountyCaviaCommand"),
6123
+ bountyHexCommand: /* @__PURE__ */ __name(async () => bountyCommand("hex"), "bountyHexCommand")
5554
6124
  };
5555
6125
  }
5556
6126
  __name(createWfCommands, "createWfCommands");
@@ -6288,7 +6858,13 @@ function setupCommands(ctx, deps) {
6288
6858
  ctx.command("fissure-sp", "当前钢铁之路虚空裂隙").alias("spfissure").alias("钢铁裂缝").alias("钢铁裂隙").action(wf.steelPathFissureCommand);
6289
6859
  ctx.command("fissure-rj", "当前九重天虚空裂隙").alias("rjfissure").alias("九重天裂缝").alias("九重天裂隙").action(wf.railjackFissureCommand);
6290
6860
  ctx.command("relic <relic-name:text>", "查询遗物内容").alias("遗物").alias("核桃").action(wf.relicCommand);
6291
- ctx.command("environment", "当前各区域状态").alias("env").alias("平原").alias("地球").alias("金星").alias("夜灵").alias("夜灵平野").alias("奥布山谷").action(wf.environmentCommand);
6861
+ ctx.command("environment", "当前各区域状态").alias("env").alias("平原").alias("夜灵平野").alias("奥布山谷").alias("魔胎之境").alias("扎里曼").action(wf.environmentCommand);
6862
+ ctx.command("bounty-cetus", "希图斯赏金").alias("希图斯").alias("希图斯赏金").alias("赏金希图斯").alias("cetus").alias("ostron").action(wf.bountyCetusCommand);
6863
+ ctx.command("bounty-fortuna", "福尔图娜赏金").alias("福尔图娜").alias("福尔图娜赏金").alias("赏金福尔图娜").alias("fortuna").alias("solaris").action(wf.bountyFortunaCommand);
6864
+ ctx.command("bounty-deimos", "火卫二赏金").alias("火卫二").alias("火卫二赏金").alias("赏金火卫二").alias("deimos").alias("entrati").action(wf.bountyDeimosCommand);
6865
+ ctx.command("bounty-zariman", "扎里曼赏金").alias("扎里曼赏金").alias("赏金扎里曼").alias("zariman").alias("holdfasts").action(wf.bountyZarimanCommand);
6866
+ ctx.command("bounty-cavia", "科维兽赏金").alias("科维兽").alias("科维兽赏金").alias("赏金科维兽").alias("cavia").action(wf.bountyCaviaCommand);
6867
+ ctx.command("bounty-hex", "六人组赏金").alias("六人组").alias("六人组赏金").alias("赏金六人组").alias("hex").action(wf.bountyHexCommand);
6292
6868
  ctx.command("weekly", "周常任务").alias("周常").alias("科研").alias("时光科研").alias("深层科研").alias("执行官").action(wf.weeklyCommand);
6293
6869
  ctx.command("circuit", "本周回廊战甲及灵化之源").alias("灵化之源").alias("灵化").action(wf.circuitCommand);
6294
6870
  ctx.command("riven <img:image>", "分析紫卡截图").action(wf.rivenCommand);