Files
grepo-remote/bot_modules/05_main.js
2026-04-26 12:53:14 +03:00

138 lines
5.4 KiB
JavaScript

// ================================================================
// 05_main.js — Poll loop, command dispatch, boot
// Depends on: everything above
// ================================================================
async function pollAndExecute() {
if (paused) return;
const player_id = uw.Game?.player_id;
if (!player_id) return;
let cmdData;
try {
const res = await fetch(`${BASE_URL}/api/commands/pending?player_id=${player_id}`);
cmdData = await res.json();
} catch (e) {
log(`Poll failed: ${e}`);
return;
}
const buildCmd = cmdData.build;
const recruitCmd = cmdData.recruit;
const marketCmd = cmdData.market;
const researchCmd = cmdData.research;
const farmCmd = cmdData.farm;
const farmUpgradeCmd = cmdData.farm_upgrade;
if (cmdData.sync_requested) {
log('Sync requested by server — pushing state immediately');
pushState();
}
const execute = async (cmd) => {
if (!cmd) return;
log(`Executing command #${cmd.id} — type:${cmd.type} town:${cmd.town_id}`);
if (paused) {
log(`[Paused] Ignoring command #${cmd.id}`);
return;
}
let result;
try {
if (cmd.type === 'build') result = await executeBuild(cmd);
else if (cmd.type === 'recruit') result = await executeRecruit(cmd);
else if (cmd.type === 'market_offer') result = await executeMarketOffer(cmd);
else if (cmd.type === 'research') result = await executeResearch(cmd);
else if (cmd.type === 'farm_loot') result = await executeFarmLoot(cmd);
else if (cmd.type === 'farm_upgrade') result = await executeFarmUpgrade(cmd);
else result = { ok: false, msg: `Unknown type: ${cmd.type}` };
} catch (e) {
result = { ok: false, msg: `Exception: ${e}` };
}
const finalStatus = result.requeue ? 'pending' : (result.ok ? 'done' : 'failed');
log(`Command #${cmd.id}: ${finalStatus === 'done' ? '✅' : finalStatus === 'pending' ? '⏳' : '❌'} ${result.msg}`);
reportResult(cmd.id, finalStatus, result.msg);
};
// Run sequentially — humans cannot perform 3 actions simultaneously!
await execute(buildCmd);
await execute(recruitCmd);
await execute(marketCmd);
await execute(researchCmd);
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);
let readyFarms = [];
try {
const coll = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation');
readyFarms = coll?.models?.filter(r =>
r.attributes.relation_status === 1 &&
(r.attributes.lootable_at || 0) <= nowTs
) || [];
} catch (e) { /* silent */ }
if (readyFarms.length > 0) {
let allFull = true;
let claimedAny = false;
const towns = Object.values(uw.ITowns?.towns || {});
for (const town of towns) {
const storage = town.resources?.()?.storage || town.get?.('storage') || 0;
const wood = town.resources?.()?.wood || town.get?.('wood') || 0;
const stone = town.resources?.()?.stone || town.get?.('stone') || 0;
const iron = town.resources?.()?.iron || town.get?.('iron') || 0;
if (!storage) continue;
const maxRes = Math.max(wood, stone, iron);
const pct = maxRes / storage;
if (pct < 0.95) {
allFull = false;
log(`⚡ Auto-farm: looting into town ${town.get?.('name')} (${Math.round(pct * 100)}% full)`);
await executeFarmLoot({ payload: { loot_option: farmSettings.loot_option } });
claimedAny = true;
pushState();
break;
}
}
if (allFull) {
log('⚠️ Auto-farm: ALL warehouses are full (>95%) — skipping loot this cycle');
try {
await fetch(`${BASE_URL}/api/farm_status?player_id=${uw.Game.player_id}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ warehouse_full: true })
});
} catch (e) {}
} else if (claimedAny) {
try {
await fetch(`${BASE_URL}/api/farm_status?player_id=${uw.Game.player_id}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ warehouse_full: false })
});
} catch (e) {}
}
}
}
}
// ----------------------------------------------------------------
// Boot
// ----------------------------------------------------------------
window.addEventListener('load', () => {
log('Grepolis Remote Control v4.0.0 (remote) loaded');
detectCaptcha();
setTimeout(pushState, 5000);
jitterLoop(pushState, 60000, 120000);
jitterLoop(pollAndExecute, 8000, 18000);
});