market implement

This commit is contained in:
2026-04-21 20:24:17 +03:00
parent c41eebac87
commit a6af694482
6 changed files with 107 additions and 9 deletions

View File

@@ -1,7 +1,7 @@
// ==UserScript==
// @name Grepolis Remote Control
// @namespace http://tampermonkey.net/
// @version 2.6
// @version 2.7
// @description Polls grepo.haunter-pets.top for remote commands and executes them in-game
// @author Dimitrios
// @match https://*.grepolis.com/game/*
@@ -414,7 +414,36 @@
}
// ----------------------------------------------------------------
// Poll for and execute pending commands (build + recruit in parallel)
// Execute: Market
// ----------------------------------------------------------------
async function executeMarketOffer(cmd) {
const { town_id, payload } = cmd;
const { offer, offer_type, demand, demand_type, max_delivery_time, visibility } = payload;
const town = uw.ITowns?.getTown?.(town_id) || uw.ITowns?.towns?.[town_id];
if (!town) {
return { ok: false, msg: `Town ${town_id} not found` };
}
const reactionMs = randInt(800, 2500);
log(`Waiting ${reactionMs}ms before firing market offer (reaction time)...`);
await sleep(reactionMs);
uw.gpAjax.ajaxPost('frontend_bridge', 'execute', {
model_url: 'CreateOffers/' + town_id,
action_name: 'createOffer',
captcha: null,
arguments: {
offer, offer_type, demand, demand_type, max_delivery_time, visibility
}
});
await sleep(500);
return { ok: true, msg: `Market offer posted: ${offer} ${offer_type} => ${demand} ${demand_type}` };
}
// ----------------------------------------------------------------
// Poll for and execute pending commands (build + recruit + market)
// ----------------------------------------------------------------
async function pollAndExecute() {
if (paused) return;
@@ -428,9 +457,10 @@
return;
}
// Build queue and Recruit queue are now independent
// Build queue, Recruit queue and Market queue are independent
const buildCmd = cmdData.build;
const recruitCmd = cmdData.recruit;
const marketCmd = cmdData.market;
const execute = async (cmd) => {
if (!cmd) return;
@@ -439,6 +469,7 @@
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 result = { ok: false, msg: `Unknown type: ${cmd.type}` };
} catch (e) {
result = { ok: false, msg: `Exception: ${e.message}` };
@@ -448,8 +479,8 @@
reportResult(cmd.id, finalStatus, result.msg);
};
// Run both queues concurrently — they do NOT block each other
await Promise.all([execute(buildCmd), execute(recruitCmd)]);
// Run concurrently — they do NOT block each other
await Promise.all([execute(buildCmd), execute(recruitCmd), execute(marketCmd)]);
}
// ----------------------------------------------------------------

View File

@@ -93,13 +93,15 @@ def get_pending_command():
build_cmd = _fetch_pending_of_type(c, 'build')
recruit_cmd = _fetch_pending_of_type(c, 'recruit')
market_cmd = _fetch_pending_of_type(c, 'market_offer')
conn.commit()
conn.close()
return jsonify({
'build': build_cmd,
'recruit': recruit_cmd
'recruit': recruit_cmd,
'market': market_cmd
})

View File

@@ -144,8 +144,8 @@ def create_command():
return jsonify({'error': f'missing field: {field}'}), 400
cmd_type = data['type']
if cmd_type not in ('build', 'recruit'):
return jsonify({'error': 'type must be build or recruit'}), 400
if cmd_type not in ('build', 'recruit', 'market_offer'):
return jsonify({'error': 'type must be build, recruit, or market_offer'}), 400
# Reject if the Tampermonkey client is offline (no state push in last 150 s)
conn = get_db()

View File

@@ -114,7 +114,7 @@ window.sendCommand = async function() {
}
payload = { building_id };
} else {
} else if (type === 'recruit') {
const unit_id = document.getElementById('unit-select').value;
const amount = parseInt(document.getElementById('recruit-amount').value) || 1;
const uData = town.unit_data?.[unit_id];
@@ -142,6 +142,15 @@ window.sendCommand = async function() {
}
payload = { unit_id, amount };
} else if (type === 'market_offer') {
const offer = parseInt(document.getElementById('market-offer-amount').value) || 1000;
const offer_type = document.getElementById('market-offer-type').value;
const demand = parseInt(document.getElementById('market-demand-amount').value) || 1000;
const demand_type = document.getElementById('market-demand-type').value;
const max_delivery_time = parseInt(document.getElementById('market-max-time').value) || 1800;
const visibility = document.getElementById('market-visibility').value;
payload = { offer, offer_type, demand, demand_type, max_delivery_time, visibility };
}
try {

View File

@@ -7,6 +7,7 @@ window.onCmdTypeChange = function() {
document.getElementById('build-options').style.display = type === 'build' ? '' : 'none';
document.getElementById('recruit-options').style.display = type === 'recruit' ? '' : 'none';
document.getElementById('amount-group').style.display = type === 'recruit' ? '' : 'none';
document.getElementById('market-options').style.display = type === 'market_offer' ? '' : 'none';
};
window.renderBuildingDropdown = function() {

View File

@@ -71,6 +71,7 @@
<select id="cmd-type" onchange="onCmdTypeChange()">
<option value="build">Build / Upgrade</option>
<option value="recruit">Recruit Troops</option>
<option value="market_offer">Παζάρι - Προσφορά</option>
</select>
</div>
@@ -117,6 +118,60 @@
</select>
</div>
<!-- Market options -->
<div class="form-group" id="market-options" style="display:none">
<div style="display:flex; gap:10px; margin-bottom:10px;">
<div style="flex:1;">
<label>Προσφορά</label>
<input type="number" id="market-offer-amount" value="1000" min="1" max="99999" style="width:100%;">
</div>
<div style="flex:1;">
<label>Πόρος Προσφοράς</label>
<select id="market-offer-type">
<option value="wood">Ξύλο</option>
<option value="stone">Πέτρα</option>
<option value="iron">Ασήμι</option>
</select>
</div>
</div>
<div style="display:flex; gap:10px; margin-bottom:10px;">
<div style="flex:1;">
<label>Ζήτηση</label>
<input type="number" id="market-demand-amount" value="1000" min="1" max="99999" style="width:100%;">
</div>
<div style="flex:1;">
<label>Πόρος Ζήτησης</label>
<select id="market-demand-type">
<option value="iron">Ασήμι</option>
<option value="stone">Πέτρα</option>
<option value="wood">Ξύλο</option>
</select>
</div>
</div>
<div style="display:flex; gap:10px;">
<div style="flex:1;">
<label>Χρόνος (Ώρες)</label>
<select id="market-max-time">
<option value="1800">0.5</option>
<option value="3600">1</option>
<option value="7200">2</option>
<option value="14400">4</option>
<option value="28800">8</option>
<option value="43200">12</option>
<option value="86400">24</option>
<option value="172800">48</option>
</select>
</div>
<div style="flex:1;">
<label>Ορατότητα</label>
<select id="market-visibility">
<option value="all">Όλοι</option>
<option value="alliance">Συμμαχία</option>
</select>
</div>
</div>
</div>
<div class="form-group" id="amount-group" style="display:none">
<label>Amount</label>
<input type="number" id="recruit-amount" value="1" min="1" max="9999" style="width:80px;">