TC Bootlegging Plus v2

Tools to help with Bootlegging

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

  1. // ==UserScript==
  2. // @name TC Bootlegging Plus v2
  3. // @namespace DieselBladeScripts
  4. // @version 0.9
  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;
  78. const RED_HSL = 0;
  79.  
  80. const totalHave = sumValues(CDs.have);
  81. const totalSold = sumValues(CDs.sold);
  82.  
  83. let worstProportion = Infinity;
  84. let bestProportion = 0;
  85.  
  86. // First pass to determine worst and best proportions
  87. document.querySelectorAll('button[class^=genreStock]').forEach((genreButton) => {
  88. const genre = genreButton.getAttribute('aria-label').split(' - ')[0].replace('Copying ', '');
  89. const typeID = CDs.genres[genre];
  90. const target = Math.floor((CDs.sold[typeID] / totalSold) * totalHave);
  91. const proportion = CDs.have[typeID] / target;
  92.  
  93. if (proportion < worstProportion) {
  94. worstProportion = proportion;
  95. }
  96. if (proportion > bestProportion) {
  97. bestProportion = proportion;
  98. }
  99. });
  100.  
  101. // Second pass to assign colors based on relative proportions
  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 proportion = CDs.have[typeID] / target;
  107.  
  108. // Normalize the proportion based on worst and best
  109. const normalizedProportion = (proportion - worstProportion) / (bestProportion - worstProportion);
  110. const h = RED_HSL + normalizedProportion * (GREEN_HSL - RED_HSL);
  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 diff = target - CDs.have[typeID];
  121. const diffText = document.createElement('div');
  122. diffText.className = 'diffText'; // Add a class to the diffText for easy selection
  123. diffText.textContent = diff > 0 ? `${diff} more needed` : 'Excess copies';
  124. genreButton.appendChild(diffText);
  125. });
  126. }
  127.  
  128.  
  129. function sumValues(obj) {
  130. return Object.values(obj).reduce((a, b) => a + b, 0);
  131. }
  132.  
  133. function addGuideBox() {
  134. const guideBox = document.createElement("div");
  135. guideBox.style.position = "fixed";
  136. guideBox.style.top = "10px";
  137. guideBox.style.right = "10px";
  138. guideBox.style.backgroundColor = "#333";
  139. guideBox.style.padding = "10px";
  140. guideBox.style.border = "2px solid gold";
  141. guideBox.style.zIndex = "9999";
  142. guideBox.style.borderRadius = "5px";
  143.  
  144. const title = document.createElement("h2");
  145. title.textContent = "Phantom Scripting";
  146. title.style.color = "gold";
  147. title.style.marginBottom = "10px";
  148. guideBox.appendChild(title);
  149.  
  150. const explanation = document.createElement("p");
  151. explanation.innerHTML = `
  152. <strong>Color Guide:</strong>
  153. <br><span style="background-color:hsl(120, 100%, 90%); display:inline-block; width:16px; height:16px; margin-right:4px;"></span> Perfect quantity.
  154. <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.
  155. `;
  156. explanation.style.color = "white";
  157. guideBox.appendChild(explanation);
  158.  
  159. document.body.appendChild(guideBox);
  160. }
  161.