greekbuilding names ,live synch button ,market capacity
This commit is contained in:
@@ -157,6 +157,21 @@
|
|||||||
log(`storage capacity lookup failed: ${e}`);
|
log(`storage capacity lookup failed: ${e}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Market / Trade capacity -----------------------------------------
|
||||||
|
let marketCapacity = 0;
|
||||||
|
try {
|
||||||
|
const marketLevel = buildings.market ?? 0;
|
||||||
|
const gd = uw.GameData?.buildingData?.market;
|
||||||
|
marketCapacity = gd?.capacity_per_level?.[marketLevel] || 0;
|
||||||
|
|
||||||
|
// Add Trade Office bonus if present
|
||||||
|
if (buildings.trade_office && buildings.trade_office > 0) {
|
||||||
|
marketCapacity += (uw.GameData?.buildingData?.trade_office?.capacity_extra_per_level || 500) * marketLevel;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log(`market capacity lookup failed: ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Coordinates & sea zone -----------------------------------------
|
// ---- Coordinates & sea zone -----------------------------------------
|
||||||
let x = null, y = null, sea = null;
|
let x = null, y = null, sea = null;
|
||||||
try {
|
try {
|
||||||
@@ -234,6 +249,7 @@
|
|||||||
stone: res.stone,
|
stone: res.stone,
|
||||||
iron: res.iron,
|
iron: res.iron,
|
||||||
storage: storageCapacity,
|
storage: storageCapacity,
|
||||||
|
market_capacity: marketCapacity,
|
||||||
population: res.population,
|
population: res.population,
|
||||||
points: town.getPoints?.() ?? 0,
|
points: town.getPoints?.() ?? 0,
|
||||||
god: town.god?.() ?? null,
|
god: town.god?.() ?? null,
|
||||||
@@ -466,6 +482,11 @@
|
|||||||
const recruitCmd = cmdData.recruit;
|
const recruitCmd = cmdData.recruit;
|
||||||
const marketCmd = cmdData.market;
|
const marketCmd = cmdData.market;
|
||||||
|
|
||||||
|
if (cmdData.sync_requested) {
|
||||||
|
log('Sync requested by server — pushing state immediately');
|
||||||
|
pushState();
|
||||||
|
}
|
||||||
|
|
||||||
const execute = async (cmd) => {
|
const execute = async (cmd) => {
|
||||||
if (!cmd) return;
|
if (!cmd) return;
|
||||||
log(`Executing command #${cmd.id} — type:${cmd.type} town:${cmd.town_id}`);
|
log(`Executing command #${cmd.id} — type:${cmd.type} town:${cmd.town_id}`);
|
||||||
|
|||||||
@@ -105,9 +105,38 @@ def get_pending_command():
|
|||||||
return jsonify({
|
return jsonify({
|
||||||
'build': build_cmd,
|
'build': build_cmd,
|
||||||
'recruit': recruit_cmd,
|
'recruit': recruit_cmd,
|
||||||
'market': market_cmd
|
'market': market_cmd,
|
||||||
|
'sync_requested': _check_and_reset_sync(c, player_id)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def _check_and_reset_sync(c, player_id):
|
||||||
|
key = f'sync_request_{player_id}'
|
||||||
|
row = c.execute("SELECT value FROM kv_store WHERE key = ?", (key,)).fetchone()
|
||||||
|
if row and row['value'] == '1':
|
||||||
|
c.execute("UPDATE kv_store SET value = '0', updated_at = ? WHERE key = ?", (datetime.utcnow().isoformat(), key))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# POST /api/sync-request
|
||||||
|
# Dashboard requests an immediate state update from the client.
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@api.route('/api/sync-request', methods=['POST'])
|
||||||
|
def sync_request():
|
||||||
|
player_id = request.args.get('player_id')
|
||||||
|
if not player_id:
|
||||||
|
return jsonify({'error': 'no player_id provided'}), 400
|
||||||
|
|
||||||
|
conn = get_db()
|
||||||
|
conn.execute('''
|
||||||
|
INSERT INTO kv_store (key, value, updated_at)
|
||||||
|
VALUES (?, '1', ?)
|
||||||
|
ON CONFLICT(key) DO UPDATE SET value = '1', updated_at = excluded.updated_at
|
||||||
|
''', (f'sync_request_{player_id}', datetime.utcnow().isoformat()))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return jsonify({'ok': True})
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# POST /api/commands/<id>/result
|
# POST /api/commands/<id>/result
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ def get_towns():
|
|||||||
'stone': d.get('stone', 0),
|
'stone': d.get('stone', 0),
|
||||||
'iron': d.get('iron', 0),
|
'iron': d.get('iron', 0),
|
||||||
'storage': d.get('storage', 0),
|
'storage': d.get('storage', 0),
|
||||||
|
'market_capacity': d.get('market_capacity', 0),
|
||||||
'population': d.get('population', 0),
|
'population': d.get('population', 0),
|
||||||
},
|
},
|
||||||
'buildings': d.get('buildings', {}),
|
'buildings': d.get('buildings', {}),
|
||||||
|
|||||||
@@ -223,3 +223,28 @@ window.dismissCaptchaBanner = function() {
|
|||||||
banner.dataset.dismissed = '1';
|
banner.dataset.dismissed = '1';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.requestLiveSync = async function() {
|
||||||
|
const btn = document.getElementById('live-btn');
|
||||||
|
const originalText = btn.textContent;
|
||||||
|
btn.textContent = '⏳ Requesting...';
|
||||||
|
btn.disabled = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/sync-request?player_id=' + window.PLAYER_ID, { method: 'POST' });
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.ok) {
|
||||||
|
btn.textContent = '✅ Requested!';
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.textContent = originalText;
|
||||||
|
btn.disabled = false;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
btn.textContent = '❌ Failed';
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.textContent = originalText;
|
||||||
|
btn.disabled = false;
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -144,8 +144,10 @@ window.renderBuildQueuePreview = function() {
|
|||||||
el.innerHTML = '<span style="color:#444">Build queue: empty</span>';
|
el.innerHTML = '<span style="color:#444">Build queue: empty</span>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const items = town.build_queue.map(o =>
|
const items = town.build_queue.map(o => {
|
||||||
`<span>${o.building_type || o.name || JSON.stringify(o)}</span>`
|
const raw = o.building_type || o.name || "";
|
||||||
).join('');
|
const nameGr = window.BUILDING_NAMES_GR[raw] || raw || JSON.stringify(o);
|
||||||
|
return `<span style="background: rgba(0,0,0,0.3); padding: 2px 6px; border-radius: 4px; margin-right: 4px; font-size: 0.8rem;">${nameGr}</span>`;
|
||||||
|
}).join('');
|
||||||
el.innerHTML = `<div style="margin-top:6px;color:#888;font-size:0.72rem;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:4px;">Current queue</div>${items}`;
|
el.innerHTML = `<div style="margin-top:6px;color:#888;font-size:0.72rem;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:4px;">Current queue</div>${items}`;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -160,6 +160,11 @@ window.renderTownDetails = function() {
|
|||||||
<div>${window.RES_ICONS.iron} Ασήμι: ${resHtml(resObj.iron || 0, reservedIron)}</div>
|
<div>${window.RES_ICONS.iron} Ασήμι: ${resHtml(resObj.iron || 0, reservedIron)}</div>
|
||||||
<div style="margin-top: 6px;">${window.RES_ICONS.pop} Πληθυσμός: <strong style="color:#fff">${resObj.population || 0}</strong></div>
|
<div style="margin-top: 6px;">${window.RES_ICONS.pop} Πληθυσμός: <strong style="color:#fff">${resObj.population || 0}</strong></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const mCap = resObj.market_capacity || 0;
|
||||||
|
document.getElementById('td-market').innerHTML = `
|
||||||
|
📦 Εμπορική Χωρητικότητα: <strong>${window.fmt(mCap)}</strong>
|
||||||
|
`;
|
||||||
|
|
||||||
const godName = t.god ? t.god.charAt(0).toUpperCase() + t.god.slice(1) : 'Κανένας';
|
const godName = t.god ? t.god.charAt(0).toUpperCase() + t.god.slice(1) : 'Κανένας';
|
||||||
const seaStr = t.sea != null ? `Θ${t.sea}` : '—';
|
const seaStr = t.sea != null ? `Θ${t.sea}` : '—';
|
||||||
|
|||||||
@@ -27,7 +27,10 @@
|
|||||||
|
|
||||||
<!-- Left: Town list -->
|
<!-- Left: Town list -->
|
||||||
<div id="town-panel">
|
<div id="town-panel">
|
||||||
<h2>Towns</h2>
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h2 style="margin: 0;">Towns</h2>
|
||||||
|
<button class="btn btn-gold btn-sm" id="live-btn" onclick="window.requestLiveSync()" title="Request immediate data update from game" style="padding: 4px 8px; font-size: 0.72rem;">⚡ Live Sync</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="town-filters" style="margin-bottom: 15px; padding: 10px; background: #0f3460; border-radius: 6px; border: 1px solid #2a4a6a;">
|
<div id="town-filters" style="margin-bottom: 15px; padding: 10px; background: #0f3460; border-radius: 6px; border: 1px solid #2a4a6a;">
|
||||||
<input type="text" id="town-search" placeholder="Αναζήτηση Πόλης..." style="width: 100%; box-sizing: border-box; margin-bottom: 10px; padding: 6px; border-radius: 4px; border: 1px solid #3a5a7a; background: #1a1a24; color: white;" onkeyup="window.renderTowns()">
|
<input type="text" id="town-search" placeholder="Αναζήτηση Πόλης..." style="width: 100%; box-sizing: border-box; margin-bottom: 10px; padding: 6px; border-radius: 4px; border: 1px solid #3a5a7a; background: #1a1a24; color: white;" onkeyup="window.renderTowns()">
|
||||||
@@ -63,6 +66,7 @@
|
|||||||
<div style="flex: 1; min-width: 130px;">
|
<div style="flex: 1; min-width: 130px;">
|
||||||
<strong style="font-size: 0.75rem; color: #888; text-transform: uppercase;">Ποροι</strong>
|
<strong style="font-size: 0.75rem; color: #888; text-transform: uppercase;">Ποροι</strong>
|
||||||
<div id="td-resources" style="font-size: 0.85rem; margin-top: 4px; line-height: 1.5;"></div>
|
<div id="td-resources" style="font-size: 0.85rem; margin-top: 4px; line-height: 1.5;"></div>
|
||||||
|
<div id="td-market" style="font-size: 0.75rem; color: #6fcfcf; margin-top: 6px; border-top: 1px solid #2a4a6a; padding-top: 4px;"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="flex: 1; min-width: 130px;">
|
<div style="flex: 1; min-width: 130px;">
|
||||||
|
|||||||
Reference in New Issue
Block a user