unlock village and fixes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Grepolis Remote Control
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 3.4
|
||||
// @version 3.5
|
||||
// @description Polls grepo.haunter-pets.top for remote commands and executes them in-game (Multi-Player)
|
||||
// @author Dimitrios
|
||||
// @match https://*.grepolis.com/game/*
|
||||
@@ -253,11 +253,15 @@
|
||||
if (farm.attributes.island_x !== ix || farm.attributes.island_y !== iy) return;
|
||||
relCollection.models.forEach(rel => {
|
||||
if (rel.attributes.farm_town_id === farm.attributes.id &&
|
||||
rel.attributes.relation_status === 1) {
|
||||
rel.attributes.relation_status >= 0) {
|
||||
farms.push({
|
||||
farm_town_id: farm.attributes.id,
|
||||
relation_id: rel.id,
|
||||
lootable_at: rel.attributes.lootable_at || 0
|
||||
farm_town_id: farm.attributes.id,
|
||||
farm_name: farm.attributes.name || '',
|
||||
relation_id: rel.id,
|
||||
relation_status: rel.attributes.relation_status,
|
||||
expansion_stage: rel.attributes.expansion_stage || 0,
|
||||
expansion_at: rel.attributes.expansion_at || 0,
|
||||
lootable_at: rel.attributes.lootable_at || 0
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -406,6 +410,97 @@
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Execute: Farm Upgrade / Unlock
|
||||
// Iterates all farm relations. Locked villages (status 0) get
|
||||
// unlocked; unlocked villages below max level get upgraded.
|
||||
// Uses random 800ms–2000ms delay between each action.
|
||||
// payload.threshold = minimum kill points to keep (default 0)
|
||||
// ----------------------------------------------------------------
|
||||
async function executeFarmUpgrade(cmd) {
|
||||
const threshold = parseInt(cmd.payload?.threshold ?? 0);
|
||||
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;
|
||||
let unlocked = 0;
|
||||
let skipped = 0;
|
||||
let 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;
|
||||
|
||||
// Skip if upgrade already in progress
|
||||
if (expAt > now) { skipped++; continue; }
|
||||
// Skip if already max level
|
||||
if (status === 1 && level >= 5) { skipped++; continue; }
|
||||
// Skip if locked and we can't unlock (status -1 means enemy)
|
||||
if (status < 0) { skipped++; continue; }
|
||||
|
||||
const isLocked = status === 0;
|
||||
const action = isLocked ? 'unlock' : 'upgrade';
|
||||
|
||||
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++; }
|
||||
|
||||
// Random delay between actions: 800ms – 2000ms
|
||||
await sleep(randInt(800, 2000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pushState(); // refresh farm data after upgrades
|
||||
return { ok: true, msg: `Farm upgrade done: ${unlocked} unlocked, ${upgraded} upgraded, ${skipped} skipped, ${errors} errors` };
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Execute: Farm Loot
|
||||
// Claims all ready farm towns across all towns that match
|
||||
@@ -653,7 +748,8 @@
|
||||
const buildCmd = cmdData.build;
|
||||
const recruitCmd = cmdData.recruit;
|
||||
const marketCmd = cmdData.market;
|
||||
const farmCmd = cmdData.farm;
|
||||
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 || {};
|
||||
@@ -687,6 +783,7 @@
|
||||
else if (cmd.type === 'recruit') result = await executeRecruit(cmd);
|
||||
else if (cmd.type === 'market_offer') result = await executeMarketOffer(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.message}` };
|
||||
@@ -699,13 +796,14 @@
|
||||
// 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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Boot
|
||||
// ----------------------------------------------------------------
|
||||
window.addEventListener('load', () => {
|
||||
log('Grepolis Remote Control v3.3 loaded');
|
||||
log('Grepolis Remote Control v3.5 loaded');
|
||||
|
||||
// Start captcha watcher immediately
|
||||
detectCaptcha();
|
||||
|
||||
@@ -99,6 +99,7 @@ def get_pending_command():
|
||||
recruit_cmd = _fetch_pending_of_type(c, 'recruit', player_id)
|
||||
market_cmd = _fetch_pending_of_type(c, 'market_offer', player_id)
|
||||
farm_cmd = _fetch_pending_of_type(c, 'farm_loot', player_id)
|
||||
farm_upgrade_cmd = _fetch_pending_of_type(c, 'farm_upgrade', player_id)
|
||||
sync_req = _check_and_reset_sync(c, player_id)
|
||||
|
||||
# Also return current farm settings so TM knows loot_option
|
||||
@@ -118,6 +119,7 @@ def get_pending_command():
|
||||
'recruit': recruit_cmd,
|
||||
'market': market_cmd,
|
||||
'farm': farm_cmd,
|
||||
'farm_upgrade': farm_upgrade_cmd,
|
||||
'farm_settings': farm_settings,
|
||||
'sync_requested': sync_req
|
||||
})
|
||||
|
||||
@@ -266,8 +266,8 @@ def create_command():
|
||||
return jsonify({'error': f'missing field: {field}'}), 400
|
||||
|
||||
cmd_type = data['type']
|
||||
if cmd_type not in ('build', 'recruit', 'market_offer', 'farm_loot'):
|
||||
return jsonify({'error': 'type must be build, recruit, market_offer, or farm_loot'}), 400
|
||||
if cmd_type not in ('build', 'recruit', 'market_offer', 'farm_loot', 'farm_upgrade'):
|
||||
return jsonify({'error': 'type must be build, recruit, market_offer, farm_loot, or farm_upgrade'}), 400
|
||||
|
||||
# Reject if the Tampermonkey client is offline (no state push in last 150 s)
|
||||
conn = get_db()
|
||||
|
||||
@@ -44,6 +44,21 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
.online-dot.live { background: #7bcc7b; box-shadow: 0 0 6px #7bcc7b; }
|
||||
.sync-btn {
|
||||
background: transparent;
|
||||
border: 1px solid #4acc64;
|
||||
color: #4acc64;
|
||||
border-radius: 6px;
|
||||
padding: 0.3rem 0.6rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
.sync-btn:hover {
|
||||
background: rgba(74, 204, 100, 0.1);
|
||||
}
|
||||
|
||||
/* ---- Control Panel ---- */
|
||||
.panel {
|
||||
@@ -147,6 +162,21 @@
|
||||
}
|
||||
.save-status.visible { opacity: 1; }
|
||||
|
||||
/* Input field */
|
||||
.input-field {
|
||||
background: #12121e;
|
||||
border: 1px solid #2a2a40;
|
||||
color: #e0e0e0;
|
||||
border-radius: 6px;
|
||||
padding: 0.6rem;
|
||||
width: 100px;
|
||||
font-family: inherit;
|
||||
font-size: 0.95rem;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.input-field:focus { border-color: #4acc64; }
|
||||
|
||||
/* ---- Farm Table ---- */
|
||||
.farm-table-wrap { overflow-x: auto; }
|
||||
table {
|
||||
@@ -206,6 +236,7 @@
|
||||
<a href="/player/{{ player_id }}">← Πίσω</a>
|
||||
<h1>🌾 Farm Manager</h1>
|
||||
<span class="online-dot" id="online-dot" title="Κατάσταση Script"></span>
|
||||
<button class="sync-btn" onclick="requestSync()">Live Sync</button>
|
||||
</div>
|
||||
|
||||
<!-- Status banner -->
|
||||
@@ -248,6 +279,23 @@
|
||||
<span class="save-status" id="save-status">✓ Αποθηκεύτηκε</span>
|
||||
</div>
|
||||
|
||||
<!-- Farm Upgrade Panel -->
|
||||
<div class="panel">
|
||||
<h2>🏰 Αυτόματη Αναβάθμιση Χωριών</h2>
|
||||
<p style="font-size: 0.85rem; color: #888; margin-bottom: 1rem;">
|
||||
Το script θα χρησιμοποιήσει αυτόματα τους πόντους μάχης σας για να ξεκλειδώσει νέα χωριά και να τα αναβαθμίσει μέχρι το επίπεδο 6.<br>
|
||||
Επιλέξτε πόσους πόντους μάχης θέλετε να κρατήσετε ως <strong>όριο ασφαλείας</strong>. Το script θα ξοδέψει μόνο τους πόντους ΠΑΝΩ από αυτό το όριο.
|
||||
</p>
|
||||
|
||||
<div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
|
||||
<label for="kp-threshold" style="font-size: 0.95rem; font-weight: 600;">Ελάχιστοι Πόντοι (Όριο):</label>
|
||||
<input type="number" id="kp-threshold" class="input-field" value="0" min="0" step="10">
|
||||
</div>
|
||||
|
||||
<button class="save-btn" id="upgrade-btn" onclick="triggerUpgrade()">🚀 Ξεκλείδωμα & Αναβάθμιση Τώρα</button>
|
||||
<span class="save-status" id="upgrade-status">Εντολή εστάλη!</span>
|
||||
</div>
|
||||
|
||||
<!-- Farm Status Table -->
|
||||
<div class="panel">
|
||||
<h2>🏘️ Κατάσταση Χωριών</h2>
|
||||
@@ -376,6 +424,37 @@
|
||||
});
|
||||
}
|
||||
|
||||
// -- Live Sync --
|
||||
function requestSync() {
|
||||
fetch(`/api/sync-request?player_id=${PLAYER_ID}`, { method: 'POST' })
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
// Will get a fast state update
|
||||
setTimeout(loadFarmData, 1500);
|
||||
});
|
||||
}
|
||||
|
||||
// -- Trigger Upgrade --
|
||||
function triggerUpgrade() {
|
||||
const threshold = document.getElementById('kp-threshold').value;
|
||||
fetch('/dashboard/commands', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
player_id: PLAYER_ID,
|
||||
town_id: 0,
|
||||
type: 'farm_upgrade',
|
||||
payload: { threshold: threshold }
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(() => {
|
||||
const s = document.getElementById('upgrade-status');
|
||||
s.classList.add('visible');
|
||||
setTimeout(() => s.classList.remove('visible'), 3000);
|
||||
});
|
||||
}
|
||||
|
||||
// -- Boot --
|
||||
loadSettings();
|
||||
loadFarmData();
|
||||
|
||||
Reference in New Issue
Block a user