TC Bootlegging Plus v2

Tools to help with Bootlegging

当前为 2025-04-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name TC Bootlegging Plus v2
  3. // @namespace DieselBladeScripts
  4. // @version 0.95
  5. // @description Tools to help with Bootlegging
  6. // @license GPLv3
  7. // @author DieselBlade [1701621], Hemicopter [2780600]
  8. // @match https://www.torn.com/loader.php?sid=crimes*
  9. // @match https://torn.com/loader.php?sid=crimes*
  10. // @grant unsafeWindow
  11. // @run-at document-start
  12. // @grant GM_xmlhttpRequest
  13. // ==/UserScript==
  14.  
  15.  
  16. const isTampermonkeyEnabled = typeof unsafeWindow !== 'undefined';
  17. const win = isTampermonkeyEnabled ? unsafeWindow : window;
  18. const {fetch: originalFetch} = win;
  19.  
  20. win.fetch = async (...args) => {
  21. const response = args.length == 2 ? await originalFetch(args[0], args[1]) : await originalFetch(args[0]);
  22. let url = args[0];
  23. if(typeof url === "object") url = url.url;
  24. if (url.includes('crimesData')) {
  25. crimesMain(response.clone()).catch(console.error);
  26. }
  27. return response;
  28. };
  29.  
  30. async function crimesMain(res) {
  31. const crimesData = await res.json();
  32. const crimeType = crimesData?.DB?.currentUserStatistics?.[1]?.value;
  33.  
  34. if (crimeType === 'Counterfeiting') {
  35. counterfeiting(crimesData.DB);
  36. } else {
  37. console.log(crimesData);
  38. }
  39. }
  40.  
  41. async function counterfeiting(db) {
  42. const { generalInfo, currentUserStats, crimesByType } = db;
  43. const CDs = {
  44. have: generalInfo.CDs,
  45. sold: {
  46. 1: currentUserStats.CDType1Sold,
  47. 2: currentUserStats.CDType2Sold,
  48. 3: currentUserStats.CDType3Sold,
  49. 4: currentUserStats.CDType4Sold,
  50. 5: currentUserStats.CDType5Sold,
  51. 6: currentUserStats.CDType6Sold,
  52. 7: currentUserStats.CDType7Sold,
  53. 8: currentUserStats.CDType8Sold
  54. },
  55. genres: {
  56. 'Action': '1',
  57. 'Comedy': '2',
  58. 'Drama': '3',
  59. 'Fantasy': '4',
  60. 'Horror': '5',
  61. 'Romance': '6',
  62. 'Thriller': '7',
  63. 'Sci-Fi': '8'
  64. }
  65. };
  66.  
  67. const currentQueue = crimesByType?.['0']?.additionalInfo?.currentQueue || [];
  68. currentQueue.forEach(cdID => CDs.have[cdID] += 1);
  69.  
  70. const observer = new MutationObserver(() => {
  71. const genreButtons = document.querySelectorAll('button[class^=genreStock]');
  72. if (genreButtons.length > 0) {
  73. updateGenreButtons(CDs);
  74. observer.disconnect();
  75. }
  76. });
  77.  
  78. observer.observe(document, { childList: true, subtree: true });
  79. }
  80.  
  81. function updateGenreButtons(CDs) {
  82. const GREEN_HSL = 120; // Green for excess copies
  83. const RED_HSL = 0; // Red for biggest shortages
  84.  
  85. const totalHave = sumValues(CDs.have);
  86. const totalSold = sumValues(CDs.sold);
  87.  
  88. let maxShortage = 0; // Track the worst shortage
  89.  
  90. // First pass: Determine the maximum shortage
  91. document.querySelectorAll('button[class^=genreStock]').forEach((genreButton) => {
  92. const genre = genreButton.getAttribute('aria-label').split(' - ')[0].replace('Copying ', '');
  93. const typeID = CDs.genres[genre];
  94. const target = Math.floor((CDs.sold[typeID] / totalSold) * totalHave);
  95. const diff = target - CDs.have[typeID]; // Positive means more are needed, negative means excess
  96. if (diff > maxShortage) {
  97. maxShortage = diff; // Store the highest shortage
  98. }
  99. });
  100.  
  101. // Second pass: Apply colors based on shortage severity
  102. document.querySelectorAll('button[class^=genreStock]').forEach((genreButton) => {
  103. const genre = genreButton.getAttribute('aria-label').split(' - ')[0].replace('Copying ', '');
  104. const typeID = CDs.genres[genre];
  105. const target = Math.floor((CDs.sold[typeID] / totalSold) * totalHave);
  106. const diff = target - CDs.have[typeID]; // Positive means more are needed, negative means excess
  107.  
  108. let h;
  109. if (diff > 0) {
  110. // Shortage: scale from red (0) to neutral
  111. h = RED_HSL + (1 - diff / maxShortage) * (GREEN_HSL - RED_HSL);
  112. } else {
  113. // Excess: Make it green
  114. h = GREEN_HSL;
  115. }
  116.  
  117. genreButton.style.backgroundColor = `hsl(${h}, 100%, 90%)`;
  118.  
  119. // Ensure text remains readable
  120. genreButton.style.color = "#888"; // Ensure button text is dark grey
  121.  
  122. // Update the "copying" text color
  123. const statusText = genreButton.querySelector('.statusText___fRZso');
  124. if (statusText) {
  125. statusText.style.color = "#888";
  126. }
  127.  
  128. // Update the text for how many more are needed or if there are excess copies
  129. const existingDiffText = genreButton.querySelector('.diffText');
  130. if (existingDiffText) {
  131. existingDiffText.remove();
  132. }
  133.  
  134. const diffText = document.createElement('div');
  135. diffText.className = 'diffText';
  136. diffText.textContent = diff > 0 ? `${diff} more needed` : 'Excess copies';
  137. diffText.style.color = "#888"; // Ensure text remains readable
  138. genreButton.appendChild(diffText);
  139. });
  140. }
  141.  
  142.  
  143.  
  144.  
  145.  
  146. function sumValues(obj) {
  147. return Object.values(obj).reduce((a, b) => a + b, 0);
  148. }
  149.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址