// ================================================================
// Command Form Component
// ================================================================
window.onCmdTypeChange = function() {
const type = document.getElementById('cmd-type').value;
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';
document.getElementById('research-options').style.display = type === 'research' ? '' : 'none';
};
// Building emoji icons for the visual grid
window.BUILDING_ICONS = {
main: '🏛️', storage: '🏚️', farm: '🌾', academy: '📜',
temple: '⛩️', barracks: '⚔️', docks: '⚓', market: '🛒',
hide: '🕳️', lumber: '🪵', stoner: '🪨', ironer: '⛏️', wall: '🧱'
};
window.selectedBuildingId = null;
window.renderBuildingDropdown = function() {
// No-op — selection now happens via the modal
};
window.openBuildingModal = function() {
const town = window.getSelectedTown();
if (!town) return;
const grid = document.getElementById('building-grid');
const bLevels = town.buildings || {};
const bData = town.build_data || {};
grid.innerHTML = Object.entries(window.BUILDING_NAMES_GR).map(([key, nameGr]) => {
const level = bLevels[key] !== undefined ? bLevels[key] : '?';
const data = bData[key];
const icon = window.BUILDING_ICONS[key] || '🏗️';
const isSelected = key === window.selectedBuildingId;
if (!data) {
return `
${level}
${icon}
${nameGr}
Αγνωστο
`;
}
const missingKeys = data.missing_dependencies ? Object.keys(data.missing_dependencies) : [];
const isLocked = !data.dependencies || missingKeys.length > 0;
const isMaxed = data.has_max_level;
let statusClass, statusLabel, cardClass = '';
if (isMaxed) {
statusClass = 'maxed'; statusLabel = '✓ Μέγιστο'; cardClass = 'bld-maxed';
} else if (isLocked) {
statusClass = 'locked'; statusLabel = '🔒 Κλειδωμένο'; cardClass = 'bld-locked';
} else if (data.can_upgrade) {
statusClass = 'can-build'; statusLabel = '✅ Αναβάθμιση';
} else if (data.enough_resources === false) {
statusClass = 'no-resources'; statusLabel = '❌ Λείπουν Πόροι';
} else {
statusClass = 'queue-warn'; statusLabel = '⚠️ Πληθ./Ουρά';
}
const w = data.wood ? window.fmt(data.wood) : 0;
const st = data.stone ? window.fmt(data.stone) : 0;
const i = data.iron ? window.fmt(data.iron) : 0;
let t = data.build_time || '';
if (t.startsWith('00:')) t = t.substring(3);
const costStr = (w || st || i) ? `Ξ:${w} Π:${st} Α:${i}${t ? ' · ⏱'+t : ''}` : '';
const clickable = !isMaxed && !isLocked;
const onclick = clickable ? `onclick="window.selectBuilding('${key}','${nameGr}')"` : '';
// Build tooltip for locked buildings
let tooltip = '';
if (isLocked && missingKeys.length > 0) {
const missingDeps = data.missing_dependencies;
const lines = missingKeys.map(k => {
const dep = missingDeps[k];
const depNameGr = window.BUILDING_NAMES_GR[k] || k;
return `${depNameGr} (Επίπεδο ${dep.needed_level || dep.needed || '?'})`;
});
tooltip = `title="Απαιτείται:\n${lines.join('\n')}"`;
}
return `
${level}
${icon}
${nameGr}
${statusLabel}
${costStr ? `${costStr}` : ''}
`;
}).join('');
// Render current build queue in modal footer
const qEl = document.getElementById('building-modal-queue-items');
if (town.build_queue && town.build_queue.length) {
qEl.innerHTML = town.build_queue.map(o => {
const raw = o.building_type || o.name || '';
const gr = window.BUILDING_NAMES_GR[raw] || raw;
return `${gr}`;
}).join('');
} else {
qEl.innerHTML = 'Κενή';
}
document.getElementById('building-modal-overlay').classList.add('open');
};
window.closeBuildingModal = function(e) {
// Close only if clicking the overlay background or the X button
if (e && e.target !== document.getElementById('building-modal-overlay') && e.target !== document.getElementById('building-modal-close')) return;
document.getElementById('building-modal-overlay').classList.remove('open');
};
window.selectBuilding = function(key, nameGr) {
window.selectedBuildingId = key;
// Update the trigger button label
document.getElementById('selected-building-label').textContent = `🏗️ ${nameGr}`;
// Re-render grid to show new selection highlight
window.openBuildingModal();
// Close after brief visual feedback
setTimeout(() => document.getElementById('building-modal-overlay').classList.remove('open'), 180);
};
// ================================================================
// Academy Research Logic
// ================================================================
window.selectedResearchId = null;
window.RESEARCH_DATA = {
"slinger": { "name": "Εκσφενδονιστές", "academy_level": 1, "wood": 300, "stone": 500, "iron": 200, "points": 4 },
"archer": { "name": "Τοξότες", "academy_level": 1, "wood": 550, "stone": 100, "iron": 400, "points": 8 },
"town_guard": { "name": "Φρουρά πόλης", "academy_level": 1, "wood": 400, "stone": 300, "iron": 300, "points": 3 },
"hoplite": { "name": "Οπλίτες", "academy_level": 4, "wood": 600, "stone": 200, "iron": 850, "points": 8 },
"meteorology": { "name": "Μετεωρολογία", "academy_level": 4, "wood": 2500, "stone": 1700, "iron": 6500, "points": 4 },
"espionage": { "name": "Κατασκοπεία", "academy_level": 7, "wood": 900, "stone": 900, "iron": 1100, "points": 3 },
"booty": { "name": "Αφοσίωση χωρικών", "academy_level": 7, "wood": 1300, "stone": 1300, "iron": 1300, "points": 6 },
"pottery": { "name": "Κεραμικά", "academy_level": 7, "wood": 700, "stone": 1500, "iron": 900, "points": 4 },
"rider": { "name": "Ιππείς", "academy_level": 10, "wood": 1400, "stone": 700, "iron": 1800, "points": 8 },
"architecture": { "name": "Αρχιτεκτονική", "academy_level": 10, "wood": 1900, "stone": 2100, "iron": 1300, "points": 6 },
"instructor": { "name": "Εκπαιδευτής", "academy_level": 10, "wood": 800, "stone": 1300, "iron": 1600, "points": 4 },
"bireme": { "name": "Διήρεις", "academy_level": 13, "wood": 2800, "stone": 1300, "iron": 2200, "points": 8 },
"building_crane": { "name": "Γερανός", "academy_level": 13, "wood": 3000, "stone": 1800, "iron": 1400, "points": 4 },
"shipwright": { "name": "Ναυπηγός", "academy_level": 13, "wood": 5000, "stone": 2000, "iron": 3900, "points": 6 },
"colonize_ship": { "name": "Αποικιακά πλοία", "academy_level": 13, "wood": 7500, "stone": 7500, "iron": 9500, "points": 0 },
"chariot": { "name": "Άρματα", "academy_level": 16, "wood": 3700, "stone": 1900, "iron": 2800, "points": 8 },
"attack_ship": { "name": "Πλοία-φάροι", "academy_level": 16, "wood": 4400, "stone": 2000, "iron": 2400, "points": 8 },
"conscription": { "name": "Στρατολόγηση", "academy_level": 16, "wood": 3800, "stone": 4200, "iron": 6000, "points": 4 },
"demolition_ship": { "name": "Πυρπολικά", "academy_level": 19, "wood": 5300, "stone": 2600, "iron": 2700, "points": 8 },
"catapult": { "name": "Καταπέλτες", "academy_level": 19, "wood": 5500, "stone": 2900, "iron": 3600, "points": 8 },
"cryptography": { "name": "Κρυπτογραφία", "academy_level": 19, "wood": 2500, "stone": 3000, "iron": 5100, "points": 6 },
"small_transporter": { "name": "Γρήγορα μεταφορικά πλοία", "academy_level": 22, "wood": 6500, "stone": 2800, "iron": 3200, "points": 8 },
"plow": { "name": "Άροτρο", "academy_level": 22, "wood": 3000, "stone": 3300, "iron": 2100, "points": 4 },
"berth": { "name": "Κουκέτες", "academy_level": 22, "wood": 8900, "stone": 5200, "iron": 7800, "points": 6 },
"trireme": { "name": "Τριήρεις", "academy_level": 25, "wood": 6500, "stone": 3800, "iron": 4700, "points": 8 },
"phalanx": { "name": "Φάλαγγα", "academy_level": 25, "wood": 4000, "stone": 4000, "iron": 15000, "points": 9 },
"breach": { "name": "Διάσπαση εχθρικού μετώπου", "academy_level": 25, "wood": 8000, "stone": 8000, "iron": 9000, "points": 6 },
"mathematics": { "name": "Μαθηματικά", "academy_level": 25, "wood": 7100, "stone": 4400, "iron": 8600, "points": 6 },
"ram": { "name": "Πολιορκητικός κριός", "academy_level": 28, "wood": 7900, "stone": 9200, "iron": 14000, "points": 10 },
"cartography": { "name": "Χαρτογραφία", "academy_level": 28, "wood": 10000, "stone": 6700, "iron": 12500, "points": 8 },
"take_over": { "name": "Κατάκτηση", "academy_level": 28, "wood": 12000, "stone": 12000, "iron": 16000, "points": 0 },
"stone_storm": { "name": "Καταιγισμός από πέτρες", "academy_level": 31, "wood": 8500, "stone": 5900, "iron": 6600, "points": 4 },
"temple_looting": { "name": "Λεηλασία ναού", "academy_level": 31, "wood": 9200, "stone": 5300, "iron": 10000, "points": 6 },
"divine_selection": { "name": "Θεϊκή επιλογή", "academy_level": 31, "wood": 10000, "stone": 8000, "iron": 12000, "points": 10 },
"combat_experience": { "name": "Εμπειρία μάχης", "academy_level": 34, "wood": 9800, "stone": 11400, "iron": 14200, "points": 6 },
"strong_wine": { "name": "Δυνατό κρασί", "academy_level": 34, "wood": 8000, "stone": 6500, "iron": 11000, "points": 4 },
"set_sail": { "name": "Σαλπάρισμα!", "academy_level": 34, "wood": 13000, "stone": 9700, "iron": 15500, "points": 8 }
};
window.openAcademyModal = function() {
const town = window.getSelectedTown();
if (!town) return;
const grid = document.getElementById('academy-grid');
// Group researches by academy level
const levels = [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34];
const townResearches = town.researches || {};
const townBuildings = town.buildings || {};
const townResources = town.resources || { wood: 0, stone: 0, iron: 0 };
const academyLvl = townBuildings.academy || 0;
let html = '';
for (const lvl of levels) {
const researchesInLvl = Object.entries(window.RESEARCH_DATA).filter(([k, v]) => v.academy_level === lvl);
if (researchesInLvl.length === 0) continue;
html += `
`;
for (const [key, data] of researchesInLvl) {
const isResearched = !!townResearches[key];
const isSelected = key === window.selectedResearchId;
const isLocked = academyLvl < lvl;
const noResources = townResources.wood < data.wood || townResources.stone < data.stone || townResources.iron < data.iron;
let statusClass, statusLabel, cardClass = '';
if (isResearched) {
statusClass = 'maxed'; statusLabel = '✓ Ερευνήθηκε'; cardClass = 'bld-maxed';
} else if (isLocked) {
statusClass = 'locked'; statusLabel = '🔒 Κλειδωμένο'; cardClass = 'bld-locked';
} else if (noResources) {
statusClass = 'no-resources'; statusLabel = '❌ Λείπουν Πόροι';
} else {
statusClass = 'can-build'; statusLabel = '✅ Έρευνα';
}
const clickable = !isResearched && !isLocked;
const onclick = clickable ? `onclick="window.selectResearch('${key}', '${data.name}')"` : '';
const costStr = `Ξ:${window.fmt(data.wood)} Π:${window.fmt(data.stone)} Α:${window.fmt(data.iron)}`;
html += `
${data.name}
${statusLabel}
Πόντοι: ${data.points}
${costStr}
`;
}
html += `
`;
}
grid.innerHTML = html;
document.getElementById('academy-modal-overlay').classList.add('open');
};
window.closeAcademyModal = function(e) {
if (e && e.target !== document.getElementById('academy-modal-overlay') && e.target !== document.getElementById('academy-modal-close')) return;
document.getElementById('academy-modal-overlay').classList.remove('open');
};
window.selectResearch = function(key, name) {
window.selectedResearchId = key;
document.getElementById('selected-research-label').textContent = `🧪 ${name}`;
window.openAcademyModal();
setTimeout(() => document.getElementById('academy-modal-overlay').classList.remove('open'), 180);
};
window.selectedUnitId = null;
window.UNIT_ICONS = {
sword: '⚔️', slinger: '🪨', archer: '🏹', hoplite: '🛡️',
rider: '🐎', chariot: '🛷', catapult: '☄️', godsent: '👼',
big_transporter: '⛴️', small_transporter: '🚤', bireme: '🛶',
attack_ship: '🔥', trireme: '🔱', colonize_ship: '⚓',
medusa: '🐍', zyklop: '👁️', harpy: '🦅', pegasus: '🐴',
minotaur: '🐂', manticore: '🦁', cerberus: '🐕',
hydra: '🐉', sea_monster: '🦑', militia: '🧑🌾'
};
window.renderUnitDropdown = function() {
// No-op - selection now happens via modal
};
window.openUnitModal = function() {
const town = window.getSelectedTown();
if (!town) return;
const grid = document.getElementById('unit-grid');
const uData = town.unit_data || {};
// Group units into categories for better display
const categories = {
'Ξηρά': ['sword', 'slinger', 'archer', 'hoplite', 'rider', 'chariot', 'catapult', 'godsent'],
'Ναυτικές': ['big_transporter', 'small_transporter', 'bireme', 'attack_ship', 'trireme', 'colonize_ship'],
'Μυθικές': ['medusa', 'zyklop', 'harpy', 'pegasus', 'minotaur', 'manticore', 'cerberus', 'hydra', 'sea_monster']
};
let html = '';
for (const [catName, units] of Object.entries(categories)) {
let catHtml = '';
for (const key of units) {
if (key === 'militia') continue;
const nameGr = window.UNIT_NAMES_GR[key] || key;
const data = uData[key];
const icon = window.UNIT_ICONS[key] || '💂';
const isSelected = key === window.selectedUnitId;
let statusClass, statusLabel, cardClass = '';
let costStr = '';
let clickable = false;
const requiredGod = window.UNIT_GODS ? window.UNIT_GODS[key] : null;
const isWrongGod = requiredGod && town.god !== requiredGod;
const isNoGod = key === 'godsent' && !town.god;
if (isWrongGod) {
statusClass = 'locked'; statusLabel = '🔒 Άλλος Θεός'; cardClass = 'bld-locked';
const greekGods = { zeus: 'Δία', poseidon: 'Ποσειδώνα', hera: 'Ήρα', athena: 'Αθηνά', hades: 'Άδη', artemis: 'Άρτεμις', aphrodite: 'Αφροδίτη', ares: 'Άρη' };
costStr = `Απαιτεί: ${greekGods[requiredGod] || requiredGod}`;
} else if (isNoGod) {
statusClass = 'locked'; statusLabel = '🔒 Χωρίς Θεό'; cardClass = 'bld-locked';
costStr = `Απαιτείται Ναός`;
} else if (data) {
const missingKeys = data.missing_dependencies ? Object.keys(data.missing_dependencies) : [];
const isLocked = missingKeys.length > 0;
const w = window.fmt(data.wood || 0);
const st = window.fmt(data.stone || 0);
const i = window.fmt(data.iron || 0);
const pop = data.pop || 0;
let t = data.build_time || 0;
let tStr = `${t}s`;
if (t > 60) {
let m = Math.floor(t / 60);
let s = t % 60;
tStr = `${m}m ${s}s`;
}
// Show favor if it's a mythical unit or godsent
const favorStr = (data.favor && data.favor > 0) ? ` ⚡:${data.favor}` : '';
costStr = `Ξ:${w} Π:${st} Α:${i}${favorStr} 🧔:${pop} · ⏱ ${tStr}`;
if (isLocked) {
statusClass = 'locked'; statusLabel = '🔒 Κλειδωμένο'; cardClass = 'bld-locked';
} else if (data.enough_resources === false) {
statusClass = 'no-resources'; statusLabel = '❌ Λείπουν Πόροι';
} else {
statusClass = 'can-build'; statusLabel = '✅ Διαθέσιμο';
clickable = true;
}
} else {
// If no data is available for this unit, treat it as locked/unknown
statusClass = 'locked'; statusLabel = '🔒 Άγνωστο'; cardClass = 'bld-locked';
}
const onclick = clickable ? `onclick="window.selectUnit('${key}', '${nameGr}')"` : '';
catHtml += `
${icon}
${nameGr}
${statusLabel}
${costStr}
`;
}
if (catHtml) {
html += ``;
}
}
grid.innerHTML = html;
document.getElementById('unit-modal-overlay').classList.add('open');
};
window.closeUnitModal = function(e) {
if (e && e.target !== document.getElementById('unit-modal-overlay') && e.target !== document.getElementById('unit-modal-close')) return;
document.getElementById('unit-modal-overlay').classList.remove('open');
};
window.selectUnit = function(key, nameGr) {
window.selectedUnitId = key;
document.getElementById('selected-unit-label').textContent = `${window.UNIT_ICONS[key] || '💂'} ${nameGr}`;
window.openUnitModal();
setTimeout(() => document.getElementById('unit-modal-overlay').classList.remove('open'), 180);
};
// ================================================================
window.renderBuildQueuePreview = function() {
const town = window.getSelectedTown();
const el = document.getElementById('build-queue-preview');
if (!town || !town.build_queue || !town.build_queue.length) {
el.innerHTML = 'Build queue: empty';
return;
}
const items = town.build_queue.map(o => {
const raw = o.building_type || o.name || "";
const nameGr = window.BUILDING_NAMES_GR[raw] || raw || JSON.stringify(o);
return `${nameGr}`;
}).join('');
el.innerHTML = `Current queue
${items}`;
};