greekbuilding names ,live synch button ,market capacity

This commit is contained in:
2026-04-22 20:48:34 +03:00
parent ec2b0c631e
commit c1cc8ceb7a
7 changed files with 92 additions and 5 deletions

View File

@@ -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}`);

View File

@@ -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

View File

@@ -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', {}),

View File

@@ -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);
}
};

View File

@@ -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}`;
}; };

View File

@@ -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}` : '—';

View File

@@ -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;">