38676-vm/index.php
2026-03-13 21:45:42 +00:00

537 lines
40 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once 'db/config.php';
require_once 'includes/status_helper.php';
session_start();
$db = db();
// HEADER IS NOW IN includes/header.php
// But we still need some data for the map and modals in index.php
$user_role = $_SESSION['user_role'] ?? 'user';
$view = isset($_GET['view']) ? $_GET['view'] : 'sector';
$galaxy_id = isset($_GET['galaxy_id']) ? (int)$_GET['galaxy_id'] : 1;
$sector_id = isset($_GET['sector_id']) ? (int)$_GET['sector_id'] : 1;
// Fetch Dynamic Types, Statuses and Factions
$object_types_db = $db->query("SELECT * FROM celestial_object_types")->fetchAll(PDO::FETCH_ASSOC);
$statuses_db = $db->query("SELECT * FROM celestial_object_statuses")->fetchAll(PDO::FETCH_ASSOC);
$factions_db = $db->query("SELECT * FROM factions")->fetchAll(PDO::FETCH_ASSOC);
$object_types_map = [];
foreach($object_types_db as $ot) {
$stmt = $db->prepare("SELECT m.* FROM modifiers m JOIN celestial_object_type_modifiers cotm ON m.id = cotm.modifier_id WHERE cotm.celestial_object_type_id = ?");
$stmt->execute([$ot['id']]);
$ot['modifiers'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
$object_types_map[$ot['slug']] = $ot;
}
$statuses_map = []; foreach($statuses_db as $s) { $s['is_blinking'] = (strpos($s['color'], ';blink') !== false); $statuses_map[$s['slug']] = $s; }
$factions_map = []; foreach($factions_db as $f) $factions_map[$f['id']] = $f;
$grid_size = 36;
if ($view === 'sector') {
$stmt = $db->prepare("SELECT * FROM planets WHERE galaxy_id = ? AND sector_id = ? AND slot BETWEEN 1 AND ?");
$stmt->execute([$galaxy_id, $sector_id, $grid_size]);
$objects_raw = $stmt->fetchAll();
$grid = array_fill(1, $grid_size, null);
$planet_ids = [];
foreach ($objects_raw as $obj) {
$grid[$obj['slot']] = $obj;
$planet_ids[] = $obj['id'];
$grid[$obj['slot']]['cities'] = [];
$grid[$obj['slot']]['orbital_controls'] = [];
$grid[$obj['slot']]['terrestrial_controls'] = [];
}
if (!empty($planet_ids)) {
$placeholders = implode(',', array_fill(0, count($planet_ids), '?'));
$stmt = $db->prepare("SELECT * FROM planet_faction_control WHERE planet_id IN ($placeholders)");
$stmt->execute($planet_ids);
$orb_controls_raw = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($orb_controls_raw as $ocr) {
foreach ($grid as &$slot_data) {
if ($slot_data && $slot_data['id'] == $ocr['planet_id']) {
$slot_data['orbital_controls'][$ocr['faction_id']] = $ocr['control_level'];
}
}
}
unset($slot_data);
$stmt = $db->prepare("SELECT c.*, st.name as type_name FROM cities c LEFT JOIN settlement_types st ON c.settlement_type_id = st.id WHERE c.planet_id IN ($placeholders)");
$stmt->execute($planet_ids);
$all_cities = $stmt->fetchAll(PDO::FETCH_ASSOC);
$city_ids = array_column($all_cities, 'id');
$city_controls = [];
if (!empty($city_ids)) {
$c_placeholders = implode(',', array_fill(0, count($city_ids), '?'));
$c_stmt = $db->prepare("SELECT * FROM city_faction_control WHERE city_id IN ($c_placeholders)");
$c_stmt->execute($city_ids);
$controls_raw = $c_stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($controls_raw as $cr) {
$city_controls[$cr['city_id']][$cr['faction_id']] = $cr['control_level'];
}
}
$planet_terrestrial_agg = [];
foreach ($all_cities as $city) {
$pid = $city['planet_id'];
$city['controls'] = $city_controls[$city['id']] ?? [];
foreach ($city['controls'] as $fid => $lvl) {
$planet_terrestrial_agg[$pid][$fid] = ($planet_terrestrial_agg[$pid][$fid] ?? 0) + $lvl;
}
foreach ($grid as &$slot_data) {
if ($slot_data && $slot_data['id'] == $pid) {
$slot_data['cities'][] = $city;
}
}
}
unset($slot_data);
foreach ($grid as &$slot_data) {
if ($slot_data && !empty($slot_data['cities'])) {
$num_cities = count($slot_data['cities']);
$pid = $slot_data['id'];
if (isset($planet_terrestrial_agg[$pid])) {
foreach ($planet_terrestrial_agg[$pid] as $fid => $total_lvl) {
$slot_data['terrestrial_controls'][$fid] = round($total_lvl / $num_cities);
}
}
}
}
unset($slot_data);
foreach ($grid as &$slot_data) {
if ($slot_data) {
$slot_data['status'] = calculateCelestialStatus($slot_data, $db, $statuses_map);
}
}
}
unset($slot_data);
$stmt = $db->prepare("SELECT name FROM sectors WHERE id = ?");
$stmt->execute([$sector_id]);
$sector_info = $stmt->fetch();
$sector_display_name = $sector_info['name'] ?? "Secteur $sector_id";
$page_title = "$sector_display_name [G$galaxy_id]";
} else {
$stmt = $db->prepare("SELECT * FROM planets WHERE galaxy_id = ? ORDER BY sector_id, slot ASC");
$stmt->execute([$galaxy_id]);
$all_planets = $stmt->fetchAll(PDO::FETCH_ASSOC);
$planet_ids = array_column($all_planets, 'id');
$orb_controls = [];
$terr_controls = [];
$city_counts = [];
if (!empty($planet_ids)) {
$placeholders = implode(',', array_fill(0, count($planet_ids), '?'));
$o_stmt = $db->prepare("SELECT * FROM planet_faction_control WHERE planet_id IN ($placeholders)");
$o_stmt->execute($planet_ids);
while($r = $o_stmt->fetch()) $orb_controls[$r['planet_id']][$r['faction_id']] = $r['control_level'];
$t_stmt = $db->prepare("SELECT c.planet_id, cfc.faction_id, SUM(cfc.control_level) as total_lvl FROM city_faction_control cfc JOIN cities c ON cfc.city_id = c.id WHERE c.planet_id IN ($placeholders) GROUP BY c.planet_id, cfc.faction_id");
$t_stmt->execute($planet_ids);
while($r = $t_stmt->fetch()) {
$terr_controls[$r['planet_id']][$r['faction_id']] = $r['total_lvl'];
}
$c_stmt = $db->prepare("SELECT planet_id, COUNT(*) as cnt FROM cities WHERE planet_id IN ($placeholders) GROUP BY planet_id");
$c_stmt->execute($planet_ids);
while($r = $c_stmt->fetch()) $city_counts[$r['planet_id']] = $r['cnt'];
}
$sector_data = [];
$active_sectors = [];
foreach ($all_planets as $p) {
$p['orbital_controls'] = $orb_controls[$p['id']] ?? [];
$p['cities'] = isset($city_counts[$p['id']]) ? array_fill(0, $city_counts[$p['id']], []) : [];
$p['terrestrial_controls'] = [];
if (!empty($p['cities'])) {
$num_cities = count($p['cities']);
if (isset($terr_controls[$p['id']])) {
foreach ($terr_controls[$p['id']] as $fid => $total_lvl) {
$p['terrestrial_controls'][$fid] = round($total_lvl / $num_cities);
}
}
}
$dynamic_status = calculateCelestialStatus($p, $db, $statuses_map);
$sector_data[$p['sector_id']][$p['slot']] = ['status' => $dynamic_status, 'type' => $p['type']];
if (!in_array($p['sector_id'], $active_sectors)) { $active_sectors[] = (int)$p['sector_id']; }
}
$page_title = "Galaxie $galaxy_id";
}
function getStatusColor($status, $statuses_map) {
$c = $statuses_map[$status]['color'] ?? 'rgba(255,255,255,0.05)'; return str_replace(';blink', '', $c);
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Nexus - <?php echo $page_title; ?></title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link href="assets/css/custom.css?v=<?php echo time(); ?>" rel="stylesheet">
<style>
body { background: #000; color: #fff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; }
#main-wrapper { display: flex; flex-direction: column; min-height: 100vh; }
#game-container { flex: 1; padding: 30px; display: flex; flex-direction: column; align-items: center; }
.nav-panel { background: rgba(10, 15, 30, 0.95); border: 1px solid #2d3545; padding: 20px; width: 180px; }
.nav-panel h3 { margin: 0 0 15px 0; color: #88c0d0; font-size: 14px; text-transform: uppercase; border-bottom: 1px solid #2d3545; padding-bottom: 10px; }
.nav-panel label { display: block; font-size: 10px; color: #8c92a3; margin-top: 10px; }
.nav-panel input { width: 100%; background: #000; border: 1px solid #3b4252; color: #fff; padding: 5px; margin-top: 3px; font-size: 12px; }
.nav-panel button { width: 100%; margin-top: 15px; background: #88c0d0; border: none; padding: 8px; color: #000; font-weight: bold; cursor: pointer; border-radius: 2px; }
.galaxy-map { display: grid; grid-template-columns: repeat(6, 140px); grid-template-rows: repeat(6, 140px); gap: 10px; padding: 15px; background: rgba(10, 15, 30, 0.5); border: 1px solid #2d3545; box-shadow: 0 0 30px rgba(0,0,0,0.5); }
.slot { width: 140px; height: 140px; background: rgba(46, 52, 64, 0.3); border: 1px solid #3b4252; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s; overflow: hidden; }
.slot:hover { background: rgba(136, 192, 208, 0.1); border-color: #88c0d0; z-index: 10; }
.slot-id { position: absolute; top: 5px; left: 8px; font-size: 9px; color: #4c566a; font-weight: bold; z-index: 5; }
.slot-icons { position: absolute; top: 5px; right: 5px; display: flex; flex-direction: column; gap: 5px; align-items: center; z-index: 6; }
.faction-icon-sm { width: 22px; height: 22px; filter: drop-shadow(0 0 2px rgba(0,0,0,0.8)); display: flex; align-items: center; justify-content: center; }
.info-icon-sm { width: 20px; height: 20px; font-size: 14px; color: #ebcb8b; filter: drop-shadow(0 0 2px rgba(0,0,0,0.8)); display: flex; align-items: center; justify-content: center; }
.object-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90px; height: 90px; display: flex; align-items: center; justify-content: center; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); line-height: 1; font-size: 90px; z-index: 2; }
.object-image { width: 90px; height: 90px; object-fit: contain; margin: 0; }
.slot:hover .object-icon { transform: translate(-50%, -50%) scale(1.1); }
.object-name { position: absolute; bottom: 8px; font-size: 11px; font-weight: bold; color: #eceff4; text-align: center; width: 95%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; z-index: 3; text-shadow: 0 0 4px rgba(0,0,0,0.8); }
.sector-grid { display: grid; grid-template-columns: repeat(6, 180px); grid-template-rows: repeat(6, 180px); gap: 15px; }
.sector-card { background: rgba(10, 15, 30, 0.95); border: 1px solid #2d3545; padding: 20px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-decoration: none; color: #fff; transition: all 0.2s; position: relative; width: 180px; height: 180px; box-sizing: border-box; }
.sector-card:hover { border-color: #88c0d0; background: #1a202c; transform: translateY(-3px); }
.sector-card.empty { opacity: 0.6; }
.mini-map { display: grid; grid-template-columns: repeat(6, 12px); gap: 4px; margin-bottom: 15px; background: #000; padding: 6px; border-radius: 2px; }
.mini-dot { width: 12px; height: 12px; border-radius: 1px; }
/* MODAL STYLES */
.planet-hero { display: flex; gap: 25px; margin-bottom: 25px; align-items: center; }
.planet-preview-img { width: 120px; height: 120px; object-fit: contain; filter: drop-shadow(0 0 15px rgba(136, 192, 208, 0.3)); }
.planet-meta { flex: 1; }
.planet-status-badge { display: inline-block; padding: 4px 10px; border-radius: 20px; font-size: 11px; font-weight: bold; text-transform: uppercase; margin-bottom: 10px; }
.control-section { margin-bottom: 25px; padding: 15px; background: rgba(30, 41, 59, 0.3); border-radius: 8px; border: 1px solid rgba(136, 192, 208, 0.1); }
.control-title { font-size: 12px; font-weight: bold; color: #88c0d0; text-transform: uppercase; margin-bottom: 15px; display: flex; align-items: center; gap: 10px; }
.multi-control-bar { height: 14px; background: #1e293b; border-radius: 7px; overflow: hidden; display: flex; margin-bottom: 10px; box-shadow: inset 0 2px 4px rgba(0,0,0,0.3); }
.control-segment { height: 100%; transition: width 0.3s ease; position: relative; }
.control-legend { display: flex; flex-wrap: wrap; gap: 15px; margin-top: 10px; }
.legend-tag { display: flex; align-items: center; gap: 6px; font-size: 11px; color: #cbd5e1; }
.legend-color { width: 10px; height: 10px; border-radius: 2px; }
.settlement-card { background: rgba(15, 23, 42, 0.6); border: 1px solid #1e293b; border-radius: 8px; padding: 15px; margin-bottom: 15px; }
.settlement-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.settlement-name { font-weight: bold; font-size: 14px; color: #fff; }
.settlement-type { font-size: 10px; color: #8c92a3; text-transform: uppercase; }
.tooltip-box { display: none; position: absolute; top: -10px; left: 105%; width: 240px; background: #1e293b; border: 1px solid #88c0d0; padding: 15px; z-index: 100; pointer-events: none; box-shadow: 10px 10px 20px rgba(0,0,0,0.5); }
.slot:hover .tooltip-box { display: block; }
.tooltip-title { font-size: 14px; color: #88c0d0; font-weight: bold; border-bottom: 1px solid #334155; padding-bottom: 8px; margin-bottom: 8px; }
.tooltip-desc { font-size: 11px; color: #d8dee9; line-height: 1.4; font-style: italic; margin-bottom: 10px; }
.mod-list { display: flex; flex-direction: column; gap: 5px; }
.mod-item { font-size: 10px; padding: 4px 8px; border-radius: 3px; display: flex; align-items: center; gap: 8px; }
.mod-bonus { background: rgba(163, 190, 140, 0.15); color: #a3be8c; border: 1px solid rgba(163, 190, 140, 0.3); }
.mod-malus { background: rgba(191, 97, 106, 0.15); color: #bf616a; border: 1px solid rgba(191, 97, 106, 0.3); }
.settlement-title { font-size: 10px; color: #ebcb8b; font-weight: bold; border-top: 1px solid #334155; margin-top: 8px; padding-top: 5px; margin-bottom: 5px; }
.settlement-item-tool { font-size: 9px; color: #fff; margin-bottom: 10px; background: rgba(0,0,0,0.2); padding: 5px; border-radius: 3px; }
.control-bars-mini { margin-top: 5px; display: flex; flex-direction: column; gap: 3px; }
.control-bar-mini { height: 4px; background: #000; border-radius: 2px; overflow: hidden; display: flex; }
.control-fill { height: 100%; }
.control-label-mini { font-size: 7px; color: #8c92a3; display: flex; justify-content: space-between; margin-bottom: 1px; }
.legend { margin-top: 20px; background: rgba(10, 15, 30, 0.95); border: 1px solid #2d3545; padding: 10px 20px; display: flex; gap: 15px; font-size: 10px; flex-wrap: wrap; max-width: 1000px; justify-content: center; }
.legend-item { display: flex; align-items: center; gap: 5px; }
.dot { width: 8px; height: 8px; border-radius: 1px; }
.breadcrumb { margin-bottom: 20px; font-size: 14px; color: #88c0d0; }
.breadcrumb a { color: #fff; text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
.admin-footer { position: fixed; bottom: 0; left: 0; width: 100%; background: rgba(0,0,0,0.8); padding: 5px 20px; display: flex; justify-content: flex-end; gap: 15px; border-top: 1px solid #2d3545; }
.admin-footer a { color: #fff; text-decoration: none; font-size: 11px; font-weight: bold; padding: 5px 10px; border-radius: 3px; }
.btn-mj { background: #ebcb8b; color: #000 !important; }
.btn-adm { background: #bf616a; }
</style>
</head>
<body>
<div id="main-wrapper">
<?php require_once 'includes/header.php'; ?>
<main id="game-container">
<div class="breadcrumb">
<a href="?view=galaxy&galaxy_id=<?php echo $galaxy_id; ?>">Galaxie <?php echo $galaxy_id; ?></a>
<?php if($view === 'sector'): ?> &nbsp;>&nbsp; <?php echo htmlspecialchars($sector_display_name); ?> <?php endif; ?>
</div>
<div style="display: flex; gap: 40px; align-items: flex-start; width: 100%; max-width: 1200px; justify-content: center;">
<div class="nav-panel">
<h3>Univers</h3>
<form method="GET"><input type="hidden" name="view" value="<?php echo $view; ?>">
<div><label>Galaxie</label><input type="number" name="galaxy_id" value="<?php echo $galaxy_id; ?>" min="1"></div>
<?php if($view === 'sector'): ?><div><label>Secteur</label><input type="number" name="sector_id" value="<?php echo $sector_id; ?>" min="1"></div><?php endif; ?>
<button type="submit">Localiser</button>
</form>
<?php if($view === 'sector'): ?><button onclick="location.href='?view=galaxy&galaxy_id=<?php echo $galaxy_id; ?>'" style="background: #3b4252; margin-top: 5px;">Vue Galaxie</button><?php endif; ?>
</div>
<?php if($view === 'sector'): ?>
<div class="galaxy-map">
<?php for($i=1; $i<=$grid_size; $i++): ?>
<?php
$obj = $grid[$i] ?? null;
$json_data = $obj ? htmlspecialchars(json_encode($obj)) : 'null';
?>
<div class="slot" onclick="openPlanetModal(<?php echo $json_data; ?>)">
<span class="slot-id"><?php echo $i; ?></span>
<?php if ($obj):
$type_info = $object_types_map[$obj['type']] ?? null;
$fac_info = isset($obj['faction_id']) ? ($factions_map[$obj['faction_id']] ?? null) : null;
?>
<div class="tooltip-box">
<div class="tooltip-title"><?php echo htmlspecialchars($obj['name']); ?></div>
<div style="font-size: 10px; color: #88c0d0; margin-bottom: 5px;"><i class="fa-solid fa-circle-info"></i> <?php echo $statuses_map[$obj['status']]['name'] ?? ucfirst($obj['status']); ?></div>
<?php if ($fac_info && $fac_info['name'] !== 'Aucune'): ?>
<div style="font-size: 10px; color: <?php echo htmlspecialchars($fac_info['color'] ?? '#ebcb8b'); ?>; margin-bottom: 5px;"><i class="fa-solid fa-flag"></i> Faction: <?php echo htmlspecialchars($fac_info['name']); ?></div>
<?php endif; ?>
<div class="tooltip-desc"><?php echo htmlspecialchars($type_info['description'] ?? ''); ?></div>
<?php if (!empty($obj['orbital_controls'])): ?>
<div class="settlement-title" style="color: #88c0d0;"><i class="fa-solid fa-satellite-dish"></i> Contrôle Orbital:</div>
<div class="settlement-item-tool">
<div class="control-bars-mini">
<?php
foreach ($obj['orbital_controls'] as $fid => $lvl):
if ($lvl <= 0) continue;
$fName = $factions_map[$fid]['name'] ?? 'Inconnue';
$fColor = $factions_map[$fid]['color'] ?? '#88c0d0';
?>
<div class="control-label-mini"><span><?php echo htmlspecialchars($fName); ?></span><span><?php echo $lvl; ?>%</span></div>
<div class="control-bar-mini"><div class="control-fill" style="width: <?php echo $lvl; ?>%; background: <?php echo htmlspecialchars($fColor); ?>;"></div></div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<?php if (!empty($obj['cities'])): ?>
<div class="settlement-title"><i class="fa-solid fa-city"></i> Établissements:</div>
<?php foreach ($obj['cities'] as $c): ?>
<div class="settlement-item-tool">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;"><strong><?php echo htmlspecialchars($c['name']); ?></strong> <span style="color: #8c92a3; font-size: 7px;"><?php echo htmlspecialchars($c['type_name']); ?></span></div>
<?php if (!empty($c['controls'])): ?>
<div class="control-bars-mini">
<?php
foreach ($c['controls'] as $fid => $lvl):
if ($lvl <= 0) continue;
$fName = $factions_map[$fid]['name'] ?? 'Inconnue';
$fColor = $factions_map[$fid]['color'] ?? '#88c0d0';
?>
<div class="control-label-mini"><span><?php echo htmlspecialchars($fName); ?></span><span><?php echo $lvl; ?>%</span></div>
<div class="control-bar-mini"><div class="control-fill" style="width: <?php echo $lvl; ?>%; background: <?php echo htmlspecialchars($fColor); ?>;"></div></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
<?php if (!empty($type_info['modifiers'])): ?>
<div class="mod-list">
<?php foreach ($type_info['modifiers'] as $m): ?>
<div class="mod-item <?php echo $m['type'] === 'bonus' ? 'mod-bonus' : 'mod-malus'; ?>"><i class="fa-solid <?php echo $m['type'] === 'bonus' ? 'fa-circle-up' : 'fa-circle-down'; ?>"></i> <strong><?php echo htmlspecialchars($m['name']); ?>:</strong> <?php echo htmlspecialchars($m['description']); ?></div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<div class="slot-icons">
<?php if ($fac_info): ?>
<div class="faction-icon-sm">
<?php if (!empty($fac_info['image_url'])): ?><img src="<?php echo htmlspecialchars($fac_info['image_url']); ?>?v=<?php echo time(); ?>" style="width: 100%; height: 100%; object-fit: contain;" title="<?php echo htmlspecialchars($fac_info['name']); ?>">
<?php elseif (!empty($fac_info['fa_icon'])): ?><i class="fa-solid <?php echo htmlspecialchars($fac_info['fa_icon']); ?>" style="color: <?php echo htmlspecialchars($fac_info['color'] ?? '#fff'); ?>; font-size: 16px;" title="<?php echo htmlspecialchars($fac_info['name']); ?>"></i>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (!empty($obj['cities'])): ?><div class="info-icon-sm" title="Établissements présents"><i class="fa-solid fa-city"></i></div><?php endif; ?>
</div>
<div class="object-icon <?php echo ($statuses_map[$obj['status']]['is_blinking'] ?? 0) ? 'blink-effect' : ''; ?>">
<?php
$icon = $type_info['icon'] ?? 'fa-earth-europe';
$color = getStatusColor($obj['status'], $statuses_map);
$imageUrl = $type_info['image_url'] ?? null;
if ($imageUrl): ?><img src="<?php echo htmlspecialchars($imageUrl); ?>?v=<?php echo time(); ?>" class="object-image">
<?php else: ?><i class="fa-solid <?php echo $icon; ?>" style="color: <?php echo $color; ?>;"></i>
<?php endif; ?>
</div>
<span class="object-name"><?php echo htmlspecialchars($obj['name']); ?></span>
<?php else: ?>
<div style="opacity: 0.05;"><i class="fa-solid fa-circle fa-sm"></i></div>
<?php endif; ?>
</div>
<?php endfor; ?>
</div>
<?php else: ?>
<div class="sector-grid">
<?php for($s=1; $s<=$grid_size; $s++): $isActive = in_array($s, $active_sectors); ?>
<a href="?view=sector&galaxy_id=<?php echo $galaxy_id; ?>&sector_id=<?php echo $s; ?>" class="sector-card <?php echo $isActive ? '' : 'empty'; ?>">
<div class="mini-map">
<?php for($p=1; $p<=$grid_size; $p++):
$dotColor = 'rgba(255,255,255,0.05)';
if (isset($sector_data[$s][$p])) { $dotColor = getStatusColor($sector_data[$s][$p]['status'], $statuses_map); }
?>
<div class="mini-dot <?php echo (isset($sector_data[$s][$p]) && ($statuses_map[$sector_data[$s][$p]['status']]['is_blinking'] ?? 0)) ? 'blink-effect' : ''; ?>" style="background-color: <?php echo $dotColor; ?>;"></div>
<?php endfor; ?>
</div>
<div style="font-size: 10px; color: #88c0d0;">SECTEUR</div>
<div style="font-size: 20px; font-weight: bold;"><?php echo $s; ?></div>
<?php if($isActive): ?><div style="font-size: 8px; color: #a3be8c; margin-top: 5px;"><i class="fa-solid fa-check"></i> Actif</div>
<?php else: ?><div style="font-size: 8px; color: #4c566a; margin-top: 5px;">Inexploré</div><?php endif; ?>
</a>
<?php endfor; ?>
</div>
<?php endif; ?>
</div>
<div class="legend">
<?php foreach($statuses_db as $s): ?>
<div class="legend-item"><span class="dot <?php echo $s['is_blinking'] ? 'blink-effect' : ''; ?>" style="background: <?php echo str_replace(';blink', '', str_replace(' ;blink', '', $s['color'])); ?>;"></span> <?php echo $s['name']; ?></div>
<?php endforeach; ?>
</div>
</main>
</div>
<!-- MODAL OVERLAY -->
<div id="planetModal" class="modal-overlay" onclick="if(event.target === this) closePlanetModal()">
<div class="modal-container">
<div class="modal-header">
<div style="display: flex; flex-direction: column; align-items: flex-start;"><h2 id="m-planet-name">Planet Name</h2><div id="m-planet-type" style="font-style: italic; font-size: 13px; color: #88c0d0; opacity: 0.8; margin-top: 2px;"></div></div>
<button class="modal-close" onclick="closePlanetModal()">&times;</button>
</div>
<div class="modal-body">
<div class="planet-hero">
<img id="m-planet-img" src="" class="planet-preview-img">
<div class="planet-meta">
<div id="m-planet-status" class="planet-status-badge">Status</div>
<div id="m-planet-faction" style="font-size: 13px; font-weight: bold; margin-bottom: 8px;">Faction: None</div>
<div id="m-planet-mods" class="mod-list"></div>
</div>
</div>
<div id="m-orbital-section" class="control-section">
<div class="control-title"><i class="fa-solid fa-satellite-dish"></i> Contrôle Orbital</div>
<div id="m-orbital-bar" class="multi-control-bar"></div>
<div id="m-orbital-legend" class="control-legend"></div>
</div>
<div id="m-terrestrial-section" class="control-section">
<div class="control-title"><i class="fa-solid fa-person-military-pointing"></i> Contrôle Terrestre</div>
<div id="m-terrestrial-bar" class="multi-control-bar"></div>
<div id="m-terrestrial-legend" class="control-legend"></div>
</div>
<div id="m-cities-section"><div class="control-title"><i class="fa-solid fa-city"></i> Lieux et points dintérêts</div><div id="m-cities-container"></div></div>
</div>
</div>
</div>
<?php if ($user_role === 'admin' || $user_role === 'gm'): ?>
<div class="admin-footer">
<a href="gm_console.php" class="btn-mj"><i class="fa-solid fa-headset"></i> CONSOLE MG</a>
<?php if ($user_role === 'admin'): ?><a href="admin.php" class="btn-adm"><i class="fa-solid fa-shield-halved"></i> CONSOLE ADMIN</a><?php endif; ?>
</div>
<?php endif; ?>
<script>
const factionsMap = <?php echo json_encode($factions_map); ?>;
const typesMap = <?php echo json_encode($object_types_map); ?>;
const statusesMap = <?php echo json_encode($statuses_map); ?>;
function openPlanetModal(data) {
if (!data) return;
const typeInfo = typesMap[data.type] || {};
const statusInfo = statusesMap[data.status] || {};
const factionInfo = factionsMap[data.faction_id] || { name: 'Aucune', color: '#8c92a3' };
document.getElementById('m-planet-name').innerText = data.name;
document.getElementById('m-planet-type').innerText = typeInfo.name || data.type;
document.getElementById('m-planet-img').src = typeInfo.image_url || '';
document.getElementById('m-planet-status').innerText = statusInfo.name || data.status;
const statusEl = document.getElementById('m-planet-status'); statusEl.style.background = (statusInfo.color || 'rgba(255,255,255,0.1)').replace(' ;blink', '').replace(';blink', ''); statusEl.classList.toggle('blink-effect', !!statusInfo.is_blinking);
document.getElementById('m-planet-faction').innerText = 'Faction dominante: ' + factionInfo.name;
document.getElementById('m-planet-faction').style.color = factionInfo.color || '#fff';
const modContainer = document.getElementById('m-planet-mods');
modContainer.innerHTML = '';
if (typeInfo.modifiers && typeInfo.modifiers.length > 0) {
typeInfo.modifiers.forEach(m => {
const modDiv = document.createElement('div');
modDiv.className = 'mod-item ' + (m.type === 'bonus' ? 'mod-bonus' : 'mod-malus');
modDiv.innerHTML = `<i class="fa-solid ${m.type === 'bonus' ? 'fa-circle-up' : 'fa-circle-down'}"></i> <strong>${m.name}:</strong> ${m.description}`;
modContainer.appendChild(modDiv);
});
} else { modContainer.innerHTML = '<div style="font-size: 11px; color: #64748b; font-style: italic;">Aucun modificateur particulier.</div>'; }
const orbitalBar = document.getElementById('m-orbital-bar'); orbitalBar.innerHTML = '';
const orbitalLegend = document.getElementById('m-orbital-legend'); orbitalLegend.innerHTML = '';
if (typeInfo.orbital_control_enabled == 1 && data.orbital_controls && Object.keys(data.orbital_controls).length > 0) {
document.getElementById('m-orbital-section').style.display = 'block';
renderMultiBar(data.orbital_controls, orbitalBar, orbitalLegend);
} else { document.getElementById('m-orbital-section').style.display = 'none'; }
const terrestrialBar = document.getElementById('m-terrestrial-bar'); terrestrialBar.innerHTML = '';
const terrestrialLegend = document.getElementById('m-terrestrial-legend'); terrestrialLegend.innerHTML = '';
if (typeInfo.terrestrial_control_enabled == 1 && data.terrestrial_controls && Object.keys(data.terrestrial_controls).length > 0) {
document.getElementById('m-terrestrial-section').style.display = 'block';
renderMultiBar(data.terrestrial_controls, terrestrialBar, terrestrialLegend);
} else { document.getElementById('m-terrestrial-section').style.display = 'none'; }
const citiesContainer = document.getElementById('m-cities-container'); citiesContainer.innerHTML = '';
if (typeInfo.terrestrial_control_enabled == 1 && data.cities && data.cities.length > 0) {
document.getElementById('m-cities-section').style.display = 'block';
data.cities.forEach(city => {
const card = document.createElement('div'); card.className = 'settlement-card';
const header = document.createElement('div'); header.className = 'settlement-header';
header.innerHTML = `<span class="settlement-name">${city.name}</span><span class="settlement-type">${city.type_name}</span>`;
card.appendChild(header);
if (city.controls && Object.keys(city.controls).length > 0) {
const bar = document.createElement('div'); bar.className = 'multi-control-bar';
const legend = document.createElement('div'); legend.className = 'control-legend';
renderMultiBar(city.controls, bar, legend);
card.appendChild(bar); card.appendChild(legend);
}
citiesContainer.appendChild(card);
});
} else { document.getElementById('m-cities-section').style.display = 'none'; }
document.getElementById('planetModal').style.display = 'flex';
}
function renderMultiBar(controls, barElement, legendElement) {
Object.entries(controls).forEach(([fid, lvl]) => {
const level = parseInt(lvl);
const fac = factionsMap[fid] || { name: 'Inconnue', color: '#88c0d0' };
if (level <= 0) return;
const segment = document.createElement('div'); segment.className = 'control-segment'; segment.style.width = level + '%'; segment.style.backgroundColor = fac.color || '#88c0d0'; segment.title = `${fac.name}: ${level}%`; barElement.appendChild(segment);
const tag = document.createElement('div'); tag.className = 'legend-tag'; tag.innerHTML = `<span class="legend-color" style="background:${fac.color}"></span> ${fac.name}: ${level}%`; legendElement.appendChild(tag);
});
}
function closePlanetModal() { document.getElementById('planetModal').style.display = 'none'; }
</script>
<!-- PROFILE MODAL -->
<div id="profileModal" class="modal-overlay" onclick="if(event.target === this) this.style.display='none'">
<div class="modal-container modal-nexus">
<div class="modal-header"><h2>Profil Public</h2><button class="modal-close" onclick="document.getElementById('profileModal').style.display='none'">&times;</button></div>
<div class="modal-body">
<div class="profile-top-section">
<div style="display: flex; align-items: center; justify-content: center; margin-bottom: 5px;">
<img src="<?php echo htmlspecialchars($_SESSION["grade_image"] ?? "assets/images/placeholder_grade.png"); ?>" class="profile-grade-img">
<span class="profile-username"><?php echo htmlspecialchars($_SESSION["grade_name"] ?? "Recrue"); ?> <?php echo htmlspecialchars($_SESSION["display_name"] ?? $_SESSION["username"]); ?></span>
</div>
<?php if (!empty($_SESSION['selected_title_name'])): ?><span class="profile-title-text">— <?php echo htmlspecialchars($_SESSION['selected_title_name']); ?> —</span><?php endif; ?>
<span class="profile-level-text">Niveau <?php echo htmlspecialchars($_SESSION["level"] ?? "1"); ?></span>
</div>
<div class="profile-section-header">Guilde</div>
<div class="guild-info-box">
<?php if (!empty($_SESSION['guild_id'])): ?>
<div class="guild-display"><div class="guild-icon-placeholder"><i class="fa-solid fa-building-shield"></i></div><span class="guild-tag-display">[<?php echo htmlspecialchars($_SESSION['guild_tag']); ?>]</span><span class="guild-name-display"><?php echo htmlspecialchars($_SESSION['guild_name']); ?></span></div>
<?php else: ?><div class="guild-display" style="opacity: 0.5;"><div class="guild-icon-placeholder"><i class="fa-solid fa-user"></i></div><span class="guild-name-display" style="font-style: italic;">Aucune guilde</span></div>
<?php endif; ?>
</div>
<div class="profile-bottom-grid">
<div class="profile-left-col"><div style="width: 100%; height: 100%; opacity: 0.1; background: url('https://www.transparenttextures.com/patterns/stardust.png');"></div></div>
<div class="profile-right-col"><div class="profile-section-header">Insigne Équipé</div><div class="badge-info-section">
<?php if (!empty($_SESSION['selected_badge_image'])): ?><img src="<?php echo htmlspecialchars($_SESSION['selected_badge_image']); ?>?v=<?php echo time(); ?>" class="badge-img-display" title="<?php echo htmlspecialchars($_SESSION['selected_badge_name'] ?? ''); ?>"><span class="badge-name-display"><?php echo htmlspecialchars($_SESSION['selected_badge_name'] ?? ''); ?></span>
<?php else: ?><div style="width: 80px; height: 80px; display: flex; align-items: center; justify-content: center; opacity: 0.2; margin-bottom: 15px;"><i class="fa-solid fa-medal fa-3x"></i></div><span class="badge-name-display" style="opacity: 0.5; font-style: italic;">Aucun insigne</span><?php endif; ?>
</div></div>
</div>
</div>
</div>
</div>
</body>
</html>