216 lines
8.4 KiB
JavaScript
216 lines
8.4 KiB
JavaScript
// ================================================================
|
|
// 04a_execute_farm.js — Farm command executors
|
|
// Depends on: uw, log, sleep, randInt, paused, pushState
|
|
// ================================================================
|
|
|
|
// ----------------------------------------------------------------
|
|
// Execute: Farm Upgrade / Unlock
|
|
// ----------------------------------------------------------------
|
|
async function executeFarmUpgrade(cmd) {
|
|
const now = Math.floor(Date.now() / 1000);
|
|
|
|
let farmModels, relModels;
|
|
try {
|
|
farmModels = uw.MM.getOnlyCollectionByName('FarmTown')?.models;
|
|
relModels = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation')?.models;
|
|
} catch (e) {
|
|
return { ok: false, msg: `Cannot access farm collections: ${e.message}` };
|
|
}
|
|
if (!farmModels || !relModels) {
|
|
return { ok: false, msg: 'Farm collections not loaded yet' };
|
|
}
|
|
|
|
// Build polis list (one town per island)
|
|
const islandsSeen = new Set();
|
|
const polisList = [];
|
|
try {
|
|
for (const town of uw.MM.getCollections().Town[0].models) {
|
|
const { on_small_island, island_id, id } = town.attributes;
|
|
if (on_small_island) continue;
|
|
if (!islandsSeen.has(island_id)) {
|
|
islandsSeen.add(island_id);
|
|
polisList.push(id);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
return { ok: false, msg: `Cannot build town list: ${e.message}` };
|
|
}
|
|
|
|
let upgraded = 0, unlocked = 0, skipped = 0, errors = 0;
|
|
|
|
for (const town_id of polisList) {
|
|
const town = uw.ITowns?.towns?.[town_id];
|
|
if (!town) continue;
|
|
const ix = town.getIslandCoordinateX();
|
|
const iy = town.getIslandCoordinateY();
|
|
if (ix == null || iy == null) continue;
|
|
|
|
for (const farm of farmModels) {
|
|
if (farm.attributes.island_x !== ix || farm.attributes.island_y !== iy) continue;
|
|
|
|
for (const rel of relModels) {
|
|
if (rel.attributes.farm_town_id !== farm.attributes.id) continue;
|
|
|
|
const status = rel.attributes.relation_status;
|
|
const level = rel.attributes.expansion_stage || 0;
|
|
const expAt = rel.attributes.expansion_at || 0;
|
|
|
|
if (expAt > now) { skipped++; continue; }
|
|
if (status === 1 && level >= 5) { skipped++; continue; }
|
|
if (status < 0) { skipped++; continue; }
|
|
|
|
const isLocked = status === 0;
|
|
const action = isLocked ? 'unlock' : 'upgrade';
|
|
|
|
const requestedAction = cmd.payload?.action_type;
|
|
if (requestedAction && requestedAction !== action) { 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', {
|
|
model_url: `FarmTownPlayerRelation/${rel.id}`,
|
|
action_name: action,
|
|
arguments: { farm_town_id: farm.attributes.id },
|
|
town_id
|
|
});
|
|
isLocked ? unlocked++ : upgraded++;
|
|
} catch (e) { errors++; }
|
|
|
|
await sleep(randInt(4000, 10000));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
pushState();
|
|
return { ok: true, msg: `Farm upgrade done: ${unlocked} unlocked, ${upgraded} upgraded, ${skipped} skipped, ${errors} errors` };
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Execute: Farm Loot
|
|
// ----------------------------------------------------------------
|
|
async function executeFarmLoot(cmd) {
|
|
const { loot_option } = cmd.payload || {};
|
|
const option = parseInt(loot_option) || 1;
|
|
const now = Math.floor(Date.now() / 1000);
|
|
|
|
let farmModels, relModels;
|
|
try {
|
|
farmModels = uw.MM.getOnlyCollectionByName('FarmTown')?.models;
|
|
relModels = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation')?.models;
|
|
} catch (e) {
|
|
return { ok: false, msg: `Cannot access farm collections: ${e.message}` };
|
|
}
|
|
if (!farmModels || !relModels) {
|
|
return { ok: false, msg: 'Farm collections not loaded yet — open island view first' };
|
|
}
|
|
|
|
// Build island groups using MM (all towns, not just visible)
|
|
const islandTownsMap = {};
|
|
try {
|
|
const allTowns = uw.MM.getCollections().Town[0].models;
|
|
for (const town of allTowns) {
|
|
const { on_small_island, island_id, id } = town.attributes;
|
|
if (on_small_island) continue;
|
|
if (!islandTownsMap[island_id]) islandTownsMap[island_id] = [];
|
|
islandTownsMap[island_id].push(id);
|
|
}
|
|
} catch (e) {
|
|
return { ok: false, msg: `Cannot build town list: ${e.message}` };
|
|
}
|
|
|
|
const islandList = Object.keys(islandTownsMap);
|
|
log(`Farm: processing ${islandList.length} islands with option=${option}`);
|
|
|
|
let claimed = 0, skipped = 0, errors = 0;
|
|
|
|
for (let i = 0; i < islandList.length; i++) {
|
|
const island_id = islandList[i];
|
|
const townIds = islandTownsMap[island_id];
|
|
|
|
let selected_town_id = null;
|
|
let lowest_total_res = Infinity;
|
|
|
|
for (const t_id of townIds) {
|
|
const t = uw.ITowns?.towns?.[t_id];
|
|
if (!t) continue;
|
|
|
|
let storageCapacity = t.getStorageCapacity?.() || 0;
|
|
if (!storageCapacity) {
|
|
const buildings = t.buildings?.()?.attributes || {};
|
|
const storageLevel = buildings.storage ?? 0;
|
|
const gd = uw.GameData?.buildingData?.storage;
|
|
storageCapacity = gd?.max_storage?.[storageLevel] || gd?.storage?.[storageLevel] || 0;
|
|
}
|
|
|
|
const res = t.resources?.() || {};
|
|
const w = res.wood || 0, s = res.stone || 0, ir = res.iron || 0;
|
|
|
|
// Skip completely full towns
|
|
if (storageCapacity > 0 && w >= storageCapacity && s >= storageCapacity && ir >= storageCapacity) continue;
|
|
|
|
const total_res = w + s + ir;
|
|
if (total_res < lowest_total_res) {
|
|
lowest_total_res = total_res;
|
|
selected_town_id = t_id;
|
|
}
|
|
}
|
|
|
|
if (!selected_town_id) {
|
|
log(`Farm: Skipping island ${island_id} (All towns are 100% full)`);
|
|
skipped++;
|
|
continue;
|
|
}
|
|
|
|
const town_id = selected_town_id;
|
|
const town = uw.ITowns?.towns?.[town_id];
|
|
if (!town) { skipped++; continue; }
|
|
|
|
const ix = town.getIslandCoordinateX();
|
|
const iy = town.getIslandCoordinateY();
|
|
if (ix == null || iy == null) { skipped++; continue; }
|
|
|
|
const readyFarms = [];
|
|
for (const farm of farmModels) {
|
|
if (farm.attributes.island_x !== ix || farm.attributes.island_y !== iy) continue;
|
|
for (const rel of relModels) {
|
|
if (
|
|
rel.attributes.farm_town_id === farm.attributes.id &&
|
|
rel.attributes.relation_status === 1 &&
|
|
(!rel.attributes.lootable_at || now >= rel.attributes.lootable_at)
|
|
) {
|
|
readyFarms.push({
|
|
town_id,
|
|
farm_town_id: rel.attributes.farm_town_id,
|
|
relation_id: rel.id
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (readyFarms.length === 0) { skipped++; continue; }
|
|
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}`,
|
|
action_name: 'claim',
|
|
arguments: { farm_town_id: farm.farm_town_id, type: 'resources', option },
|
|
town_id: farm.town_id
|
|
});
|
|
claimed++;
|
|
} catch (e) { errors++; }
|
|
|
|
await sleep(randInt(500, 1500));
|
|
}
|
|
|
|
try { uw.WMap.removeFarmTownLootCooldownIconAndRefreshLootTimers(); } catch (e) {}
|
|
}
|
|
|
|
return { ok: true, msg: `Farm done: ${claimed} claimed, ${skipped} islands skipped, ${errors} errors` };
|
|
}
|