276 lines
9.7 KiB
JavaScript
276 lines
9.7 KiB
JavaScript
// ================================================================
|
||
// API & Networking
|
||
// ================================================================
|
||
|
||
window.fetchTowns = async function() {
|
||
try {
|
||
const res = await fetch('/dashboard/towns?player_id=' + window.PLAYER_ID);
|
||
window.towns = await res.json();
|
||
window.renderTowns();
|
||
window.updateServerStatus(true);
|
||
|
||
// Automatically select the first town if none is selected
|
||
if (!window.selectedTownId && window.towns && window.towns.length > 0) {
|
||
window.selectTown(window.towns[0].town_id);
|
||
}
|
||
|
||
if (window.selectedTownId) {
|
||
window.renderBuildQueuePreview();
|
||
window.renderBuildingDropdown();
|
||
window.renderUnitDropdown();
|
||
window.renderTownDetails();
|
||
// Refresh the build queue panel if in queue mode
|
||
if (window._logPanelMode === 'queue') {
|
||
window.fetchBuildQueue(window.selectedTownId);
|
||
}
|
||
}
|
||
} catch (e) {
|
||
window.updateServerStatus(false);
|
||
}
|
||
};
|
||
|
||
window.fetchClientStatus = async function() {
|
||
try {
|
||
const res = await fetch('/dashboard/client-status?player_id=' + window.PLAYER_ID);
|
||
const data = await res.json();
|
||
const isOnline = data.online === true;
|
||
|
||
// Detect transition: online → offline
|
||
if (window.wasClientOnline === true && !isOnline) {
|
||
// Fail all queued commands immediately
|
||
await fetch('/dashboard/commands/fail-stale?player_id=' + window.PLAYER_ID, { method: 'POST' });
|
||
window.fetchLog();
|
||
}
|
||
|
||
window.clientOnline = isOnline;
|
||
window.wasClientOnline = isOnline;
|
||
window.updateClientStatus(isOnline);
|
||
} catch (e) {
|
||
window.updateClientStatus(false);
|
||
}
|
||
};
|
||
|
||
window.fetchLog = async function() {
|
||
try {
|
||
const res = await fetch('/dashboard/commands?player_id=' + window.PLAYER_ID);
|
||
const cmds = await res.json();
|
||
window.cmds = cmds; // Save globally so viewer can see reserved resources
|
||
if (window._logPanelMode === 'log') {
|
||
window.renderLog(cmds);
|
||
}
|
||
if (window.selectedTownId) window.renderTownDetails();
|
||
} catch (e) {}
|
||
};
|
||
|
||
window.updateServerStatus = function(online) {
|
||
const el = document.getElementById('server-status');
|
||
if (online) {
|
||
el.textContent = '● Server';
|
||
el.className = 'conn-badge online';
|
||
} else {
|
||
el.textContent = '● Server offline';
|
||
el.className = 'conn-badge offline';
|
||
}
|
||
};
|
||
|
||
window.updateClientStatus = function(online) {
|
||
const el = document.getElementById('client-status');
|
||
if (online) {
|
||
el.textContent = '● Script';
|
||
el.className = 'conn-badge online';
|
||
} else {
|
||
el.textContent = '● Script offline';
|
||
el.className = 'conn-badge offline';
|
||
}
|
||
// Enable/disable the Send button
|
||
const btn = document.getElementById('btn-send');
|
||
if (btn) {
|
||
btn.disabled = !online;
|
||
btn.title = online ? '' : 'Script is offline — cannot send commands';
|
||
btn.style.opacity = online ? '' : '0.4';
|
||
btn.style.cursor = online ? '' : 'not-allowed';
|
||
}
|
||
};
|
||
|
||
window.sendCommand = async function() {
|
||
if (!window.clientOnline) return alert('Το script είναι offline — δεν μπορείτε να στείλετε εντολές.');
|
||
const town = window.getSelectedTown();
|
||
if (!town) return alert('Select a town first.');
|
||
|
||
const type = document.getElementById('cmd-type').value;
|
||
if (!type) return alert('Παρακαλώ επιλέξτε Ενέργεια (Command Type) πρώτα.');
|
||
|
||
let payload = {};
|
||
|
||
if (type === 'build') {
|
||
const building_id = window.selectedBuildingId;
|
||
if (!building_id) return alert('Παρακαλώ επιλέξτε Κατασκευή από τον πίνακα.');
|
||
|
||
const bData = town.build_data?.[building_id];
|
||
|
||
// UI Validation logic
|
||
if (bData) {
|
||
const missingDeps = bData.missing_dependencies || {};
|
||
const missingKeys = Object.keys(missingDeps);
|
||
|
||
// 1. Popup if dependencies are lacking
|
||
if (missingKeys.length > 0) {
|
||
let msg = '⚠ ΑΔΥΝΑΤΗ Η ΚΑΤΑΣΚΕΥΗ: Λείπουν προϋποθέσεις!\n\nΑπαιτείται:\n';
|
||
for (const k of missingKeys) {
|
||
msg += `- ${missingDeps[k].name} (Επίπεδο ${missingDeps[k].needed_level})\n`;
|
||
}
|
||
return alert(msg);
|
||
}
|
||
|
||
// 2. Confirmation if resources are lacking
|
||
if (bData.enough_resources === false) {
|
||
if (!confirm('❌ Δεν έχετε αρκετούς πόρους!\n\nΘέλετε να προστεθεί στην ουρά αναμονής; Το σύστημα θα το χτίσει αυτόματα μόλις συγκεντρωθούν οι πόροι.')) {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
payload = { building_id };
|
||
} else if (type === 'recruit') {
|
||
const unit_id = document.getElementById('unit-select').value;
|
||
if (!unit_id) return alert('Παρακαλώ επιλέξτε Μονάδα προς εκπαίδευση.');
|
||
|
||
const amount = parseInt(document.getElementById('recruit-amount').value) || 1;
|
||
const uData = town.unit_data?.[unit_id];
|
||
|
||
// UI Validation logic
|
||
if (uData) {
|
||
const missingDeps = uData.missing_dependencies || {};
|
||
const missingKeys = Object.keys(missingDeps);
|
||
|
||
// 1. Popup if dependencies are lacking
|
||
if (missingKeys.length > 0) {
|
||
let msg = '⚠ ΑΔΥΝΑΤΗ Η ΕΚΠΑΙΔΕΥΣΗ: Λείπουν προϋποθέσεις!\n\nΑπαιτείται:\n';
|
||
for (const k of missingKeys) {
|
||
msg += `- ${missingDeps[k].name || k} (Επίπεδο ${missingDeps[k].needed_level || '1'})\n`;
|
||
}
|
||
return alert(msg);
|
||
}
|
||
|
||
// 2. Confirmation if resources are lacking for 1x
|
||
if (uData.enough_resources === false) {
|
||
if (!confirm(`❌ Δεν έχετε αρκετούς πόρους για 1x ${unit_id}!\n\nΘέλετε να προστεθεί στην ουρά αναμονής; Το σύστημα θα εκπαιδεύσει τον στρατό μόλις συγκεντρωθούν οι πόροι.`)) {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
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 };
|
||
} else if (type === 'research') {
|
||
const research_id = window.selectedResearchId;
|
||
if (!research_id) return alert('Παρακαλώ επιλέξτε Έρευνα από την Ακαδημία.');
|
||
|
||
const academyLevel = town.buildings?.academy || 0;
|
||
const rData = window.RESEARCH_DATA[research_id];
|
||
|
||
if (rData && academyLevel < rData.academy_level) {
|
||
return alert(`❌ ΑΔΥΝΑΤΗ Η ΕΡΕΥΝΑ: Απαιτείται Ακαδημία Επίπεδο ${rData.academy_level} (Έχετε ${academyLevel})`);
|
||
}
|
||
|
||
payload = { research_id };
|
||
}
|
||
|
||
try {
|
||
const res = await fetch('/dashboard/commands', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
town_id: town.town_id,
|
||
town_name: town.town_name,
|
||
type,
|
||
payload,
|
||
player_id: window.PLAYER_ID
|
||
})
|
||
});
|
||
const data = await res.json();
|
||
if (data.ok) {
|
||
// Refresh whichever panel is active
|
||
if (type === 'build' && window._logPanelMode === 'queue') {
|
||
window.fetchBuildQueue(town.town_id);
|
||
} else {
|
||
window.fetchLog();
|
||
}
|
||
} else if (data.error === 'client_offline') {
|
||
alert(data.message || 'Το script είναι offline.');
|
||
} else {
|
||
alert('Error: ' + JSON.stringify(data));
|
||
}
|
||
} catch (e) {
|
||
alert('Failed to send command: ' + e);
|
||
}
|
||
};
|
||
|
||
window.cancelCommand = async function(id) {
|
||
await fetch(`/dashboard/commands/${id}`, { method: 'DELETE' });
|
||
window.fetchLog();
|
||
};
|
||
|
||
window.fetchCaptchaStatus = async function() {
|
||
try {
|
||
const res = await fetch('/dashboard/captcha-status?player_id=' + window.PLAYER_ID);
|
||
const data = await res.json();
|
||
const banner = document.getElementById('captcha-banner');
|
||
if (!banner) return;
|
||
|
||
if (data.captcha_active) {
|
||
// Only show it if the user hasn't explicitly clicked 'close' for this specific alert
|
||
if (banner.dataset.dismissed !== '1') {
|
||
banner.style.display = 'flex';
|
||
}
|
||
} else {
|
||
// Captcha cleared from the game - hide banner and reset dismiss state for next time
|
||
banner.style.display = 'none';
|
||
banner.dataset.dismissed = '0';
|
||
}
|
||
} catch (e) {}
|
||
};
|
||
|
||
window.dismissCaptchaBanner = function() {
|
||
const banner = document.getElementById('captcha-banner');
|
||
if (banner) {
|
||
banner.style.display = 'none';
|
||
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);
|
||
}
|
||
};
|
||
|
||
|