Greasy Fork is available in English.

Tribal Wars Resource Buyer (Multi-language)

Automate buying resources in Tribal Wars with premium points limit - works in all languages

  1. // ==UserScript==
  2. // @name Tribal Wars Resource Buyer (Multi-language)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4.0
  5. // @description Automate buying resources in Tribal Wars with premium points limit - works in all languages
  6. // @author ricardofauch (modified)
  7. // @match https://*.die-staemme.de/game.php?village=*&screen=market&mode=exchange
  8. // @match https://*.tribalwars.*/game.php?village=*&screen=market&mode=exchange
  9. // @match https://*.plemiona.pl/game.php?village=*&screen=market&mode=exchange
  10. // @match https://*.tribal-wars.*/game.php?village=*&screen=market&mode=exchange
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // Default configuration
  20. const DEFAULT_CONFIG = {
  21. MAX_PREMIUM_POINTS: 300,
  22. PREMIUM_POINTS_TIMEOUT: 600000, // 10 minutes in ms
  23. PURCHASE_PERCENTAGE: 0.7,
  24. MIN_STOCK_THRESHOLD: 50,
  25. PAGE_RELOAD_INTERVAL: 10000, // 10 seconds in ms
  26. RANDOM_INTERVAL_MIN: 50,
  27. RANDOM_INTERVAL_MAX: 180,
  28. ENABLED: true
  29. };
  30.  
  31. // Load configuration from storage or use defaults
  32. let config = Object.assign({}, DEFAULT_CONFIG, GM_getValue('buyerConfig', {}));
  33.  
  34. let isReloadNeeded = false;
  35. let reloadInterval;
  36.  
  37. // Create and inject configuration UI
  38. function createConfigUI() {
  39. const configDiv = document.createElement('div');
  40. configDiv.style.cssText = `
  41. position: fixed;
  42. top: 10%;
  43. left: 4%;
  44. background-color: rgba(240, 216, 176, 0.90);
  45. border: 1px solid #333;
  46. padding: 10px;
  47. z-index: 9999;
  48. max-width: 200px;
  49. border-radius: 5px;
  50. box-shadow: 0 0 10px rgba(0,0,0,0.1);
  51. `;
  52.  
  53. configDiv.innerHTML = `
  54. <h3 style="margin: 0 0 10px 0;">Resource Buyer Settings</h3>
  55. <div style="display: grid; gap: 5px;">
  56. <label>
  57. <input type="checkbox" id="buyer-enabled" ${config.ENABLED ? 'checked' : ''}>
  58. Enable Buyer
  59. </label>
  60. <label>
  61. Max Premium Points:
  62. <input type="number" id="max-premium" value="${config.MAX_PREMIUM_POINTS}" min="0">
  63. </label>
  64. <label>
  65. Premium Points Timeout (min):
  66. <input type="number" id="premium-timeout" value="${config.PREMIUM_POINTS_TIMEOUT / 60000}" min="1">
  67. </label>
  68. <label>
  69. Purchase Percentage:
  70. <input type="number" id="purchase-percentage" value="${config.PURCHASE_PERCENTAGE * 100}" min="1" max="100" step="1">
  71. </label>
  72. <label>
  73. Min Stock Threshold:
  74. <input type="number" id="min-stock" value="${config.MIN_STOCK_THRESHOLD}" min="1">
  75. </label>
  76. <label>
  77. Page Reload Interval (sec):
  78. <input type="number" id="reload-interval" value="${config.PAGE_RELOAD_INTERVAL / 1000}" min="1">
  79. </label>
  80. <label>
  81. Random Interval Min (ms):
  82. <input type="number" id="random-min" value="${config.RANDOM_INTERVAL_MIN}" min="0">
  83. </label>
  84. <label>
  85. Random Interval Max (ms):
  86. <input type="number" id="random-max" value="${config.RANDOM_INTERVAL_MAX}" min="0">
  87. </label>
  88. <button id="save-config" style="margin-top: 5px;">Save Settings</button>
  89. <div id="save-status" style="color: green; display: none;">Settings saved!</div>
  90. </div>
  91. `;
  92.  
  93. document.body.appendChild(configDiv);
  94.  
  95. // Add event listener for save button
  96. document.getElementById('save-config').addEventListener('click', saveConfig);
  97.  
  98. document.getElementById('buyer-enabled').addEventListener('change', function(e) {
  99. config.ENABLED = e.target.checked;
  100. GM_setValue('buyerConfig', config);
  101. restartIntervals();
  102.  
  103. // Show save confirmation
  104. const saveStatus = document.getElementById('save-status');
  105. saveStatus.style.display = 'block';
  106. saveStatus.textContent = config.ENABLED ? 'Buyer enabled!' : 'Buyer disabled!';
  107. setTimeout(() => {
  108. saveStatus.style.display = 'none';
  109. }, 2000);
  110. });
  111.  
  112. }
  113.  
  114. function saveConfig() {
  115. config = {
  116. ENABLED: document.getElementById('buyer-enabled').checked,
  117. MAX_PREMIUM_POINTS: parseInt(document.getElementById('max-premium').value),
  118. PREMIUM_POINTS_TIMEOUT: parseInt(document.getElementById('premium-timeout').value) * 60000,
  119. PURCHASE_PERCENTAGE: parseInt(document.getElementById('purchase-percentage').value) / 100,
  120. MIN_STOCK_THRESHOLD: parseInt(document.getElementById('min-stock').value),
  121. PAGE_RELOAD_INTERVAL: parseInt(document.getElementById('reload-interval').value) * 1000,
  122. RANDOM_INTERVAL_MIN: parseInt(document.getElementById('random-min').value),
  123. RANDOM_INTERVAL_MAX: parseInt(document.getElementById('random-max').value)
  124. };
  125.  
  126. GM_setValue('buyerConfig', config);
  127.  
  128. // Show save confirmation
  129. const saveStatus = document.getElementById('save-status');
  130. saveStatus.style.display = 'block';
  131. setTimeout(() => {
  132. saveStatus.style.display = 'none';
  133. }, 2000);
  134.  
  135. // Restart intervals with new config
  136. restartIntervals();
  137. }
  138.  
  139. function restartIntervals() {
  140. // Clear existing intervals
  141. if (reloadInterval) clearInterval(reloadInterval);
  142.  
  143. // Set up new intervals if enabled
  144. if (config.ENABLED) {
  145. console.log(`Setting up automatic reload every ${config.PAGE_RELOAD_INTERVAL/1000} seconds`);
  146. reloadInterval = setInterval(function() {
  147. console.log('Executing scheduled reload...');
  148. window.location.reload();
  149. }, config.PAGE_RELOAD_INTERVAL);
  150. }
  151. }
  152.  
  153. function checkPremiumPoints() {
  154. console.log('Checking premium points...');
  155. const marketStatusBar = document.getElementById('market_status_bar');
  156. if (marketStatusBar) {
  157. const premiumIcon = marketStatusBar.querySelector('.icon.header.premium');
  158. if (premiumIcon) {
  159. const parentElement = premiumIcon.closest('th');
  160. if (parentElement) {
  161. const text = parentElement.textContent;
  162. const points = parseInt(text.replace(/\D/g, ''));
  163. console.log(`Current premium points: ${points}`);
  164. if (points > config.MAX_PREMIUM_POINTS) {
  165. console.log(`⚠️ Premium points exceed ${config.MAX_PREMIUM_POINTS}! Setting timeout...`);
  166. return new Promise(resolve => setTimeout(resolve, config.PREMIUM_POINTS_TIMEOUT));
  167. }
  168. }
  169. }
  170. }
  171. return Promise.resolve();
  172. }
  173.  
  174. function checkForUsageWarningAndReload() {
  175. console.log('Checking for usage warning...');
  176. const errorMessages = document.querySelectorAll('.error_box');
  177. for (const errorBox of errorMessages) {
  178. if (errorBox.textContent.includes('premium') ||
  179. errorBox.textContent.includes('börse') ||
  180. errorBox.textContent.includes('market') ||
  181. errorBox.textContent.includes('exchange')) {
  182. console.log("⚠️ Usage warning detected! Initiating page reload...");
  183. window.location.reload();
  184. return;
  185. }
  186. }
  187. console.log("✓ No usage warning found");
  188. }
  189.  
  190. function checkForErrorAndReload() {
  191. console.log('Checking for error image...');
  192. const errorImages = document.querySelectorAll('.error_image, img[src*="error"]');
  193.  
  194. if (errorImages.length > 0) {
  195. console.log("⚠️ Error image detected! Initiating reload...");
  196. window.location.reload();
  197. } else {
  198. console.log("✓ No error images found");
  199. }
  200. }
  201.  
  202. function clickBuyButton() {
  203. console.log('Attempting to click buy button...');
  204. const buyButton = document.querySelector('.btn-premium-exchange-buy');
  205. if (buyButton) {
  206. console.log("✓ Found buy button. Clicking...");
  207. buyButton.click();
  208. } else {
  209. console.error("❌ Buy button not found!");
  210. }
  211. }
  212.  
  213. function clickConfirmButton() {
  214. console.log('Starting confirmation dialog check...');
  215. let counter = 0;
  216. const checkDialog = setInterval(function() {
  217. const confirmDialog = document.querySelector('.confirmation-box');
  218. if (confirmDialog && confirmDialog.style.display !== 'none') {
  219. clearInterval(checkDialog);
  220. console.log("✓ Confirmation dialog detected");
  221. const confirmButton = document.querySelector('.btn-confirm-yes');
  222.  
  223. if (confirmButton) {
  224. console.log("✓ Found confirm button");
  225.  
  226. // Add click event listener before clicking
  227. confirmButton.addEventListener('click', function() {
  228. console.log("✓ Button click confirmed");
  229. const randomIntervalReload = Math.random() * (65 - 50) + 420;
  230. console.log(`Scheduling page reload in ${randomIntervalReload.toFixed(2)}ms`);
  231. setTimeout(function() {
  232. console.log('Executing scheduled reload...');
  233. window.location.reload();
  234. }, randomIntervalReload);
  235. });
  236.  
  237. console.log("Clicking button...");
  238. confirmButton.click();
  239. } else {
  240. console.error("❌ Confirm button not found! Initiating fallback reload...");
  241. window.location.reload();
  242. }
  243. }
  244. }, 20);
  245. }
  246.  
  247. async function checkAndBuyResources() {
  248. if (!config.ENABLED) {
  249. console.log('Buyer is disabled in settings');
  250. return;
  251. }
  252.  
  253. console.log('-----------------------------------');
  254. console.log('Starting resource check cycle...');
  255.  
  256. await checkPremiumPoints();
  257. checkForUsageWarningAndReload();
  258. console.log(`Current reload flag status: ${isReloadNeeded}`);
  259.  
  260. console.log(`Purchase percentage set to: ${config.PURCHASE_PERCENTAGE * 100}%`);
  261. const resources = ['wood', 'stone', 'iron'];
  262. let anyResourceAvailable = false;
  263.  
  264. for (let i = 0; i < resources.length; i++) {
  265. const resource = resources[i];
  266. const stockElement = document.getElementById(`premium_exchange_stock_${resource}`);
  267.  
  268. if (!stockElement) {
  269. console.error(`❌ Could not find stock element for ${resource}!`);
  270. continue;
  271. }
  272.  
  273. const stock = parseInt(stockElement.innerText.replace(/\D/g, ''), 10);
  274. console.log(`📊 ${resource.toUpperCase()}: Current stock: ${stock}`);
  275.  
  276. if (stock > config.MIN_STOCK_THRESHOLD) {
  277. anyResourceAvailable = true;
  278. const amountToBuy = Math.floor(stock * config.PURCHASE_PERCENTAGE);
  279. console.log(`✓ ${resource.toUpperCase()}: Sufficient stock available. Attempting to buy: ${amountToBuy}`);
  280.  
  281. const buyInputField = document.querySelector(`input[name="buy_${resource}"]`);
  282. if (buyInputField) {
  283. buyInputField.value = amountToBuy;
  284. console.log(`✓ ${resource.toUpperCase()}: Set buy amount to ${amountToBuy}`);
  285. isReloadNeeded = false;
  286.  
  287. const randomIntervalBuy = Math.random() * (config.RANDOM_INTERVAL_MAX - config.RANDOM_INTERVAL_MIN) + config.RANDOM_INTERVAL_MIN;
  288. console.log(`Scheduling buy click in ${randomIntervalBuy.toFixed(2)}ms`);
  289. setTimeout(function() {
  290. console.log('Executing scheduled buy click...');
  291. clickBuyButton();
  292. }, randomIntervalBuy);
  293.  
  294. const randomIntervalConfirm = Math.random() * (65 - 50) + 50;
  295. console.log(`Scheduling confirm click in ${randomIntervalConfirm.toFixed(2)}ms`);
  296. setTimeout(function() {
  297. console.log('Executing scheduled confirm click...');
  298. clickConfirmButton();
  299. }, randomIntervalConfirm);
  300.  
  301. break;
  302. } else {
  303. console.error(`❌ ${resource.toUpperCase()}: Buy input field not found!`);
  304. }
  305. } else {
  306. console.log(`ℹ️ ${resource.toUpperCase()}: Insufficient stock (${stock} < ${config.MIN_STOCK_THRESHOLD})`);
  307. }
  308. }
  309.  
  310. isReloadNeeded = !anyResourceAvailable;
  311. console.log(`Resource check complete. Reload needed: ${isReloadNeeded}`);
  312.  
  313. if (isReloadNeeded) {
  314. const randomInterval = Math.random() * (4000 - 50) + 200;
  315. console.log(`No resources available. Scheduling reload in ${randomInterval.toFixed(2)}ms`);
  316. setTimeout(function() {
  317. console.log('Executing scheduled reload due to no resources...');
  318. window.location.reload();
  319. }, randomInterval);
  320. }
  321. }
  322.  
  323. // Initialize UI and start script
  324. console.log('Script initialized. Version 1.4.0');
  325. createConfigUI();
  326.  
  327. const randomIntervalCheck = Math.random() * (config.RANDOM_INTERVAL_MAX - config.RANDOM_INTERVAL_MIN) + config.RANDOM_INTERVAL_MIN;
  328. console.log(`Initial check scheduled in ${randomIntervalCheck.toFixed(2)}ms`);
  329. setTimeout(function() {
  330. console.log('Executing initial resource check...');
  331. checkAndBuyResources();
  332. }, randomIntervalCheck);
  333.  
  334. restartIntervals();
  335.  
  336. })();