TC Bootlegging Plus v2

Tools to help with Bootlegging

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

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