diff --git a/GrepolisRemoteControl.user.js b/GrepolisRemoteControl.user.js index 8984c4e..a776c2e 100644 --- a/GrepolisRemoteControl.user.js +++ b/GrepolisRemoteControl.user.js @@ -485,6 +485,10 @@ skipped++; continue; } + if (paused) { + return { ok: false, msg: 'Aborted due to pause/captcha' }; + } + log(`Farm ${action}: farm_id=${farm.attributes.id} level=${level} town=${town_id}`); try { uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { @@ -496,8 +500,8 @@ isLocked ? unlocked++ : upgraded++; } catch (e) { errors++; } - // Random delay between actions: 800ms – 2000ms - await sleep(randInt(800, 2000)); + // Random delay between actions: 1200ms – 2500ms + await sleep(randInt(1200, 2500)); } } } @@ -626,6 +630,10 @@ log(`Farm: ${readyFarms.length} ready on island of town ${town_id}`); for (const farm of readyFarms) { + if (paused) { + return { ok: false, msg: 'Aborted due to pause/captcha' }; + } + try { uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { model_url: `FarmTownPlayerRelation/${farm.relation_id}`, @@ -636,8 +644,8 @@ claimed++; } catch (e) { errors++; } - // Random per-claim delay: 500ms – 1500ms (never below 500ms) - await sleep(randInt(500, 1500)); + // Random per-claim delay: 1000ms – 2200ms + await sleep(randInt(1000, 2200)); } // Refresh map icons after claiming (same as original) @@ -645,6 +653,7 @@ // Random between-island delay: 30s – 90s (only if more islands remain) if (i < islandList.length - 1) { + if (paused) return { ok: false, msg: 'Aborted due to pause/captcha' }; const gap = randInt(30000, 90000); log(`Farm: island done. Waiting ${(gap / 1000).toFixed(0)}s before next island...`); await sleep(gap); @@ -698,6 +707,8 @@ log(`Waiting ${reactionMs}ms before firing buildUp (reaction time)...`); await sleep(reactionMs); + if (paused) return { ok: false, msg: 'Aborted due to pause/captcha' }; + uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { model_url: 'BuildingOrder', action_name: 'buildUp', @@ -733,6 +744,8 @@ log(`Waiting ${reactionMs}ms before firing recruit (reaction time)...`); await sleep(reactionMs); + if (paused) return { ok: false, msg: 'Aborted due to pause/captcha' }; + uw.gpAjax.ajaxPost(endpoint, 'build', { unit_id, amount: parseInt(amount) || 1, @@ -759,6 +772,8 @@ log(`Waiting ${reactionMs}ms before firing market offer (reaction time)...`); await sleep(reactionMs); + if (paused) return { ok: false, msg: 'Aborted due to pause/captcha' }; + uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { model_url: 'CreateOffers/' + town_id, action_name: 'createOffer', @@ -796,23 +811,7 @@ const farmCmd = cmdData.farm; const farmUpgradeCmd = cmdData.farm_upgrade; - // Auto-farm: if enabled, claim all ready farms (no explicit command needed) - const farmSettings = cmdData.farm_settings || {}; - if (farmSettings.enabled && !farmCmd) { - const nowTs = Math.floor(Date.now() / 1000); - // Check if any town has ready farms before triggering - const hasFarms = Object.values(uw.ITowns?.towns || {}).some(t => { - try { - const coll = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation'); - return coll?.models?.some(r => r.attributes.relation_status === 1 && (r.attributes.lootable_at || 0) <= nowTs); - } catch (e) { return false; } - }); - if (hasFarms) { - log('⚡ Auto-farm: ready farms detected, triggering loot...'); - await executeFarmLoot({ payload: { loot_option: farmSettings.loot_option } }); - pushState(); - } - } + if (cmdData.sync_requested) { log('Sync requested by server — pushing state immediately'); @@ -838,10 +837,30 @@ reportResult(cmd.id, finalStatus, result.msg); }; - // Run concurrently — they do NOT block each other - await Promise.all([execute(buildCmd), execute(recruitCmd), execute(marketCmd)]); - if (farmCmd) await execute(farmCmd); - if (farmUpgradeCmd) await execute(farmUpgradeCmd); + // Run sequentially — humans cannot perform 3 actions simultaneously! + await execute(buildCmd); + await execute(recruitCmd); + await execute(marketCmd); + await execute(farmCmd); + await execute(farmUpgradeCmd); + + // Auto-farm: if enabled, claim all ready farms (no explicit command needed) + const farmSettings = cmdData.farm_settings || {}; + if (farmSettings.enabled && !farmCmd) { + const nowTs = Math.floor(Date.now() / 1000); + // Check if ANY farm relation is ready (no need to iterate per-town) + const hasFarms = (() => { + try { + const coll = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation'); + return coll?.models?.some(r => r.attributes.relation_status === 1 && (r.attributes.lootable_at || 0) <= nowTs); + } catch (e) { return false; } + })(); + if (hasFarms) { + log('⚡ Auto-farm: ready farms detected, triggering loot...'); + await executeFarmLoot({ payload: { loot_option: farmSettings.loot_option } }); + pushState(); + } + } } // ---------------------------------------------------------------- diff --git a/templates/farm.html b/templates/farm.html index a0e542d..5abb4f6 100644 --- a/templates/farm.html +++ b/templates/farm.html @@ -275,8 +275,11 @@ - - ✓ Αποθηκεύτηκε +
+ + + ✓ Στάλθηκε +
@@ -475,6 +478,33 @@ }); } + // -- Trigger Manual Loot -- + function triggerManualLoot() { + const btn = document.getElementById('manual-loot-btn'); + const originalText = btn.innerText; + btn.innerText = '⏳ Αποστολή...'; + btn.disabled = true; + + fetch('/dashboard/commands', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + player_id: PLAYER_ID, + town_id: 0, + type: 'farm_loot', + payload: { loot_option: selectedOption } + }) + }) + .then(r => r.json()) + .then(() => { + btn.innerText = '✓ Εστάλη!'; + setTimeout(() => { + btn.innerText = originalText; + btn.disabled = false; + }, 2000); + }); + } + // -- Boot -- loadSettings(); loadFarmData();