38676-vm/gm_console.php
2026-02-26 03:04:39 +00:00

281 lines
28 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';
session_start();
$db = db();
// Auth Check: Must be logged in and be admin or gm
if (!isset($_SESSION['user_id'])) {
header("Location: auth.php?page=login");
exit;
}
$user_id = $_SESSION['user_id'];
$user_stmt = $db->prepare("SELECT role FROM users WHERE id = ?");
$user_stmt->execute([$user_id]);
$current_user = $user_stmt->fetch();
if (!$current_user || ($current_user['role'] !== 'admin' && $current_user['role'] !== 'gm')) {
die("Accès refusé. Vous devez être un Maître du Jeu (MJ) pour accéder à cette console.");
}
$is_admin = ($current_user['role'] === 'admin');
// Fetch Dynamic Types, Statuses, Profiles, Settlement Types, and Factions
$object_types_db = $db->query("SELECT * FROM celestial_object_types ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
$statuses_db = $db->query("SELECT * FROM celestial_object_statuses ORDER BY id ASC")->fetchAll(PDO::FETCH_ASSOC);
$status_profiles_db = $db->query("SELECT * FROM celestial_object_status_profiles WHERE enabled = 1 ORDER BY priority DESC, name ASC")->fetchAll(PDO::FETCH_ASSOC);
$settlement_types_db = $db->query("SELECT * FROM settlement_types ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
$factions_db = $db->query("SELECT * FROM factions ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
$object_types_map = []; foreach($object_types_db as $ot) $object_types_map[$ot['slug']] = $ot;
$statuses_map = []; foreach($statuses_db as $s) $statuses_map[$s['slug']] = $s;
$factions_map = []; foreach($factions_db as $f) $factions_map[$f['id']] = $f;
function resolvePlanetStatus($planet, $profiles, $statuses_db, $object_types_map) {
// 1. Determine which profile to use (Individual first, then Type default)
$profile_id = $planet['status_profile_id'] ?: ($object_types_map[$planet['type']]['status_profile_id'] ?? null);
if (!empty($profile_id)) {
foreach ($profiles as $prof) {
if ($prof['id'] == $profile_id) {
$config = json_decode($prof['config'], true);
if (isset($config['rules']) && is_array($config['rules'])) {
foreach ($config['rules'] as $rule) {
$match = false; $cond = $rule['condition_type'];
if ($cond === 'fixed') $match = true;
elseif ($cond === 'orbital_control') { $val = (float)($planet['orbital_control'] ?? 0); if ($val >= ($rule['min_value'] ?? 0) && $val <= ($rule['max_value'] ?? 100)) $match = true; }
elseif ($cond === 'terrestrial_control') { $val = (float)($planet['terrestrial_control'] ?? 0); if ($val >= ($rule['min_value'] ?? 0) && $val <= ($rule['max_value'] ?? 100)) $match = true; }
elseif ($cond === 'uncontrolled') { if ((float)($planet['orbital_control'] ?? 0) == 0 && (float)($planet['terrestrial_control'] ?? 0) == 0) $match = true; }
if ($match) {
foreach ($statuses_db as $s) {
if ($s['id'] == $rule['status_id']) return $s['slug'];
}
}
}
}
break;
}
}
}
return $planet['status'];
}
// Handle Planet/Slot Update
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update_slot') {
$slot_id = (int)($_POST['slot_id'] ?? 0);
$galaxy_id = (int)($_POST['galaxy_id'] ?? 1);
$sector_id = (int)($_POST['sector_id'] ?? 1);
$slot_num = (int)($_POST['slot_num'] ?? 0);
$name = $_POST['name'] ?? 'Inconnu';
$type = $_POST['type'] ?? 'empty';
$manual_status = $_POST['manual_status'] ?? '';
$status_profile_id = !empty($_POST['status_profile_id']) ? (int)$_POST['status_profile_id'] : null;
$orbital_controls = $_POST['orbital_controls'] ?? [];
$dominant_orbital_val = 0; foreach($orbital_controls as $fid => $val) { if ((int)$val > $dominant_orbital_val && (int)$fid != 1) $dominant_orbital_val = (int)$val; }
$status = 'sta_inhabited'; $faction_id = null; $total_non_aucun = 0; $active_factions = []; $num_cities = 0; $avg_terrestrial_control = 0;
if (isset($_POST['cities']) && is_array($_POST['cities'])) {
foreach ($_POST['cities'] as $city_data) {
if (empty($city_data['name'])) continue; $num_cities++;
if (isset($city_data['controls']) && is_array($city_data['controls'])) { foreach ($city_data['controls'] as $f_id => $lvl) { if ((int)$lvl > 0 && $f_id != 1) { $total_non_aucun += (int)$lvl; $active_factions[$f_id] = ($active_factions[$f_id] ?? 0) + (int)$lvl; $avg_terrestrial_control += (int)$lvl; } } }
}
}
if ($num_cities > 0) $avg_terrestrial_control = round($avg_terrestrial_control / $num_cities);
if ($num_cities > 0 && $total_non_aucun > 0) {
arsort($active_factions); $faction_id = (int)key($active_factions);
if (count($active_factions) > 1) { $status = 'sta_hostile'; } else { $status = ($total_non_aucun >= ($num_cities * 100)) ? 'sta_controlled' : 'sta_contested'; }
} else if ($type !== 'empty') { $status = 'sta_inhabited'; }
if (!empty($manual_status)) $status = $manual_status;
if ($type === 'empty') { if ($slot_id > 0) { $db->prepare("DELETE FROM cities WHERE planet_id = ?")->execute([$slot_id]); $db->prepare("DELETE FROM planet_faction_control WHERE planet_id = ?")->execute([$slot_id]); $db->prepare("DELETE FROM planets WHERE id = ?")->execute([$slot_id]); } }
else {
if ($slot_id > 0) { $db->prepare("UPDATE planets SET name = ?, type = ?, status = ?, faction_id = ?, orbital_control = ?, terrestrial_control = ?, status_profile_id = ? WHERE id = ?")->execute([$name, $type, $status, $faction_id, $dominant_orbital_val, $avg_terrestrial_control, $status_profile_id, $slot_id]); $planet_id = $slot_id; }
else { $db->prepare("INSERT INTO planets (galaxy_id, sector_id, slot, name, type, status, faction_id, orbital_control, terrestrial_control, status_profile_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")->execute([$galaxy_id, $sector_id, $slot_num, $name, $type, $status, $faction_id, $dominant_orbital_val, $avg_terrestrial_control, $status_profile_id]); $planet_id = $db->lastInsertId(); }
$db->prepare("DELETE FROM planet_faction_control WHERE planet_id = ?")->execute([$planet_id]);
foreach($orbital_controls as $fid => $lvl) { if ((int)$lvl > 0) $db->prepare("INSERT INTO planet_faction_control (planet_id, faction_id, control_level) VALUES (?, ?, ?)")->execute([$planet_id, (int)$fid, (int)$lvl]); }
if (isset($_POST['cities']) && is_array($_POST['cities'])) {
$sent_city_ids = [];
foreach ($_POST['cities'] as $city_data) {
if (empty($city_data['name'])) continue; $c_id = (int)($city_data['id'] ?? 0);
if ($c_id > 0) { $db->prepare("UPDATE cities SET name = ?, settlement_type_id = ? WHERE id = ?")->execute([$city_data['name'], !empty($city_data['type_id'])?(int)$city_data['type_id']:null, $c_id]); $city_id = $c_id; }
else { $db->prepare("INSERT INTO cities (planet_id, name, settlement_type_id) VALUES (?, ?, ?)")->execute([$planet_id, $city_data['name'], !empty($city_data['type_id'])?(int)$city_data['type_id']:null]); $city_id = $db->lastInsertId(); }
$sent_city_ids[] = $city_id; $db->prepare("DELETE FROM city_faction_control WHERE city_id = ?")->execute([$city_id]);
if (isset($city_data['controls']) && is_array($city_data['controls'])) { foreach ($city_data['controls'] as $f_id => $l) { if ((int)$l > 0) $db->prepare("INSERT INTO city_faction_control (city_id, faction_id, control_level) VALUES (?, ?, ?)")->execute([$city_id, (int)$f_id, (int)$l]); } }
}
if ($planet_id > 0) { if (empty($sent_city_ids)) { $db->prepare("DELETE FROM cities WHERE planet_id = ?")->execute([$planet_id]); } else { $placeholders = implode(',', array_fill(0, count($sent_city_ids), '?')); $db->prepare("DELETE FROM cities WHERE planet_id = ? AND id NOT IN ($placeholders)")->execute(array_merge([$planet_id], $sent_city_ids)); } }
}
}
header("Location: gm_console.php?view=sector&galaxy_id=$galaxy_id&sector_id=$sector_id&success=1"); exit;
}
$view = isset($_GET['view']) ? $_GET['view'] : 'galaxy'; $galaxy_id = (int)($_GET['galaxy_id'] ?? 1); $sector_id = (int)($_GET['sector_id'] ?? 1); $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]);
$grid = array_fill(1, $grid_size, null); $planet_ids = [];
foreach ($stmt->fetchAll() as $obj) { $obj['status'] = resolvePlanetStatus($obj, $status_profiles_db, $statuses_db, $object_types_map); $grid[$obj['slot']] = $obj; $planet_ids[] = $obj['id']; $grid[$obj['slot']]['cities'] = []; $grid[$obj['slot']]['orbital_controls'] = []; }
if (!empty($planet_ids)) {
$p_list = implode(',', array_fill(0, count($planet_ids), '?'));
$stmt = $db->prepare("SELECT * FROM planet_faction_control WHERE planet_id IN ($p_list)"); $stmt->execute($planet_ids);
foreach ($stmt->fetchAll() as $ocr) { foreach ($grid as &$s) { if ($s && $s['id'] == $ocr['planet_id']) $s['orbital_controls'][$ocr['faction_id']] = $ocr['control_level']; } }
unset($s);
$stmt = $db->prepare("SELECT * FROM cities WHERE planet_id IN ($p_list)"); $stmt->execute($planet_ids);
$cities = $stmt->fetchAll(); $c_ids = array_column($cities, 'id');
if (!empty($c_ids)) {
$c_list = implode(',', array_fill(0, count($c_ids), '?'));
$c_stmt = $db->prepare("SELECT * FROM city_faction_control WHERE city_id IN ($c_list)"); $c_stmt->execute($c_ids);
$c_ctrls = []; foreach ($c_stmt->fetchAll() as $cr) $c_ctrls[$cr['city_id']][$cr['faction_id']] = $cr['control_level'];
foreach ($cities as $c) { $c['controls'] = $c_ctrls[$c['id']] ?? []; foreach ($grid as &$s) { if ($s && $s['id'] == $c['planet_id']) $s['cities'][] = $c; } }
unset($s);
}
}
$stmt = $db->prepare("SELECT name, status FROM sectors WHERE id = ?"); $stmt->execute([$sector_id]); $sector_info = $stmt->fetch();
} else {
$stmt = $db->prepare("SELECT id, sector_id, slot, status, type, orbital_control, terrestrial_control, status_profile_id FROM planets WHERE galaxy_id = ? ORDER BY sector_id, slot ASC"); $stmt->execute([$galaxy_id]);
$sector_data = []; foreach ($stmt->fetchAll() as $p) { $p['status'] = resolvePlanetStatus($p, $status_profiles_db, $statuses_db, $object_types_map); $sector_data[$p['sector_id']][$p['slot']] = ['status' => $p['status'], 'type' => $p['type']]; }
}
function getStatusColor($status, $type, $statuses_map) { if ($type === 'empty') return 'rgba(255,255,255,0.05)'; $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>Console MJ - Nexus</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: #0b0f19; color: #fff; font-family: 'Segoe UI', sans-serif; margin: 0; }
header { background: #1a202c; padding: 10px 20px; border-bottom: 2px solid #2d3545; display: flex; justify-content: space-between; align-items: center; }
.container { padding: 40px; display: flex; flex-direction: column; align-items: center; }
.galaxy-map { display: grid; grid-template-columns: repeat(6, 140px); gap: 10px; padding: 15px; background: rgba(10, 15, 30, 0.5); border: 1px solid #2d3545; }
.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: 0.2s; overflow: hidden; }
.slot:hover { background: rgba(136, 192, 208, 0.1); border-color: #88c0d0; }
.slot-id { position: absolute; top: 5px; left: 8px; font-size: 9px; color: #4c566a; font-weight: bold; }
.object-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90px; height: 90px; display: flex; align-items: center; justify-content: center; font-size: 90px; z-index: 2; transition: 0.3s; }
.object-image { width: 90px; height: 90px; object-fit: contain; }
.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 #000; }
.slot:hover .object-icon { transform: translate(-50%, -50%) scale(1.1); }
.faction-badge { position: absolute; top: 5px; right: 8px; width: 22px; height: 22px; border-radius: 50%; border: 1px solid #fff; display: flex; align-items: center; justify-content: center; z-index: 5; font-size: 10px; background: rgba(0,0,0,0.8); }
.building-badge { position: absolute; bottom: 25px; right: 8px; color: #ebcb8b; z-index: 5; font-size: 12px; text-shadow: 0 0 3px #000; }
#editModal, #sectorModal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 1000; align-items: center; justify-content: center; }
.modal-content { background: #1e293b; padding: 30px; border: 1px solid #88c0d0; width: 650px; max-height: 90vh; overflow-y: auto; border-radius: 8px; }
.form-group { margin-bottom: 20px; }
.form-group label { display: block; font-size: 12px; color: #8c92a3; margin-bottom: 8px; font-weight: bold; }
.form-group input, .form-group select, .form-group textarea { width: 100%; background: #0f172a; border: 1px solid #334155; color: #fff; padding: 10px; border-radius: 4px; }
.btn-save { background: #a3be8c; border: none; padding: 12px 25px; color: #000; font-weight: bold; cursor: pointer; border-radius: 4px; width: 100%; }
.btn-cancel { background: #4c566a; border: none; padding: 12px 25px; color: #fff; font-weight: bold; cursor: pointer; border-radius: 4px; width: 100%; margin-top: 10px; }
.settlement-item { background: #1e293b; border: 1px solid #334155; padding: 15px; margin-bottom: 10px; position: relative; border-radius: 6px; }
.btn-remove-settlement { position: absolute; right: 8px; top: 8px; background: #bf616a; color: #fff; border: none; width: 22px; height: 22px; cursor: pointer; border-radius: 50%; }
.btn-add-settlement { background: #81a1c1; color: #000; border: none; padding: 8px 15px; cursor: pointer; font-size: 11px; font-weight: bold; border-radius: 4px; width: 100%; margin-bottom: 15px; }
.control-bars { margin-top: 15px; display: flex; flex-direction: column; gap: 10px; border-top: 1px dashed #334155; padding-top: 10px; }
.control-bar-row { display: flex; align-items: center; gap: 10px; }
.control-bar-label { width: 100px; font-size: 11px; color: #eceff4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: flex; align-items: center; gap: 5px; }
.control-bar-input { flex: 1; height: 8px; background: #0f172a; border-radius: 4px; outline: none; -webkit-appearance: none; }
.control-bar-input::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; background: #88c0d0; border-radius: 50%; cursor: pointer; }
.control-bar-value { width: 35px; text-align: right; font-size: 11px; color: #88c0d0; font-weight: bold; }
.sector-grid { display: grid; grid-template-columns: 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; text-decoration: none; color: #fff; transition: 0.2s; width: 180px; height: 180px; box-sizing: border-box; }
.sector-card:hover { border-color: #88c0d0; background: #1a202c; transform: translateY(-3px); }
.mini-map { display: grid; grid-template-columns: repeat(6, 12px); gap: 4px; margin-bottom: 10px; background: #000; padding: 6px; }
.mini-dot { width: 12px; height: 12px; }
.faction-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
</style>
</head>
<body>
<header>
<div style="display: flex; align-items: center; gap: 20px;"><h2 style="margin: 0; color: #ebcb8b;"><i class="fa-solid fa-headset"></i> CONSOLE MJ</h2><nav style="display: flex; gap: 20px;"><a href="index.php" style="color: #88c0d0; text-decoration: none; font-size: 14px; font-weight: bold;"><i class="fa-solid fa-eye"></i> Vue Joueur</a><?php if ($is_admin): ?><a href="admin.php" style="color: #bf616a; text-decoration: none; font-size: 14px; font-weight: bold;"><i class="fa-solid fa-shield-halved"></i> Admin</a><?php endif; ?></nav></div>
</header>
<div class="container">
<?php if (isset($_GET["success"])): ?><div style="background: rgba(163, 190, 140, 0.2); border: 1px solid #a3be8c; color: #a3be8c; padding: 15px; border-radius: 4px; margin-bottom: 20px; width: 100%; max-width: 840px; text-align: center;"><i class="fa-solid fa-circle-check"></i> Succès !</div><?php endif; ?>
<?php if ($view === 'galaxy'): ?>
<div class="sector-grid">
<?php for($s=1; $s<=$grid_size; $s++): ?>
<a href="?view=sector&galaxy_id=<?php echo $galaxy_id; ?>&sector_id=<?php echo $s; ?>" class="sector-card">
<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'], $sector_data[$s][$p]['type'], $statuses_map); ?><div class="mini-dot" style="background-color: <?php echo $dotColor; ?>;"></div><?php endfor; ?></div>
<div style="font-size: 14px; font-weight: bold;">SECTEUR <?php echo $s; ?></div>
</a>
<?php endfor; ?>
</div>
<?php elseif ($view === 'sector'): ?>
<div class="galaxy-map">
<?php for($i=1; $i<=$grid_size; $i++): ?>
<div class="slot" onclick='editSlot(<?php echo $i; ?>, <?php echo json_encode($grid[$i] ?? null); ?>)'><span class="slot-id"><?php echo $i; ?></span><?php if (isset($grid[$i])): $obj = $grid[$i]; $type_info = $object_types_map[$obj['type']] ?? null; $fac = $factions_map[$obj['faction_id']] ?? null; ?>
<?php if ($fac && $obj['faction_id'] != 1): ?>
<div class="faction-badge" style="border-color: <?php echo $fac['color']; ?>; color: <?php echo $fac['color']; ?>;">
<i class="fa-solid <?php echo htmlspecialchars($fac['fa_icon'] ?: 'fa-flag'); ?>"></i>
</div>
<?php endif; ?>
<?php if (!empty($obj['cities'])): ?>
<div class="building-badge"><i class="fa-solid fa-city"></i></div>
<?php endif; ?>
<div class="object-icon"><?php $icon = $type_info['icon'] ?? 'fa-circle'; $color = getStatusColor($obj['status'], $obj['type'], $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.1;"><i class="fa-solid fa-plus"></i></div><?php endif; ?></div>
<?php endfor; ?>
</div>
<?php endif; ?>
</div>
<div id="editModal">
<div class="modal-content">
<h3 id="modalTitle">Éditer Case</h3>
<form method="POST"><input type="hidden" name="action" value="update_slot"><input type="hidden" name="slot_id" id="form_slot_id"><input type="hidden" name="slot_num" id="form_slot_num"><input type="hidden" name="galaxy_id" value="<?php echo $galaxy_id; ?>"><input type="hidden" name="sector_id" value="<?php echo $sector_id; ?>">
<div style="display: flex; gap: 15px;"><div class="form-group" style="flex: 2;"><label>Nom</label><input type="text" name="name" id="form_name"></div><div class="form-group" style="flex: 1;"><label>Type</label><select name="type" id="form_type" onchange="updateControlToggles()"><option value="empty">VIDE</option><?php foreach($object_types_db as $ot): ?><option value="<?php echo $ot['slug']; ?>"><?php echo $ot['name']; ?></option><?php endforeach; ?></select></div></div>
<div style="display: flex; gap: 15px;">
<div class="form-group" style="flex: 1;"><label>Statut Manuel</label><select name="manual_status" id="form_status"><option value="">-- Automatique --</option><?php foreach($statuses_db as $s): ?><option value="<?php echo $s["slug"]; ?>"><?php echo $s["name"]; ?></option><?php endforeach; ?></select></div>
<div class="form-group" style="flex: 1;"><label>Profil Automatique</label><select name="status_profile_id" id="form_profile_id"><option value="">-- Aucun --</option><?php foreach($status_profiles_db as $p): ?><option value="<?php echo $p["id"]; ?>"><?php echo $p["name"]; ?></option><?php endforeach; ?></select></div>
</div>
<div id="orbitalSectionWrapper" style="display:none; background: rgba(0,0,0,0.1); padding: 15px; border-radius: 6px; border: 1px solid #334155; margin-bottom: 20px;">
<h4 style="margin:0 0 10px 0; font-size:12px; color:#88c0d0;">ZONE ORBITALE</h4>
<div id="orbitalControlContainer" class="control-bars"></div>
</div>
<div id="terrestrialSectionWrapper" style="display:none; background: rgba(0,0,0,0.1); padding: 15px; border-radius: 6px; border: 1px solid #334155; margin-bottom: 20px;">
<h4 style="margin:0 0 10px 0; font-size:12px; color:#88c0d0;">ZONE TERRESTRE / AU SOL</h4>
<div id="settlementsContainer"></div>
<button type="button" class="btn-add-settlement" onclick="addSettlementRow()">+ AJOUTER ÉTABLISSEMENT</button>
</div>
<button type="submit" class="btn-save">ENREGISTRER</button><button type="button" class="btn-cancel" onclick="closeModal()">ANNULER</button>
</form>
</div>
</div>
<script>
let settlementIndex = 0; const settlementTypes = <?php echo json_encode($settlement_types_db); ?>; const typesMap = <?php echo json_encode($object_types_map); ?>; const allFactions = <?php echo json_encode($factions_db); ?>; const AUCUN_ID = 1;
function initOrbitalSliders(data = null) {
const container = document.getElementById('orbitalControlContainer'); container.innerHTML = '';
allFactions.forEach(f => {
let val = (data && data[f.id] !== undefined) ? parseInt(data[f.id]) : (f.id == AUCUN_ID ? 100 : 0);
const div = document.createElement('div'); div.className = 'control-bar-row';
div.innerHTML = `<div class="control-bar-label"><span class="faction-dot" style="background: ${f.color || '#808080'}"></span> ${f.name}</div><input type="range" name="orbital_controls[${f.id}]" class="control-bar-input orbital-slider" data-faction-id="${f.id}" min="0" max="100" value="${val}" oninput="handleSliderChangeGeneric('orbital-slider', ${f.id}, this.value)"><div class="control-bar-value" id="val_orbital_${f.id}">${val}%</div>`;
container.appendChild(div);
});
}
function addSettlementRow(data = null) {
const container = document.getElementById('settlementsContainer'); const index = settlementIndex++; const div = document.createElement('div'); div.className = 'settlement-item'; div.id = 'settlement_row_' + index;
let html = `<button type="button" class="btn-remove-settlement" onclick="document.getElementById('settlement_row_${index}').remove()">×</button><input type="hidden" name="cities[${index}][id]" value="${data ? data.id : 0}"><div style="display:flex; gap:10px; margin-bottom:10px;"><div style="flex:2"><label>Nom</label><input type="text" name="cities[${index}][name]" value="${data ? data.name : ''}"></div><div style="flex:1"><label>Type</label><select name="cities[${index}][type_id]">${settlementTypes.map(t => `<option value="${t.id}" ${data && data.settlement_type_id == t.id ? 'selected' : ''}>${t.name}</option>`).join('')}</select></div></div><div class="control-bars">`;
allFactions.forEach(f => {
let val = (data && data.controls && data.controls[f.id] !== undefined) ? parseInt(data.controls[f.id]) : (f.id == AUCUN_ID ? 100 : 0);
html += `<div class="control-bar-row"><div class="control-bar-label"><span class="faction-dot" style="background: ${f.color || '#808080'}"></span> ${f.name}</div><input type="range" name="cities[${index}][controls][${f.id}]" class="control-bar-input city-slider-${index}" data-faction-id="${f.id}" min="0" max="100" value="${val}" oninput="handleSliderChangeGeneric('city-slider-${index}', ${f.id}, this.value, ${index})"><div class="control-bar-value" id="val_${index}_${f.id}">${val}%</div></div>`;
});
div.innerHTML = html + '</div>'; container.appendChild(div);
}
function handleSliderChangeGeneric(className, changedFid, newVal, rowIdx = null) {
newVal = parseInt(newVal); const sliders = Array.from(document.querySelectorAll(`.${className}`)); let otherSum = 0; sliders.forEach(s => { if (parseInt(s.dataset.factionId) !== changedFid) otherSum += parseInt(s.value); });
let diff = (100 - newVal) - otherSum; if (diff !== 0) { const aucun = sliders.find(s => parseInt(s.dataset.factionId) === AUCUN_ID); if (aucun && parseInt(aucun.dataset.factionId) !== changedFid) { aucun.value = Math.max(0, Math.min(100, parseInt(aucun.value) + diff)); } }
sliders.forEach(s => { document.getElementById(rowIdx !== null ? `val_${rowIdx}_${s.dataset.factionId}` : `val_orbital_${s.dataset.factionId}`).innerText = s.value + '%'; });
}
function updateControlToggles() {
const type = document.getElementById('form_type').value; const typeInfo = typesMap[type] || { orbital_control_enabled: 0, terrestrial_control_enabled: 0 };
document.getElementById('orbitalSectionWrapper').style.display = (typeInfo.orbital_control_enabled == 1) ? 'block' : 'none';
document.getElementById('terrestrialSectionWrapper').style.display = (typeInfo.terrestrial_control_enabled == 1) ? 'block' : 'none';
}
function editSlot(num, data) {
document.getElementById('form_slot_num').value = num; document.getElementById('form_slot_id').value = data ? data.id : 0;
if (data) { document.getElementById('form_name').value = data.name; document.getElementById('form_type').value = data.type; document.getElementById('form_status').value = data.status; document.getElementById('form_profile_id').value = data.status_profile_id || ""; initOrbitalSliders(data.orbital_controls); document.getElementById('settlementsContainer').innerHTML = ''; settlementIndex = 0; if (data.cities) data.cities.forEach(c => addSettlementRow(c)); }
else { document.getElementById('form_name').value = ''; document.getElementById('form_type').value = 'empty'; document.getElementById('form_status').value = ''; document.getElementById('form_profile_id').value = ''; initOrbitalSliders(null); document.getElementById('settlementsContainer').innerHTML = ''; }
updateControlToggles(); document.getElementById('editModal').style.display = 'flex';
}
function closeModal() { document.getElementById('editModal').style.display = 'none'; }
</script>
</body></html>