// ==UserScript== // @name GrepoTweaks-AutoRuralResources (Captain-Free Version) // @namespace sentinelindicator // @version 2.2.0 // @description Auto farm loot from rural villages using per-town AJAX requests, no Captain required // @author Dimitrios // @match http://*.grepolis.com/game/* // @match https://*.grepolis.com/game/* // @grant none // ==/UserScript== (function () { 'use strict'; const uw = typeof unsafeWindow !== "undefined" ? unsafeWindow : window; const timerInterval = 300000; // 5 minutes const delta_time = 10000; let loop, lastTime, timer; let startOnLogin = true; const buttonHtml = '
' + '
' + '

' + '
'; function getPolisList() { const islandList = []; const polisList = []; const towns = uw.MM.getCollections().Town[0].models; for (let town of towns) { const { on_small_island, island_id, id } = town.attributes; if (on_small_island) continue; if (!islandList.includes(island_id)) { islandList.push(island_id); polisList.push(id); } } return polisList; } function getLootableFarms(town_id) { const { models: farms } = uw.MM.getOnlyCollectionByName('FarmTown'); const { models: relations } = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation'); const town = uw.ITowns.towns[town_id]; const x = town.getIslandCoordinateX(); const y = town.getIslandCoordinateY(); const now = Math.floor(Date.now() / 1000); const result = []; for (let farm of farms) { if (farm.attributes.island_x !== x || farm.attributes.island_y !== y) continue; for (let rel of relations) { if ( rel.attributes.farm_town_id === farm.attributes.id && rel.attributes.relation_status === 1 && (!rel.attributes.lootable_at || now >= rel.attributes.lootable_at) ) { result.push({ town_id, farm_town_id: rel.attributes.farm_town_id, relation_id: rel.id }); } } } return result; } function claimSingle(town_id, farm_town_id, relation_id) { const data = { model_url: `FarmTownPlayerRelation/${relation_id}`, action_name: 'claim', arguments: { farm_town_id: farm_town_id, type: 'resources', option: 1 }, town_id: town_id, }; uw.gpAjax.ajaxPost('frontend_bridge', 'execute', data); } async function claimIndividually(polisList) { let max = 60; for (let town_id of polisList) { const farms = getLootableFarms(town_id); for (let farm of farms) { claimSingle(farm.town_id, farm.farm_town_id, farm.relation_id); await new Promise(r => setTimeout(r, 500)); if (!--max) return; } } } function getNextCollectionTime() { const models = uw.MM.getCollections().FarmTownPlayerRelation[0].models; let lootTimes = {}; for (let m of models) { const time = m.attributes.lootable_at; lootTimes[time] = (lootTimes[time] || 0) + 1; } let max = 0; let next = 0; for (let key in lootTimes) { if (lootTimes[key] > max) { max = lootTimes[key]; next = key; } } const seconds = next - Math.floor(Date.now() / 1000); return seconds > 0 ? seconds * 1000 : 0; } async function mainLoop() { const next = getNextCollectionTime(); if (timer + 2 * delta_time < next) { timer = next + Math.floor(Math.random() * delta_time); } if (timer < 1) { const polisList = getPolisList(); await claimIndividually(polisList); timer = timerInterval + Math.floor(Math.random() * delta_time); setTimeout(() => uw.WMap.removeFarmTownLootCooldownIconAndRefreshLootTimers(), 2000); } const now = Date.now(); timer -= now - lastTime; lastTime = now; const bt = document.getElementById('ptimer'); bt.innerHTML = timer > 0 ? parseInt(timer / 1000) : '0'; } function handleClick() { const isCaptainActive = uw.GameDataPremium.isAdvisorActivated('captain'); if (!loop) { timer = getNextCollectionTime() + Math.random() * delta_time; lastTime = Date.now(); loop = setInterval(mainLoop, 1000); uw.$('#btbutton').css( 'filter', isCaptainActive ? 'brightness(100%) sepia(100%) hue-rotate(90deg) saturate(1500%) contrast(0.8)' : 'brightness(294%) sepia(100%) hue-rotate(15deg) saturate(1000%) contrast(0.8)' ); } else { clearInterval(loop); loop = null; uw.$('#btbutton').css( 'filter', 'brightness(70%) sepia(100%) hue-rotate(-50deg) saturate(1000%) contrast(0.8)' ); } } setTimeout(() => { if (!document.getElementById('btbutton')) { uw.$('.tb_activities, .toolbar_activities').find('.middle').append(buttonHtml); } if (startOnLogin) handleClick(); }, 4000); uw.$(document).on('click', '#btbutton', handleClick); console.log('[GrepoTweaks-AutoRuralResources] Captain-free script loaded 🚀'); })();