38676-vm/admin.php
2026-02-26 09:27:45 +00:00

1781 lines
105 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
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') {
die("Accès refusé. Cette console est réservée aux Administrateurs.");
}
$tab = isset($_GET['tab']) ? $_GET['tab'] : 'users';
// --- HANDLERS ---
// Handle User Role Update
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update_user_role') {
$target_user_id = (int)$_POST['target_user_id'];
$new_role = $_POST['new_role'];
if (in_array($new_role, ['user', 'gm', 'admin'])) {
$stmt = $db->prepare("UPDATE users SET role = ? WHERE id = ?");
$stmt->execute([$new_role, $target_user_id]);
}
header("Location: admin.php?tab=users&success=1");
exit;
}
// Handle Celestial Object Type CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_object_type') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$slug = $_POST['slug'];
$icon = $_POST['icon'];
$description = $_POST['description'];
$status_profile_id = !empty($_POST['status_profile_id']) ? (int)$_POST['status_profile_id'] : null;
$modifier_ids = isset($_POST['modifiers']) ? $_POST['modifiers'] : [];
$image_url = null;
if ($id > 0) {
$stmt_img = $db->prepare("SELECT image_url FROM celestial_object_types WHERE id = ?");
$stmt_img->execute([$id]);
$image_url = $stmt_img->fetchColumn();
}
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$ext = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$filename = $slug . "_" . time() . "." . $ext;
$target = "assets/images/celestial/" . $filename;
if (move_uploaded_file($_FILES['image']['tmp_name'], $target)) {
$image_url = $target;
}
}
$orbital_enabled = isset($_POST["orbital_control_enabled"]) ? 1 : 0;
$terrestrial_enabled = isset($_POST["terrestrial_control_enabled"]) ? 1 : 0;
if ($id > 0) {
$stmt = $db->prepare("UPDATE celestial_object_types SET name = ?, slug = ?, icon = ?, description = ?, image_url = ?, orbital_control_enabled = ?, terrestrial_control_enabled = ?, status_profile_id = ? WHERE id = ?");
$stmt->execute([$name, $slug, $icon, $description, $image_url, $orbital_enabled, $terrestrial_enabled, $status_profile_id, $id]);
} else {
$stmt = $db->prepare("INSERT INTO celestial_object_types (name, slug, icon, description, image_url, orbital_control_enabled, terrestrial_control_enabled, status_profile_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$name, $slug, $icon, $description, $image_url, $orbital_enabled, $terrestrial_enabled, $status_profile_id]);
$id = $db->lastInsertId();
}
// Sync modifiers
$db->prepare("DELETE FROM celestial_object_type_modifiers WHERE celestial_object_type_id = ?")->execute([$id]);
if (!empty($modifier_ids)) {
$ins = $db->prepare("INSERT INTO celestial_object_type_modifiers (celestial_object_type_id, modifier_id) VALUES (?, ?)");
foreach ($modifier_ids as $mid) {
$ins->execute([$id, (int)$mid]);
}
}
header("Location: admin.php?tab=objects&success=1");
exit;
}
if (isset($_GET['delete_object'])) {
$id = (int)$_GET['delete_object'];
$db->prepare("DELETE FROM celestial_object_types WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=objects&success=1");
exit;
}
// Handle Status CRUD
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["action"]) && $_POST["action"] === "upsert_status") {
$id = (int)$_POST["id"];
$name = $_POST["name"];
$slug = $_POST["slug"];
$color = $_POST["color"];
$description = $_POST["description"];
// Gérer le clignotement
if (isset($_POST["is_blinking"]) && $_POST["is_blinking"] === "on") {
if (strpos($color, ";blink") === false) {
$color .= ";blink";
}
} else {
$color = str_replace(";blink", "", $color);
}
if ($id > 0) {
$stmt = $db->prepare("UPDATE celestial_object_statuses SET name = ?, slug = ?, color = ?, description = ? WHERE id = ?");
$stmt->execute([$name, $slug, $color, $description, $id]);
} else {
$stmt = $db->prepare("INSERT INTO celestial_object_statuses (name, slug, color, description) VALUES (?, ?, ?, ?)");
$stmt->execute([$name, $slug, $color, $description]);
}
header("Location: admin.php?tab=statuses&success=1");
exit;
}
if (isset($_GET['delete_status'])) {
$id = (int)$_GET['delete_status'];
$db->prepare("DELETE FROM celestial_object_statuses WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=statuses&success=1");
exit;
}
// Handle Status Profile CRUD
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["action"]) && $_POST["action"] === "upsert_status_profile") {
$id = (int)$_POST["id"];
$name = $_POST["name"];
$slug = $_POST["slug"];
if ($id > 0) {
$stmt = $db->prepare("UPDATE celestial_object_status_profiles SET name = ?, slug = ? WHERE id = ?");
$stmt->execute([$name, $slug, $id]);
} else {
$stmt = $db->prepare("INSERT INTO celestial_object_status_profiles (name, slug) VALUES (?, ?)");
$stmt->execute([$name, $slug]);
}
header("Location: admin.php?tab=statuses&success=1");
exit;
}
if (isset($_GET["delete_status_profile"])) {
$id = (int)$_GET["delete_status_profile"];
// Check if it is used
$count = $db->query("SELECT COUNT(*) FROM celestial_object_status_rules WHERE profile_id = $id")->fetchColumn();
$count2 = $db->query("SELECT COUNT(*) FROM celestial_object_types WHERE status_profile_id = $id")->fetchColumn();
if ($count == 0 && $count2 == 0) {
$db->prepare("DELETE FROM celestial_object_status_profiles WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=statuses&success=1");
} else {
header("Location: admin.php?tab=statuses&error=profile_in_use");
}
exit;
}
// Handle Status Rule CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_status_rule') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$status_id = (int)$_POST['status_id'];
$profile_id = (int)$_POST['profile_id'];
$priority = (int)$_POST['priority'];
$orbital_count_op = $_POST['orbital_count_op'] ?: null;
$orbital_count_val = $_POST['orbital_count_val'] !== '' ? (int)$_POST['orbital_count_val'] : null;
$terrestrial_count_op = $_POST['terrestrial_count_op'] ?: null;
$terrestrial_count_val = $_POST['terrestrial_count_val'] !== '' ? (int)$_POST['terrestrial_count_val'] : null;
$orbital_dominance = isset($_POST['orbital_dominance']) ? implode(',', (array)$_POST['orbital_dominance']) : null;
$terrestrial_dominance = isset($_POST['terrestrial_dominance']) ? implode(',', (array)$_POST['terrestrial_dominance']) : null;
$is_empty_case = isset($_POST['is_empty_case']) ? 1 : 0;
$combine_mode = $_POST['combine_mode'] ?? 'OR';
if ($id > 0) {
$stmt = $db->prepare("UPDATE celestial_object_status_rules SET name = ?, status_id = ?, profile_id = ?, priority = ?, orbital_count_op = ?, orbital_count_val = ?, terrestrial_count_op = ?, terrestrial_count_val = ?, orbital_dominance = ?, terrestrial_dominance = ?, is_empty_case = ?, combine_mode = ? WHERE id = ?");
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case, $combine_mode, $id]);
} else {
$stmt = $db->prepare("INSERT INTO celestial_object_status_rules (name, status_id, profile_id, priority, orbital_count_op, orbital_count_val, terrestrial_count_op, terrestrial_count_val, orbital_dominance, terrestrial_dominance, is_empty_case, combine_mode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case, $combine_mode]);
}
header("Location: admin.php?tab=statuses&success=1");
exit;
}
if (isset($_GET['delete_status_rule'])) {
$id = (int)$_GET['delete_status_rule'];
$db->prepare("DELETE FROM celestial_object_status_rules WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=statuses&success=1");
exit;
}
// Handle Settlement Type CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_settlement_type') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$slug = $_POST['slug'];
$description = $_POST['description'];
if ($id > 0) {
$stmt = $db->prepare("UPDATE settlement_types SET name = ?, slug = ?, description = ? WHERE id = ?");
$stmt->execute([$name, $slug, $description, $id]);
} else {
$stmt = $db->prepare("INSERT INTO settlement_types (name, slug, description) VALUES (?, ?, ?)");
$stmt->execute([$name, $slug, $description]);
}
header("Location: admin.php?tab=settlement_types&success=1");
exit;
}
if (isset($_GET['delete_settlement_type'])) {
$id = (int)$_GET['delete_settlement_type'];
$db->prepare("DELETE FROM settlement_types WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=settlement_types&success=1");
exit;
}
// Handle Modifiers CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_modifier') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$slug = $_POST['slug'];
$type = $_POST['type'];
$description = $_POST['description'];
if ($id > 0) {
$stmt = $db->prepare("UPDATE modifiers SET name = ?, slug = ?, type = ?, description = ? WHERE id = ?");
$stmt->execute([$name, $slug, $type, $description, $id]);
} else {
$stmt = $db->prepare("INSERT INTO modifiers (name, slug, type, description) VALUES (?, ?, ?, ?)");
$stmt->execute([$name, $slug, $type, $description]);
}
header("Location: admin.php?tab=modifiers&success=1");
exit;
}
if (isset($_GET['delete_modifier'])) {
$id = (int)$_GET['delete_modifier'];
$db->prepare("DELETE FROM modifiers WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=modifiers&success=1");
exit;
}
// Handle Faction CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_faction') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$slug = $_POST['slug'];
$fa_icon = $_POST['fa_icon'];
$color = $_POST['color'];
$image_url = null;
$alliance_ids = isset($_POST['alliances']) ? $_POST['alliances'] : [];
if ($id > 0) {
$stmt_img = $db->prepare("SELECT image_url FROM factions WHERE id = ?");
$stmt_img->execute([$id]);
$image_url = $stmt_img->fetchColumn();
}
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$ext = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$filename = "faction_" . time() . "." . $ext;
$target = "assets/images/factions/" . $filename;
if (move_uploaded_file($_FILES['image']['tmp_name'], $target)) {
$image_url = $target;
}
}
if ($id > 0) {
$stmt = $db->prepare("UPDATE factions SET name = ?, slug = ?, image_url = ?, fa_icon = ?, color = ? WHERE id = ?");
$stmt->execute([$name, $slug, $image_url, $fa_icon, $color, $id]);
} else {
$stmt = $db->prepare("INSERT INTO factions (name, slug, image_url, fa_icon, color) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$name, $slug, $image_url, $fa_icon, $color]);
$id = $db->lastInsertId();
}
// Handle Alliances (Reciprocal)
$db->prepare("DELETE FROM faction_alliances WHERE faction_id_1 = ? OR faction_id_2 = ?")->execute([$id, $id]);
foreach ($alliance_ids as $ally_id) {
$f1 = min((int)$id, (int)$ally_id);
$f2 = max((int)$id, (int)$ally_id);
if ($f1 === $f2) continue;
$db->prepare("INSERT IGNORE INTO faction_alliances (faction_id_1, faction_id_2) VALUES (?, ?)")->execute([$f1, $f2]);
}
header("Location: admin.php?tab=factions&success=1");
exit;
}
if (isset($_GET['delete_faction'])) {
$id = (int)$_GET['delete_faction'];
$db->prepare("DELETE FROM factions WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=factions&success=1");
exit;
}
// Handle Resource CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_resource') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$slug = $_POST['slug'];
$icon = $_POST['icon'];
$description = $_POST['description'];
$show_in_header = isset($_POST["show_in_header"]) ? 1 : 0;
$image_url = null;
if ($id > 0) {
$stmt_img = $db->prepare("SELECT image_url FROM game_resources WHERE id = ?");
$stmt_img->execute([$id]);
$image_url = $stmt_img->fetchColumn();
}
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$ext = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$filename = "res_" . $slug . "_" . time() . "." . $ext;
if (!is_dir("assets/images/resources")) {
mkdir("assets/images/resources", 0775, true);
}
$target = "assets/images/resources/" . $filename;
if (move_uploaded_file($_FILES['image']['tmp_name'], $target)) {
$image_url = $target;
}
}
if ($id > 0) {
$stmt = $db->prepare("UPDATE game_resources SET name = ?, slug = ?, icon = ?, description = ?, image_url = ?, show_in_header = ? WHERE id = ?");
$stmt->execute([$name, $slug, $icon, $description, $image_url, $show_in_header, $id]);
} else {
$stmt = $db->prepare("INSERT INTO game_resources (name, slug, icon, description, image_url, show_in_header) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$name, $slug, $icon, $description, $image_url, $show_in_header]);
}
header("Location: admin.php?tab=resources&success=1");
exit;
}
if (isset($_GET['delete_resource'])) {
$id = (int)$_GET['delete_resource'];
$db->prepare("DELETE FROM game_resources WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=resources&success=1");
exit;
}
// Handle Lootbox CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_lootbox') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$slug = $_POST['slug'];
$description = $_POST['description'];
if ($id > 0) {
$stmt = $db->prepare("UPDATE lootboxes SET name = ?, slug = ?, description = ? WHERE id = ?");
$stmt->execute([$name, $slug, $description, $id]);
} else {
$stmt = $db->prepare("INSERT INTO lootboxes (name, slug, description) VALUES (?, ?, ?)");
$stmt->execute([$name, $slug, $description]);
$id = $db->lastInsertId();
}
// Handle Rolls
$db->prepare("DELETE FROM lootbox_rolls WHERE lootbox_id = ?")->execute([$id]);
if (isset($_POST['rolls_count']) && is_array($_POST['rolls_count'])) {
$ins_roll = $db->prepare("INSERT INTO lootbox_rolls (lootbox_id, roll_count, probability) VALUES (?, ?, ?)");
foreach ($_POST['rolls_count'] as $idx => $rc) {
$prob = (float)$_POST['rolls_prob'][$idx];
if ($prob > 0) {
$ins_roll->execute([$id, (int)$rc, $prob]);
}
}
}
// Handle Items
$db->prepare("DELETE FROM lootbox_items WHERE lootbox_id = ?")->execute([$id]);
if (isset($_POST['item_slug']) && is_array($_POST['item_slug'])) {
$ins_item = $db->prepare("INSERT INTO lootbox_items (lootbox_id, resource_slug, probability, quantity_min, quantity_max, is_guaranteed) VALUES (?, ?, ?, ?, ?, ?)");
foreach ($_POST['item_slug'] as $idx => $islug) {
$is_guaranteed = isset($_POST['item_is_guaranteed'][$idx]) ? (int)$_POST['item_is_guaranteed'][$idx] : 0;
$iprob = $is_guaranteed ? 100.00 : (float)$_POST['item_prob'][$idx];
if ($is_guaranteed || $iprob > 0) {
$qmin = (int)$_POST['item_qmin'][$idx];
$qmax = (int)$_POST['item_qmax'][$idx];
$ins_item->execute([$id, $islug ?: null, $iprob, $qmin, $qmax, $is_guaranteed]);
}
}
}
header("Location: admin.php?tab=lootboxes&success=1");
exit;
}
if (isset($_GET['delete_lootbox'])) {
$id = (int)$_GET['delete_lootbox'];
$db->prepare("DELETE FROM lootboxes WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=lootboxes&success=1");
exit;
}
// Handle Project Log CRUD
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["action"]) && $_POST["action"] === "upsert_project_log") {
$id = (int)$_POST["id"];
$version = $_POST["version"];
$title = $_POST["title"];
$content_log = $_POST["content"];
if ($id > 0) {
$stmt = $db->prepare("UPDATE project_logs SET version = ?, title = ?, content = ? WHERE id = ?");
$stmt->execute([$version, $title, $content_log, $id]);
} else {
$stmt = $db->prepare("INSERT INTO project_logs (version, title, content) VALUES (?, ?, ?)");
$stmt->execute([$version, $title, $content_log]);
}
header("Location: admin.php?tab=project_logs&success=1");
exit;
}
if (isset($_GET["delete_project_log"])) {
$id = (int)$_GET["delete_project_log"];
$db->prepare("DELETE FROM project_logs WHERE id = ?")->execute([$id]);
header("Location: admin.php?tab=project_logs&success=1");
exit;
}
// --- DATA FETCHING ---
$users_list = [];
$objects_list = [];
$statuses_list = [];
$status_rules_list = [];
$status_profiles_list = [];
$settlement_types_list = [];
$modifiers_list = [];
$factions_list = [];
$resources_list = [];
$lootboxes_list = [];
$project_logs_list = [];
if ($tab === 'users') {
$users_list = $db->query("SELECT id, username, email, role FROM users ORDER BY username ASC")->fetchAll();
} elseif ($tab === 'objects') {
$objects_list = $db->query("SELECT * FROM celestial_object_types ORDER BY name ASC")->fetchAll();
foreach ($objects_list as &$obj) {
$stmt = $db->prepare("SELECT modifier_id FROM celestial_object_type_modifiers WHERE celestial_object_type_id = ?");
$stmt->execute([$obj['id']]);
$obj['modifier_ids'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
}
unset($obj);
$modifiers_list = $db->query("SELECT * FROM modifiers ORDER BY type, name ASC")->fetchAll();
$status_profiles_list = $db->query("SELECT * FROM celestial_object_status_profiles ORDER BY name ASC")->fetchAll();
} elseif ($tab === 'statuses') {
$statuses_list = $db->query("SELECT * FROM celestial_object_statuses ORDER BY name ASC")->fetchAll();
$status_rules_list = $db->query("SELECT r.*, s.name as status_name, p.name as profile_name FROM celestial_object_status_rules r JOIN celestial_object_statuses s ON r.status_id = s.id LEFT JOIN celestial_object_status_profiles p ON r.profile_id = p.id ORDER BY r.profile_id, r.priority DESC, r.name ASC")->fetchAll();
$status_profiles_list = $db->query("SELECT * FROM celestial_object_status_profiles ORDER BY name ASC")->fetchAll();
$factions_list = $db->query("SELECT * FROM factions ORDER BY name ASC")->fetchAll();
} elseif ($tab === 'settlement_types') {
$settlement_types_list = $db->query("SELECT * FROM settlement_types ORDER BY name ASC")->fetchAll();
} elseif ($tab === 'modifiers') {
$modifiers_list = $db->query("SELECT * FROM modifiers ORDER BY type, name ASC")->fetchAll();
} elseif ($tab === 'factions') {
$factions_list = $db->query("SELECT * FROM factions ORDER BY name ASC")->fetchAll();
foreach ($factions_list as &$f) {
$stmt = $db->prepare("SELECT faction_id_1 as ally_id FROM faction_alliances WHERE faction_id_2 = ? UNION SELECT faction_id_2 as ally_id FROM faction_alliances WHERE faction_id_1 = ?");
$stmt->execute([$f['id'], $f['id']]);
$f['alliance_ids'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
}
unset($f);
} elseif ($tab === 'resources') {
$resources_list = $db->query("SELECT * FROM game_resources ORDER BY name ASC")->fetchAll();
} elseif ($tab === 'project_logs') {
$project_logs_list = $db->query("SELECT * FROM project_logs ORDER BY created_at DESC")->fetchAll();
} elseif ($tab === 'lootboxes') {
$lootboxes_list = $db->query("SELECT * FROM lootboxes ORDER BY name ASC")->fetchAll();
$resources_list = $db->query("SELECT name, slug FROM game_resources ORDER BY name ASC")->fetchAll();
foreach ($lootboxes_list as &$lb) {
$stmt_r = $db->prepare("SELECT * FROM lootbox_rolls WHERE lootbox_id = ?");
$stmt_r->execute([$lb['id']]);
$lb['rolls'] = $stmt_r->fetchAll();
$stmt_i = $db->prepare("SELECT * FROM lootbox_items WHERE lootbox_id = ?");
$stmt_i->execute([$lb['id']]);
$lb['items'] = $stmt_i->fetchAll();
}
unset($lb);
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Console Admin - 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: #000; color: #fff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; }
header { background: #1a202c; padding: 10px 20px; border-bottom: 2px solid #2d3545; display: flex; justify-content: space-between; align-items: center; }
.nav-links a { color: #88c0d0; text-decoration: none; margin-right: 20px; font-weight: bold; font-size: 14px; }
.nav-links a:hover { color: #fff; }
.container { padding: 40px; max-width: 1400px; margin: 0 auto; }
.tabs { display: flex; gap: 5px; margin-bottom: 20px; border-bottom: 2px solid #2d3545; flex-wrap: wrap; }
.tab-link { padding: 10px 20px; text-decoration: none; color: #8c92a3; background: #0a0f1d; border: 1px solid #2d3545; border-bottom: none; font-weight: bold; font-size: 14px; }
.tab-link.active { background: #1a202c; color: #88c0d0; border-bottom: 2px solid #88c0d0; }
table { width: 100%; border-collapse: collapse; background: #0a0f1d; margin-top: 20px; }
th, td { border: 1px solid #2d3545; padding: 12px; text-align: left; }
th { background: #1a202c; color: #88c0d0; font-size: 13px; text-transform: uppercase; }
.form-card { background: #1e293b; padding: 20px; border: 1px solid #334155; margin-bottom: 30px; }
.form-group { margin-bottom: 15px; }
.form-group label { display: block; font-size: 12px; color: #8c92a3; margin-bottom: 5px; }
.form-group input, .form-group select, .form-group textarea { width: 100%; background: #0f172a; border: 1px solid #334155; color: #fff; padding: 8px; box-sizing: border-box; }
.btn { border: none; padding: 8px 15px; cursor: pointer; font-weight: bold; border-radius: 4px; font-size: 12px; }
.btn-add { background: #a3be8c; color: #000; }
.btn-edit { background: #ebcb8b; color: #000; }
.btn-del { background: #bf616a; color: #fff; text-decoration: none; }
.btn-ok { background: #88c0d0; color: #000; }
.success-msg { background: #a3be8c; color: #000; padding: 10px; margin-bottom: 20px; border-radius: 4px; font-weight: bold; }
.modifier-tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 10px; font-weight: bold; margin-right: 5px; margin-bottom: 5px; }
.tag-bonus { background: #a3be8c; color: #000; }
.tag-malus { background: #bf616a; color: #fff; }
.sub-form-row { display: flex; gap: 8px; margin-bottom: 5px; align-items: center; }
.sub-form-row .btn-del-row { flex: 0 0 30px; background: #bf616a; color: #fff; padding: 5px; border-radius: 4px; text-align: center; cursor: pointer; }
.sub-form-header { display: flex; gap: 8px; margin-bottom: 5px; font-size: 10px; color: #8c92a3; text-transform: uppercase; font-weight: bold; }
.sub-form-header .btn-del-row-placeholder { flex: 0 0 30px; }
/* Custom toggle switch */
.toggle-container { display: flex; align-items: center; gap: 5px; font-size: 9px; color: #8c92a3; flex: 0 0 100px; }
.switch { position: relative; display: inline-block; width: 40px; height: 20px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #334155; transition: .4s; border-radius: 20px; }
.slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; }
input:checked + .slider { background-color: #a3be8c; }
input:checked + .slider:before { transform: translateX(20px); }
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0.3; }
100% { opacity: 1; }
}
.blink-effect {
animation: blink 1s infinite;
}
/* Color picker custom style */
.color-group { display: flex; gap: 5px; }
.color-picker-input { width: 45px !important; height: 34px !important; padding: 2px !important; border: 1px solid #334155 !important; background: #0f172a !important; cursor: pointer; }
/* Multi-select dropdown */
.ms-container { position: relative; width: 100%; }
.ms-display {
background: #0f172a; border: 1px solid #334155; color: #fff; padding: 8px; cursor: pointer; min-height: 34px; box-sizing: border-box; font-size: 12px; display: flex; align-items: center; justify-content: space-between;
}
.ms-display:after { content: '▼'; font-size: 8px; color: #8c92a3; }
.ms-dropdown {
position: absolute; top: 100%; left: 0; right: 0; background: #1a202c; border: 1px solid #334155; z-index: 1000; display: none; max-height: 200px; overflow-y: auto; padding: 5px;
}
.ms-item { padding: 5px 8px; cursor: pointer; display: flex; align-items: center; gap: 8px; font-size: 11px; }
.ms-item:hover { background: #2d3545; }
.ms-item input { width: auto !important; }
</style>
</head>
<body>
<header>
<div style="display: flex; align-items: center; gap: 20px;">
<h2 style="margin: 0; color: #bf616a;"><i class="fa-solid fa-shield-halved"></i> CONSOLE ADMIN</h2>
<nav class="nav-links">
<a href="project_log.php"><i class="fa-solid fa-clipboard-list"></i> Journal</a> <a href="index.php"><i class="fa-solid fa-eye"></i> Vue Joueur</a>
<a href="gm_console.php"><i class="fa-solid fa-headset"></i> Console MJ</a>
</nav>
</div>
<div>
<span style="font-weight: bold; color: #88c0d0;"><?php echo htmlspecialchars($_SESSION['username']); ?></span>
</div>
</header>
<div class="container">
<?php if (isset($_GET['success'])): ?>
<div class="success-msg"><i class="fa-solid fa-check-circle"></i> Opération effectuée avec succès.</div>
<?php endif; ?>
<div class="tabs">
<a href="?tab=users" class="tab-link <?php echo $tab === 'users' ? 'active' : ''; ?>"><i class="fa-solid fa-users"></i> Utilisateurs</a>
<a href="?tab=objects" class="tab-link <?php echo $tab === 'objects' ? 'active' : ''; ?>"><i class="fa-solid fa-earth-europe"></i> Objets Célestes</a>
<a href="?tab=modifiers" class="tab-link <?php echo $tab === 'modifiers' ? 'active' : ''; ?>"><i class="fa-solid fa-bolt"></i> Bonus & Malus</a>
<a href="?tab=statuses" class="tab-link <?php echo $tab === 'statuses' ? 'active' : ''; ?>"><i class="fa-solid fa-signal"></i> Statuts / États</a>
<a href="?tab=settlement_types" class="tab-link <?php echo $tab === 'settlement_types' ? 'active' : ''; ?>"><i class="fa-solid fa-city"></i> Types d'Établissements</a>
<a href="?tab=factions" class="tab-link <?php echo $tab === 'factions' ? 'active' : ''; ?>"><i class="fa-solid fa-flag"></i> Factions</a>
<a href="?tab=resources" class="tab-link <?php echo $tab === 'resources' ? 'active' : ''; ?>"><i class="fa-solid fa-gem"></i> Ressources</a>
<a href="?tab=project_logs" class="tab-link <?php echo $tab === "project_logs" ? "active" : ""; ?>"><i class="fa-solid fa-clipboard-list"></i> Journal de Bord</a>
<a href="?tab=lootboxes" class="tab-link <?php echo $tab === 'lootboxes' ? 'active' : ''; ?>"><i class="fa-solid fa-box-open"></i> Lootboxes</a>
</div>
<?php if ($tab === 'users'): ?>
<h3 style="color: #88c0d0;">Gestion des Rôles</h3>
<table>
<thead>
<tr><th>Utilisateur</th><th>Email</th><th>Rôle Actuel</th><th>Nouveau Rôle</th></tr>
</thead>
<tbody>
<?php foreach ($users_list as $u): ?>
<tr>
<td><strong><?php echo htmlspecialchars($u['username']); ?></strong></td>
<td><?php echo htmlspecialchars($u['email']); ?></td>
<td>
<span style="background: <?php echo $u['role'] === 'admin' ? '#bf616a' : ($u['role'] === 'gm' ? '#ebcb8b' : '#4c566a'); ?>; padding: 2px 8px; border-radius: 10px; font-size: 11px; color: #000; font-weight: bold;">
<?php echo strtoupper($u['role']); ?>
</span>
</td>
<td>
<form method="POST" style="display: flex; gap: 10px;">
<input type="hidden" name="action" value="update_user_role">
<input type="hidden" name="target_user_id" value="<?php echo $u['id']; ?>">
<select name="new_role">
<option value="user" <?php echo $u['role'] === 'user' ? 'selected' : ''; ?>>Utilisateur</option>
<option value="gm" <?php echo $u['role'] === 'gm' ? 'selected' : ''; ?>>Maître du Jeu (MJ)</option>
<option value="admin" <?php echo $u['role'] === 'admin' ? 'selected' : ''; ?>>Administrateur</option>
</select>
<button type="submit" class="btn btn-ok">Modifier</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php elseif ($tab === 'objects'): ?>
<h3 style="color: #88c0d0;">Objets Célestes</h3>
<div class="form-card">
<h4>Ajouter / Modifier un Objet</h4>
<form method="POST" id="objectForm" enctype="multipart/form-data">
<input type="hidden" name="action" value="upsert_object_type">
<input type="hidden" name="id" id="obj_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 1;">
<label>Nom (Affichage)</label>
<input type="text" name="name" id="obj_name" required placeholder="Ex: Planète">
</div>
<div class="form-group" style="flex: 1;">
<label>Slug (Identifiant technique)</label>
<input type="text" name="slug" id="obj_slug" required placeholder="Ex: planet">
</div>
<div class="form-group" style="flex: 1;">
<label>Icône (FontAwesome)</label>
<input type="text" name="icon" id="obj_icon" required placeholder="Ex: fa-earth-europe">
</div>
<div class="form-group" style="flex: 1;">
<label>Image (PNG/JPG) - Optionnel</label>
<input type="file" name="image" accept="image/*">
</div>
</div>
<div style="display: flex; gap: 20px; margin-bottom: 15px;">
<div class="form-group" style="flex: 1; background: rgba(0,0,0,0.2); padding: 10px; border-radius: 4px; border: 1px solid #334155;">
<label style="color: #88c0d0; font-weight: bold;">Contrôles activés</label>
<div style="display: flex; gap: 20px; margin-top: 5px;">
<div style="display: flex; align-items: center; gap: 10px;">
<input type="checkbox" name="orbital_control_enabled" id="obj_orbital_enabled" checked style="width: auto;">
<label for="obj_orbital_enabled" style="margin-bottom: 0; cursor: pointer;">Orbital</label>
</div>
<div style="display: flex; align-items: center; gap: 10px;">
<input type="checkbox" name="terrestrial_control_enabled" id="obj_terrestrial_enabled" checked style="width: auto;">
<label for="obj_terrestrial_enabled" style="margin-bottom: 0; cursor: pointer;">Terrestre</label>
</div>
</div>
</div>
<div class="form-group" style="flex: 1; background: rgba(136, 192, 208, 0.1); padding: 10px; border-radius: 4px; border: 1px solid #88c0d0;">
<label style="color: #88c0d0; font-weight: bold;">Règle(s) à appliquer</label>
<select name="status_profile_id" id="obj_profile_id" style="margin-top: 5px;">
<option value="">(Aucune règle - Statut fixe)</option>
<?php foreach ($status_profiles_list as $p): ?>
<option value="<?php echo $p['id']; ?>"><?php echo htmlspecialchars($p['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div style="display: flex; gap: 20px;">
<div style="flex: 1;">
<label style="font-size: 12px; color: #8c92a3;">Bonus / Malus attribués</label>
<div style="background: #0f172a; border: 1px solid #334155; padding: 10px; max-height: 150px; overflow-y: auto; display: flex; flex-wrap: wrap; gap: 10px; margin-top: 5px;">
<?php foreach ($modifiers_list as $m): ?>
<label style="font-size: 11px; display: flex; align-items: center; gap: 5px; cursor: pointer;">
<input type="checkbox" name="modifiers[]" value="<?php echo $m['id']; ?>" class="modifier-checkbox" data-id="<?php echo $m['id']; ?>">
<span class="modifier-tag <?php echo $m['type'] === 'bonus' ? 'tag-bonus' : 'tag-malus'; ?>">
<?php echo htmlspecialchars($m['name']); ?>
</span>
</label>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="form-group" style="margin-top: 15px;">
<label>Description</label>
<textarea name="description" id="obj_desc" rows="2"></textarea>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER L'OBJET</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetObjectForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Visuel</th><th>Nom</th><th>Contrôles</th><th>Règles</th><th>Bonus/Malus</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($objects_list as $o): ?>
<tr>
<td style="text-align: center;">
<?php if (!empty($o['image_url'])): ?>
<img src="<?php echo htmlspecialchars($o['image_url']); ?>?v=<?php echo time(); ?>" style="max-width: 40px; max-height: 40px; display: block; margin: 0 auto;">
<?php else: ?>
<i class="fa-solid <?php echo htmlspecialchars($o['icon']); ?> fa-lg"></i>
<?php endif; ?>
</td>
<td><strong><?php echo htmlspecialchars($o['name']); ?></strong><br><small><code><?php echo htmlspecialchars($o['slug']); ?></code></small></td>
<td style="text-align: center;">
<div style="display: flex; flex-direction: column; gap: 4px; align-items: center;">
<span style="font-size: 10px; display: inline-flex; align-items: center; gap: 3px; padding: 2px 6px; border-radius: 4px; background: <?php echo $o['orbital_control_enabled'] ? 'rgba(163, 190, 140, 0.2)' : 'rgba(191, 97, 106, 0.2)'; ?>; color: <?php echo $o['orbital_control_enabled'] ? '#a3be8c' : '#bf616a'; ?>; border: 1px solid <?php echo $o['orbital_control_enabled'] ? '#a3be8c' : '#bf616a'; ?>; width: 90px; justify-content: center;">
<i class="fa-solid <?php echo $o['orbital_control_enabled'] ? 'fa-check' : 'fa-xmark'; ?>"></i> ORBITAL
</span>
<span style="font-size: 10px; display: inline-flex; align-items: center; gap: 3px; padding: 2px 6px; border-radius: 4px; background: <?php echo $o['terrestrial_control_enabled'] ? 'rgba(163, 190, 140, 0.2)' : 'rgba(191, 97, 106, 0.2)'; ?>; color: <?php echo $o['terrestrial_control_enabled'] ? '#a3be8c' : '#bf616a'; ?>; border: 1px solid <?php echo $o['terrestrial_control_enabled'] ? '#a3be8c' : '#bf616a'; ?>; width: 90px; justify-content: center;">
<i class="fa-solid <?php echo $o['terrestrial_control_enabled'] ? 'fa-check' : 'fa-xmark'; ?>"></i> TERRESTRE
</span>
</div>
</td>
<td>
<?php
$p_name = "<em>Fixe</em>";
foreach($status_profiles_list as $p) if($p['id'] == $o['status_profile_id']) $p_name = htmlspecialchars($p['name']);
echo $p_name;
?>
</td>
<td>
<?php
$stmt = $db->prepare("SELECT m.name, m.type FROM modifiers m JOIN celestial_object_type_modifiers cotm ON m.id = cotm.modifier_id WHERE cotm.celestial_object_type_id = ?");
$stmt->execute([$o['id']]);
$m_list = $stmt->fetchAll();
foreach ($m_list as $ml): ?>
<span class="modifier-tag <?php echo $ml['type'] === 'bonus' ? 'tag-bonus' : 'tag-malus'; ?>">
<?php echo htmlspecialchars($ml['name']); ?>
</span>
<?php endforeach; ?>
</td>
<td>
<button class="btn btn-edit" onclick='editObject(<?php echo json_encode($o, JSON_HEX_APOS); ?>)'>Editer</button>
<a href="?tab=objects&delete_object=<?php echo $o['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer cet objet ?')">Suppr</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php elseif ($tab === 'modifiers'): ?>
<h3 style="color: #88c0d0;">Gestion des Bonus & Malus</h3>
<div class="form-card">
<h4>Ajouter / Modifier un Modificateur</h4>
<form method="POST" id="modifierForm">
<input type="hidden" name="action" value="upsert_modifier">
<input type="hidden" name="id" id="mod_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 2;">
<label>Nom du Bonus/Malus</label>
<input type="text" name="name" id="mod_name" required placeholder="Ex: Chaleur Extrême">
</div>
<div class="form-group" style="flex: 1;">
<label>Slug</label>
<input type="text" name="slug" id="mod_slug" required placeholder="Ex: chaleur_extreme">
</div>
<div class="form-group" style="flex: 1;">
<label>Type</label>
<select name="type" id="mod_type">
<option value="bonus">Bonus</option>
<option value="malus">Malus</option>
</select>
</div>
</div>
<div class="form-group">
<label>Description (Effet en jeu)</label>
<textarea name="description" id="mod_desc" rows="2" placeholder="Ex: Vitesse de déplacement divisée par 2"></textarea>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetModifierForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Type</th><th>Nom</th><th>Description</th><th>Slug</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($modifiers_list as $m): ?>
<tr>
<td>
<span class="modifier-tag <?php echo $m['type'] === 'bonus' ? 'tag-bonus' : 'tag-malus'; ?>">
<?php echo strtoupper($m['type']); ?>
</span>
</td>
<td><strong><?php echo htmlspecialchars($m['name']); ?></strong></td>
<td><small><?php echo htmlspecialchars($m['description']); ?></small></td>
<td><code><?php echo htmlspecialchars($m['slug']); ?></code></td>
<td>
<button class="btn btn-edit" onclick='editModifier(<?php echo json_encode($m, JSON_HEX_APOS); ?>)'>Editer</button>
<a href="?tab=modifiers&delete_modifier=<?php echo $m['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer ce modificateur ?')">Suppr</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php elseif ($tab === 'statuses'): ?>
<h3 style="color: #88c0d0;">Statuts / États</h3>
<div style="display: flex; gap: 30px; align-items: flex-start;">
<!-- LEFT: Status Management -->
<div style="flex: 1;">
<div class="form-card">
<h4>Ajouter / Modifier un Statut</h4>
<form method="POST" id="statusForm">
<input type="hidden" name="action" value="upsert_status">
<input type="hidden" name="id" id="st_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 1;">
<label>Nom du Statut</label>
<input type="text" name="name" id="st_name" required>
</div>
<div class="form-group" style="flex: 1;">
<label>Slug</label>
<input type="text" name="slug" id="st_slug" required>
</div>
<div class="form-group" style="flex: 1;">
<label>Couleur</label>
<div class="color-group">
<input type="color" id="st_color_picker" class="color-picker-input" oninput="document.getElementById('st_color').value = this.value">
<input type="text" name="color" id="st_color" required placeholder="#ef4444" oninput="document.getElementById('st_color_picker').value = this.value">
</div>
</div>
<div class="form-group" style="flex: 0 0 100px;">
<label>Clignotement</label>
<label class="switch">
<input type="checkbox" name="is_blinking" id="st_is_blinking">
<span class="slider"></span>
</label>
</div>
</div>
<div class="form-group">
<label>Description</label>
<textarea name="description" id="st_desc" rows="2"></textarea>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER LE STATUT</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetStatusForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Couleur</th><th>Nom</th><th>Slug</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($statuses_list as $s): ?>
<tr>
<?php
$c = $s['color'];
$isBlink = strpos($c, ';blink') !== false;
$pureColor = str_replace(';blink', '', $c);
?>
<td><div class="<?php echo $isBlink ? 'blink-effect' : ''; ?>" style="width: 20px; height: 20px; background: <?php echo $pureColor; ?>; border: 1px solid #fff;"></div></td>
<td><strong><?php echo htmlspecialchars($s['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($s['slug']); ?></code></td>
<td>
<button class="btn btn-edit" onclick='editStatus(<?php echo json_encode($s, JSON_HEX_APOS); ?>)'>Editer</button>
<a href="?tab=statuses&delete_status=<?php echo $s['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer ce statut ?')">Suppr</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- RIGHT: Rules Management -->
<div style="flex: 1.5;">
<!-- PROFILE MANAGEMENT -->
<div class="form-card" style="border-color: #ebcb8b; margin-bottom: 20px;">
<h4 style="color: #ebcb8b;"><i class="fa-solid fa-layer-group"></i> PROFILS / GROUPES DE RÈGLES</h4>
<form method="POST" id="profileForm" style="display: flex; gap: 10px; align-items: flex-end;">
<input type="hidden" name="action" value="upsert_status_profile">
<input type="hidden" name="id" id="prof_id" value="0">
<div class="form-group" style="flex: 1; margin-bottom: 0;">
<label>Nom du Profil</label>
<input type="text" name="name" id="prof_name" required placeholder="Ex: Planètes Spéciales">
</div>
<div class="form-group" style="flex: 1; margin-bottom: 0;">
<label>Slug</label>
<input type="text" name="slug" id="prof_slug" required placeholder="Ex: planetes_speciales">
</div>
<button type="submit" class="btn btn-add" style="margin-bottom: 0;">ENREGISTRER</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff; margin-bottom: 0;" onclick="resetProfileForm()">ANNULER</button>
</form>
<div style="margin-top: 15px; display: flex; flex-wrap: wrap; gap: 10px;">
<?php foreach ($status_profiles_list as $p): ?>
<div style="background: rgba(235, 203, 139, 0.1); border: 1px solid #ebcb8b; padding: 5px 10px; border-radius: 4px; display: flex; align-items: center; gap: 10px;">
<strong><?php echo htmlspecialchars($p['name']); ?></strong> (<code><?php echo htmlspecialchars($p['slug']); ?></code>)
<div style="display: flex; gap: 5px;">
<i class="fa-solid fa-pen-to-square" style="cursor: pointer; color: #ebcb8b;" onclick='editProfile(<?php echo json_encode($p, JSON_HEX_APOS); ?>)'></i>
<a href="?tab=statuses&delete_status_profile=<?php echo $p['id']; ?>" onclick="return confirm('Supprimer ce profil ?')" style="color: #bf616a;"><i class="fa-solid fa-trash"></i></a>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="form-card" style="border-color: #88c0d0;">
<h4 style="color: #88c0d0;"><i class="fa-solid fa-gears"></i> CONFIGURATION DES RÈGLES</h4>
<form method="POST" id="ruleForm">
<input type="hidden" name="action" value="upsert_status_rule">
<input type="hidden" name="id" id="rule_id" value="0">
<div style="display: flex; gap: 15px; margin-bottom: 15px;">
<div class="form-group" style="flex: 1.5;">
<label>Nom de la règle</label>
<input type="text" name="name" id="rule_name" required placeholder="Ex: Occupation ennemie">
</div>
<div class="form-group" style="flex: 1;">
<label>Profile / Groupe</label>
<select name="profile_id" id="rule_profile_id" required>
<?php foreach ($status_profiles_list as $p): ?>
<option value="<?php echo $p['id']; ?>"><?php echo htmlspecialchars($p['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group" style="flex: 1;">
<label>Statut à appliquer</label>
<select name="status_id" id="rule_status_id" required>
<?php foreach ($statuses_list as $s): ?>
<option value="<?php echo $s['id']; ?>"><?php echo htmlspecialchars($s['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group" style="flex: 0.5;">
<label>Priorité</label>
<input type="number" name="priority" id="rule_priority" value="0">
</div>
</div>
<div style="background: rgba(0,0,0,0.2); padding: 15px; border-radius: 4px; border: 1px solid #334155; margin-bottom: 15px;">
<div style="display: flex; gap: 20px; align-items: stretch;">
<!-- COLONNE ORBITALE -->
<div style="flex: 1; display: flex; flex-direction: column; gap: 15px; padding-right: 15px; border-right: 1px dashed #334155;">
<div style="font-size: 11px; color: #88c0d0; font-weight: bold; text-align: center; border-bottom: 1px solid #334155; padding-bottom: 5px; margin-bottom: 5px;">EN ORBITE</div>
<div class="form-group" style="margin-bottom: 0;">
<label style="font-size: 10px;">Nombre de factions</label>
<div style="display: flex; gap: 5px;">
<select name="orbital_count_op" id="rule_orb_op" style="width: 70px;">
<option value="">-
</option>
<option value="=">=
</option><option value=">">>
</option><option value="<"><
</option>
<option value=">=">>=
</option><option value="<="><=
</option>
</select>
<input type="number" name="orbital_count_val" id="rule_orb_val" placeholder="0">
</div>
</div>
<div class="form-group" style="margin-bottom: 0;">
<label style="font-size: 10px;">Filtre Dominance</label>
<div class="ms-container" id="ms_orb">
<div class="ms-display" onclick="toggleMS('ms_orb_list')">Toutes / Peu importe</div>
<div class="ms-dropdown" id="ms_orb_list">
<label class="ms-item"><input type="checkbox" value="none" onchange="updateMSLabel('ms_orb')"> Aucune (Vide)</label>
<?php foreach($factions_list as $f): if($f['name'] !== 'Aucune'): ?>
<label class="ms-item"><input type="checkbox" value="<?php echo $f['id']; ?>" name="orbital_dominance[]" onchange="updateMSLabel('ms_orb')"> <?php echo htmlspecialchars($f['name']); ?></label>
<?php endif; endforeach; ?>
</div>
</div>
</div>
</div>
<!-- COLONNE COMBINAISON (MILIEU) -->
<div style="flex: 0 0 100px; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 10px; background: rgba(136, 192, 208, 0.05); border-radius: 8px; border: 1px solid rgba(136, 192, 208, 0.2); padding: 10px;">
<label style="font-size: 10px; color: #88c0d0; font-weight: bold; text-transform: uppercase;">Combinaison</label>
<select name="combine_mode" id="rule_combine" style="width: 100%; text-align: center; font-weight: bold; color: #ebcb8b; background: #2e3440; border-color: #88c0d0;">
<option value="OR">OU</option>
<option value="AND">ET</option>
</select>
<div style="font-size: 9px; color: #d8dee9; text-align: center; opacity: 0.7;">(Orbital) [?] (Sol)</div>
</div>
<!-- COLONNE SOL -->
<div style="flex: 1; display: flex; flex-direction: column; gap: 15px; padding-left: 15px; border-left: 1px dashed #334155;">
<div style="font-size: 11px; color: #88c0d0; font-weight: bold; text-align: center; border-bottom: 1px solid #334155; padding-bottom: 5px; margin-bottom: 5px;">AU SOL</div>
<div class="form-group" style="margin-bottom: 0;">
<label style="font-size: 10px;">Nombre de factions</label>
<div style="display: flex; gap: 5px;">
<select name="terrestrial_count_op" id="rule_terr_op" style="width: 70px;">
<option value="">-
</option>
<option value="=">=
</option><option value=">">>
</option><option value="<"><
</option>
<option value=">=">>=
</option><option value="<="><=
</option>
</select>
<input type="number" name="terrestrial_count_val" id="rule_terr_val" placeholder="0">
</div>
</div>
<div class="form-group" style="margin-bottom: 0;">
<label style="font-size: 10px;">Filtre Dominance</label>
<div class="ms-container" id="ms_terr">
<div class="ms-display" onclick="toggleMS('ms_terr_list')">Toutes / Peu importe</div>
<div class="ms-dropdown" id="ms_terr_list">
<label class="ms-item"><input type="checkbox" value="none" onchange="updateMSLabel('ms_terr')"> Aucune (Vide)</label>
<?php foreach($factions_list as $f): if($f['name'] !== 'Aucune'): ?>
<label class="ms-item"><input type="checkbox" value="<?php echo $f['id']; ?>" name="terrestrial_dominance[]" onchange="updateMSLabel('ms_terr')"> <?php echo htmlspecialchars($f['name']); ?></label>
<?php endif; endforeach; ?>
</div>
</div>
</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 10px; padding-top: 15px; margin-top: 15px; border-top: 1px solid #334155;">
<input type="checkbox" name="is_empty_case" id="rule_empty" style="width: auto;">
<label for="rule_empty" style="margin-bottom: 0; color: #ebcb8b;">Cas "CASE VIDE" (Aucune faction nulle part)</label>
</div>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER LA RÈGLE</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetRuleForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Profile</th><th>Priorité</th><th>Nom / Condition</th><th>Statut</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($status_rules_list as $r): ?>
<tr>
<td><span style="background: #3b4252; padding: 2px 6px; border-radius: 4px; font-size: 10px;"><?php echo htmlspecialchars($r['profile_name'] ?: 'Standard'); ?></span></td>
<td><code><?php echo $r['priority']; ?></code></td>
<td>
<strong><?php echo htmlspecialchars($r['name']); ?></strong><br>
<small style="color: #8c92a3; font-size: 10px;">
<?php
$orb_conds = [];
if($r['orbital_count_op']) $orb_conds[] = "Factions " . $r['orbital_count_op'] . " " . $r['orbital_count_val'];
if($r['orbital_dominance']) $orb_conds[] = "IN (" . $r['orbital_dominance'] . ")";
$terr_conds = [];
if($r['terrestrial_count_op']) $terr_conds[] = "Factions " . $r['terrestrial_count_op'] . " " . $r['terrestrial_count_val'];
if($r['terrestrial_dominance']) $terr_conds[] = "IN (" . $r['terrestrial_dominance'] . ")";
$final_parts = [];
if ($r['is_empty_case']) $final_parts[] = "Case Vide";
$orb_str = !empty($orb_conds) ? "Orbital (" . implode(' AND ', $orb_conds) . ")" : "";
$terr_str = !empty($terr_conds) ? "Ground (" . implode(' AND ', $terr_conds) . ")" : "";
if ($orb_str && $terr_str) {
$sep = ($r['combine_mode'] == 'AND') ? ' AND ' : ' OR ';
$final_parts[] = $orb_str . $sep . $terr_str;
} elseif ($orb_str) {
$final_parts[] = $orb_str;
} elseif ($terr_str) {
$final_parts[] = $terr_str;
}
echo !empty($final_parts) ? implode(' AND ', $final_parts) : '<em>Toujours vrai</em>';
?>
</small>
</td>
<td><span style="color: <?php echo str_replace(';blink','', $statuses_list[array_search($r['status_id'], array_column($statuses_list, 'id'))]['color'] ?? '#fff'); ?>; font-weight: bold;"><i class="fa-solid fa-circle" style="font-size: 8px;"></i> <?php echo htmlspecialchars($r['status_name']); ?></span></td>
<td>
<button class="btn btn-edit" onclick='editRule(<?php echo json_encode($r, JSON_HEX_APOS); ?>)'>Editer</button>
<a href="?tab=statuses&delete_status_rule=<?php echo $r['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer cette règle ?')">Suppr</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($tab === 'settlement_types'): ?>
<h3 style="color: #88c0d0;">Types d'Établissements</h3>
<div class="form-card">
<h4>Ajouter / Modifier un Type d'Établissement</h4>
<form method="POST" id="settlementTypeForm">
<input type="hidden" name="action" value="upsert_settlement_type">
<input type="hidden" name="id" id="set_t_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 1;">
<label>Nom</label>
<input type="text" name="name" id="set_t_name" required placeholder="Ex: Ville, Avant-poste...">
</div>
<div class="form-group" style="flex: 1;">
<label>Slug</label>
<input type="text" name="slug" id="set_t_slug" required placeholder="Ex: ville, avant_poste...">
</div>
</div>
<div class="form-group">
<label>Description</label>
<textarea name="description" id="set_t_desc" rows="2"></textarea>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetSettlementTypeForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Nom</th><th>Slug</th><th>Description</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($settlement_types_list as $st): ?>
<tr>
<td><strong><?php echo htmlspecialchars($st['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($st['slug']); ?></code></td>
<td><small><?php echo htmlspecialchars($st['description']); ?></small></td>
<td>
<button class="btn btn-edit" onclick='editSettlementType(<?php echo json_encode($st, JSON_HEX_APOS); ?>)'>Editer</button>
<a href="?tab=settlement_types&delete_settlement_type=<?php echo $st['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer ce type ?')">Suppr</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php elseif ($tab === 'factions'): ?>
<h3 style="color: #88c0d0;">Gestion des Factions</h3>
<div class="form-card">
<h4>Ajouter / Modifier une Faction</h4>
<form method="POST" id="factionForm" enctype="multipart/form-data">
<input type="hidden" name="action" value="upsert_faction">
<input type="hidden" name="id" id="fac_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 2;">
<label>Nom de la Faction</label>
<input type="text" name="name" id="fac_name" required placeholder="Ex: Fédération, Empire...">
</div>
<div class="form-group" style="flex: 1;">
<label>Slug</label>
<input type="text" name="slug" id="fac_slug" required placeholder="Ex: federation, empire...">
</div>
<div class="form-group" style="flex: 1;">
<label>Couleur</label>
<div class="color-group">
<input type="color" id="fac_color_picker" class="color-picker-input" oninput="document.getElementById('fac_color').value = this.value">
<input type="text" name="color" id="fac_color" required placeholder="#808080" oninput="document.getElementById('fac_color_picker').value = this.value">
</div>
</div>
<div class="form-group" style="flex: 1;">
<label>Icône (FontAwesome)</label>
<input type="text" name="fa_icon" id="fac_fa_icon" placeholder="Ex: fa-users">
</div>
<div class="form-group" style="flex: 1;">
<label>PNG (Prioritaire)</label>
<input type="file" name="image" accept="image/png">
</div>
</div>
<div class="form-group">
<label style="font-size: 12px; color: #8c92a3;">Alliances (Réciprocité automatique)</label>
<div style="background: #0f172a; border: 1px solid #334155; padding: 10px; max-height: 150px; overflow-y: auto; display: flex; flex-wrap: wrap; gap: 10px; margin-top: 5px;">
<?php foreach ($factions_list as $potential_ally): ?>
<label class="alliance-label" style="font-size: 11px; display: flex; align-items: center; gap: 5px; cursor: pointer;" data-id="<?php echo $potential_ally['id']; ?>">
<input type="checkbox" name="alliances[]" value="<?php echo $potential_ally['id']; ?>" class="alliance-checkbox" data-id="<?php echo $potential_ally['id']; ?>">
<span style="padding: 2px 8px; border-radius: 4px; background: #334155; color: #fff;">
<?php echo htmlspecialchars($potential_ally['name']); ?>
</span>
</label>
<?php endforeach; ?>
</div>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER LA FACTION</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetFactionForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Couleur</th><th>Visuel</th><th>Nom</th><th>Slug</th><th>Alliances</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($factions_list as $f): ?>
<tr>
<td><div style="width: 25px; height: 25px; border-radius: 50%; background: <?php echo htmlspecialchars($f['color'] ?? '#808080'); ?>; border: 1px solid #334155;"></div></td>
<td style="text-align: center;">
<?php if (!empty($f['image_url'])): ?>
<img src="<?php echo htmlspecialchars($f['image_url']); ?>?v=<?php echo time(); ?>" style="max-width: 40px; max-height: 40px;">
<?php elseif (!empty($f['fa_icon'])): ?>
<i class="fa-solid <?php echo htmlspecialchars($f['fa_icon']); ?> fa-lg" style="color: <?php echo htmlspecialchars($f['color'] ?? '#fff'); ?>;"></i>
<?php else: ?>
<i class="fa-solid fa-flag fa-lg" style="color: <?php echo htmlspecialchars($f['color'] ?? '#4c566a'); ?>;"></i>
<?php endif; ?>
</td>
<td><strong><?php echo htmlspecialchars($f['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($f['slug']); ?></code></td>
<td>
<small>
<?php
$allies = [];
foreach ($f['alliance_ids'] as $aid) {
foreach ($factions_list as $fl) {
if ($fl['id'] == $aid) {
$allies[] = '<span style="color: #a3be8c;">' . htmlspecialchars($fl['name']) . '</span>';
break;
}
}
}
echo !empty($allies) ? implode(', ', $allies) : '<em>Aucune</em>';
?>
</small>
</td>
<td>
<button class="btn btn-edit" onclick='editFaction(<?php echo json_encode($f, JSON_HEX_APOS); ?>)'>Editer</button>
<?php if ($f['name'] !== 'Aucune'): ?>
<a href="?tab=factions&delete_faction=<?php echo $f['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer cette faction ?')">Suppr</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php elseif ($tab === 'resources'): ?>
<h3 style="color: #88c0d0;">Gestion des Ressources</h3>
<div class="form-card">
<h4>Ajouter / Modifier une Ressource</h4>
<form method="POST" id="resourceForm" enctype="multipart/form-data">
<input type="hidden" name="action" value="upsert_resource">
<input type="hidden" name="id" id="res_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 2;">
<label>Nom de la Ressource</label>
<input type="text" name="name" id="res_name" required placeholder="Ex: Métal, Carburant, Crédits...">
</div>
<div class="form-group" style="flex: 1;">
<label>Slug (Identifiant technique)</label>
<input type="text" name="slug" id="res_slug" required placeholder="Ex: metal, fuel, credits...">
</div>
</div>
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 1;">
<label>Icône (FontAwesome)</label>
<input type="text" name="icon" id="res_icon" placeholder="Ex: fa-gem">
</div>
<div class="form-group" style="flex: 1;">
<label>Image (PNG/JPG) - Optionnel</label>
<input type="file" name="image" accept="image/*">
</div>
</div>
<div class="form-group">
<label>Description</label>
<textarea name="description" id="res_desc" rows="2"></textarea>
</div>
<div class="form-group">
<label class="switch-label" style="display: flex; align-items: center; gap: 10px; cursor: pointer;">
<input type="checkbox" name="show_in_header" id="res_show" value="1" style="width: 20px; height: 20px;">
<span>Afficher dans la barre du header des joueurs</span>
</label>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER LA RESSOURCE</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetResourceForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Visuel</th><th>Nom</th><th>Slug</th><th>Header?</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($resources_list as $r): ?>
<tr>
<td style="text-align: center;">
<?php if (!empty($r['image_url'])): ?>
<img src="<?php echo htmlspecialchars($r['image_url']); ?>?v=<?php echo time(); ?>" style="max-width: 40px; max-height: 40px;">
<?php elseif (!empty($r['icon'])): ?>
<i class="fa-solid <?php echo htmlspecialchars($r['icon']); ?> fa-lg"></i>
<?php else: ?>
<i class="fa-solid fa-gem fa-lg" style="color: #4c566a;"></i>
<?php endif; ?>
</td>
<td><strong><?php echo htmlspecialchars($r['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($r['slug']); ?></code></td>
<td style="text-align: center;">
<?php if ($r['show_in_header']): ?>
<i class="fa-solid fa-check-circle" style="color: #a3be8c;"></i>
<?php else: ?>
<i class="fa-solid fa-times-circle" style="color: #bf616a;"></i>
<?php endif; ?>
</td>
<td>
<button class="btn btn-edit" onclick='editResource(<?php echo json_encode($r, JSON_HEX_APOS); ?>)'>Editer</button>
<a href="?tab=resources&delete_resource=<?php echo $r['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer cette ressource ?')">Suppr</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php elseif ($tab === 'project_logs'): ?>
<h3 style="color: #88c0d0;">Journal de Bord (Versions)</h3>
<div class="form-card">
<h4>Ajouter / Modifier une Version</h4>
<form method="POST" id="logForm">
<input type="hidden" name="action" value="upsert_project_log">
<input type="hidden" name="id" id="log_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 1;">
<label>Version</label>
<input type="text" name="version" id="log_version" required placeholder="Ex: 1.0.1">
</div>
<div class="form-group" style="flex: 3;">
<label>Titre</label>
<input type="text" name="title" id="log_title" required placeholder="Ex: Mise à jour majeure">
</div>
</div>
<div class="form-group">
<label>Contenu / Description des changements</label>
<textarea name="content" id="log_content" rows="5" required placeholder="Détaillez les changements..."></textarea>
</div>
<button type="submit" class="btn btn-add">ENREGISTRER LA VERSION</button>
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetLogForm()">ANNULER</button>
</form>
</div>
<table>
<thead><tr><th>Version</th><th>Titre</th><th>Date</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($project_logs_list as $log): ?>
<tr>
<td><span class="version-badge" style="background:#88c0d0; color:#000; padding:2px 8px; border-radius:10px; font-weight:bold;">v<?php echo htmlspecialchars($log['version']); ?></span></td>
<td><strong><?php echo htmlspecialchars($log['title']); ?></strong></td>
<td style="font-size:12px; color:#8c92a3;"><?php echo date('d/m/Y H:i', strtotime($log['created_at'])); ?></td>
<td>
<button class="btn btn-ok" onclick='editLog(<?php echo htmlspecialchars(json_encode($log)); ?>)'>ÉDITER</button>
<a href="?tab=project_logs&delete_project_log=<?php echo $log['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer cette version ?')">SUPPR</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<script>
function editLog(log) {
document.getElementById('log_id').value = log.id;
document.getElementById('log_version').value = log.version;
document.getElementById('log_title').value = log.title;
document.getElementById('log_content').value = log.content;
}
function resetLogForm() {
document.getElementById('log_id').value = 0;
document.getElementById('logForm').reset();
}
function toggleMS(id) {
const d = document.getElementById(id);
d.style.display = d.style.display === 'block' ? 'none' : 'block';
}
function updateMSLabel(containerId) {
const container = document.getElementById(containerId);
const checkboxes = container.querySelectorAll('input[type="checkbox"]:checked');
const display = container.querySelector('.ms-display');
if (checkboxes.length === 0) {
display.innerText = "Toutes / Peu importe";
} else {
const labels = Array.from(checkboxes).map(cb => cb.parentElement.innerText.trim());
display.innerText = labels.join(', ');
}
}
document.addEventListener('click', function(e) {
if (!e.target.closest('.ms-container')) {
document.querySelectorAll('.ms-dropdown').forEach(d => d.style.display = 'none');
}
});
</script>
<?php elseif ($tab === 'lootboxes'): ?>
<h3 style="color: #88c0d0;">Système de Lootboxes</h3>
<div class="form-card">
<h4>Créer / Modifier une Lootbox</h4>
<form method="POST" id="lootboxForm">
<input type="hidden" name="action" value="upsert_lootbox">
<input type="hidden" name="id" id="lb_id" value="0">
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 2;">
<label>Nom de la Lootbox</label>
<input type="text" name="name" id="lb_name" required placeholder="Ex: Coffre Mystère">
</div>
<div class="form-group" style="flex: 1;">
<label>Slug</label>
<input type="text" name="slug" id="lb_slug" required placeholder="Ex: coffre_mystere">
</div>
</div>
<div class="form-group">
<label>Description</label>
<textarea name="description" id="lb_desc" rows="2"></textarea>
</div>
<div style="display: flex; gap: 20px; margin-top: 20px;">
<!-- ROLLS SECTION -->
<div style="flex: 0 0 350px; border: 1px solid #2d3545; padding: 15px; border-radius: 8px; background: #0f172a;">
<label style="color: #88c0d0; font-weight: bold; font-size: 14px; margin-bottom: 15px; display: block; border-bottom: 1px solid #2d3545; padding-bottom: 5px;">
Probabilité du nombre total d'objets
</label>
<div class="sub-form-header">
<div style="flex: 1;">Nb Total</div>
<div style="flex: 1;">Chance (%)</div>
<div class="btn-del-row-placeholder"></div>
</div>
<div id="rolls_container">
<!-- Dynamic rows for rolls -->
</div>
<button type="button" class="btn btn-ok" style="margin-top: 10px; width: 100%;" onclick="addRollRow()">+ Ajouter un palier</button>
</div>
<!-- ITEMS SECTION -->
<div style="flex: 1; border: 1px solid #2d3545; padding: 15px; border-radius: 8px; background: #0f172a;">
<label style="color: #88c0d0; font-weight: bold; font-size: 14px; margin-bottom: 15px; display: block; border-bottom: 1px solid #2d3545; padding-bottom: 5px;">
Objets en poule (Attribution direct ou pool aléatoire)
</label>
<div class="sub-form-header">
<div style="flex: 0 0 100px;">Type</div>
<div style="flex: 2;">Ressource / Objet</div>
<div style="flex: 1;" class="chance-header">Chance (%)</div>
<div style="flex: 0 0 70px;">Qté Min</div>
<div style="flex: 0 0 70px;">Qté Max</div>
<div class="btn-del-row-placeholder"></div>
</div>
<div id="items_container">
<!-- Dynamic rows for items -->
</div>
<button type="button" class="btn btn-ok" style="margin-top: 10px; width: 100%;" onclick="addItemRow()">+ Ajouter un objet</button>
</div>
</div>
<div style="margin-top: 30px; text-align: right;">
<button type="button" class="btn" style="background: #4c566a; color: #fff; margin-right: 10px;" onclick="resetLootboxForm()">ANNULER TOUT</button>
<button type="submit" class="btn btn-add" style="padding: 12px 30px;">ENREGISTRER LA CONFIGURATION</button>
</div>
</form>
</div>
<table>
<thead><tr><th>Nom</th><th>Slug</th><th>Objets Directs (100%)</th><th>Nb Total (%)</th><th>Pool Aléatoire (%)</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($lootboxes_list as $lb): ?>
<tr>
<td><strong><?php echo htmlspecialchars($lb['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($lb['slug']); ?></code></td>
<td>
<small>
<?php
$directs = array_filter($lb['items'], fn($i) => $i['is_guaranteed']);
foreach ($directs as $d): ?>
<div style="margin-bottom: 2px; color: #a3be8c;">
<i class="fa-solid fa-bolt"></i> <?php echo htmlspecialchars($d['resource_slug']); ?>
<span style="color: #8c92a3;">(Qté: <?php echo $d['quantity_min']; ?>-<?php echo $d['quantity_max']; ?>)</span>
</div>
<?php endforeach; if(empty($directs)) echo "<em>Aucun</em>"; ?>
</small>
</td>
<td>
<small>
<?php foreach ($lb['rolls'] as $r): ?>
<div style="margin-bottom: 2px;">
<span style="color: #88c0d0;"><?php echo $r['roll_count']; ?> objet(s)</span>:
<strong><?php echo $r['probability']; ?>%</strong>
</div>
<?php endforeach; ?>
</small>
</td>
<td>
<small>
<?php
$pool = array_filter($lb['items'], fn($i) => !$i['is_guaranteed']);
foreach ($pool as $i): ?>
<div style="margin-bottom: 2px;">
<?php echo $i['resource_slug'] ?: '<em style="color:#bf616a">(Rien)</em>'; ?>:
<strong><?php echo $i['probability']; ?>%</strong>
<span style="color: #8c92a3;">(Qté: <?php echo $i['quantity_min']; ?>-<?php echo $i['quantity_max']; ?>)</span>
</div>
<?php endforeach; ?>
</small>
</td>
<td>
<button class="btn btn-edit" onclick='editLootbox(<?php echo json_encode($lb, JSON_HEX_APOS); ?>)'>Editer</button>
<a href="?tab=lootboxes&delete_lootbox=<?php echo $lb['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer cette lootbox ?')">Suppr</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<script>
// --- SHARED RESOURCES ---
const resourcesList = <?php echo json_encode($resources_list); ?>;
function editObject(data) {
document.getElementById('obj_id').value = data.id;
document.getElementById('obj_name').value = data.name;
document.getElementById('obj_slug').value = data.slug;
document.getElementById('obj_icon').value = data.icon;
document.getElementById('obj_desc').value = data.description;
document.getElementById('obj_orbital_enabled').checked = data.orbital_control_enabled == 1;
document.getElementById('obj_terrestrial_enabled').checked = data.terrestrial_control_enabled == 1;
document.getElementById('obj_profile_id').value = data.status_profile_id || "";
document.querySelectorAll('.modifier-checkbox').forEach(cb => cb.checked = false);
if (data.modifier_ids) {
data.modifier_ids.forEach(mid => {
const cb = document.querySelector(`.modifier-checkbox[value="${mid}"]`);
if (cb) cb.checked = true;
});
}
window.scrollTo(0,0);
}
function resetObjectForm() { document.getElementById('objectForm').reset(); document.getElementById('obj_id').value = 0; document.querySelectorAll('.modifier-checkbox').forEach(cb => cb.checked = false); }
function editProfile(data) {
document.getElementById("prof_id").value = data.id;
document.getElementById("prof_name").value = data.name;
document.getElementById("prof_slug").value = data.slug;
}
function resetProfileForm() {
document.getElementById("prof_id").value = 0;
document.getElementById("prof_name").value = "";
document.getElementById("prof_slug").value = "";
}
function editStatus(data) {
document.getElementById("st_id").value = data.id;
document.getElementById("st_name").value = data.name;
document.getElementById("st_slug").value = data.slug;
let color = data.color || "#000000";
let isBlinking = color.includes(";blink");
let pureColor = color.replace(";blink", "");
document.getElementById("st_color").value = pureColor;
document.getElementById("st_is_blinking").checked = isBlinking;
if (document.getElementById("st_color_picker")) {
document.getElementById("st_color_picker").value = pureColor.startsWith("#") ? pureColor : "#000000";
}
document.getElementById("st_desc").value = data.description;
window.scrollTo(0,0);
}
function resetStatusForm() {
document.getElementById("statusForm").reset();
document.getElementById("st_id").value = 0;
document.getElementById("st_color_picker").value = "#000000";
document.getElementById("st_is_blinking").checked = false;
}
function editRule(data) {
document.getElementById('rule_id').value = data.id;
document.getElementById('rule_name').value = data.name;
document.getElementById('rule_profile_id').value = data.profile_id || "";
document.getElementById('rule_status_id').value = data.status_id;
document.getElementById('rule_priority').value = data.priority || 0;
document.getElementById('rule_orb_op').value = data.orbital_count_op || "";
document.getElementById('rule_orb_val').value = data.orbital_count_val !== null ? data.orbital_count_val : "";
document.getElementById('rule_terr_op').value = data.terrestrial_count_op || "";
document.getElementById('rule_terr_val').value = data.terrestrial_count_val !== null ? data.terrestrial_count_val : "";
// Set multi-selects
const orbVals = (data.orbital_dominance || "").split(",");
document.querySelectorAll('#ms_orb_list input').forEach(cb => {
cb.checked = orbVals.includes(cb.value);
});
updateMSLabel('ms_orb');
const terrVals = (data.terrestrial_dominance || "").split(",");
document.querySelectorAll('#ms_terr_list input').forEach(cb => {
cb.checked = terrVals.includes(cb.value);
});
updateMSLabel('ms_terr');
document.getElementById('rule_empty').checked = data.is_empty_case == 1;
document.getElementById('rule_combine').value = data.combine_mode || "OR";
window.scrollTo(0,0);
}
function resetRuleForm() {
document.getElementById('ruleForm').reset();
document.getElementById('rule_id').value = 0; document.getElementById('rule_combine').value = 'OR';
updateMSLabel('ms_orb');
updateMSLabel('ms_terr');
}
function editSettlementType(data) {
document.getElementById('set_t_id').value = data.id;
document.getElementById('set_t_name').value = data.name;
document.getElementById('set_t_slug').value = data.slug;
document.getElementById('set_t_desc').value = data.description;
window.scrollTo(0,0);
}
function resetSettlementTypeForm() { document.getElementById('settlementTypeForm').reset(); document.getElementById('set_t_id').value = 0; }
function editModifier(data) {
document.getElementById('mod_id').value = data.id;
document.getElementById('mod_name').value = data.name;
document.getElementById('mod_slug').value = data.slug || '';
document.getElementById('mod_type').value = data.type;
document.getElementById('mod_desc').value = data.description;
window.scrollTo(0,0);
}
function resetModifierForm() { document.getElementById('modifierForm').reset(); document.getElementById('mod_id').value = 0; }
function editFaction(data) {
document.getElementById('fac_id').value = data.id;
document.getElementById('fac_name').value = data.name;
document.getElementById('fac_slug').value = data.slug || '';
const color = data.color || '#808080';
document.getElementById('fac_color').value = color;
if (document.getElementById('fac_color_picker')) {
document.getElementById('fac_color_picker').value = color.startsWith('#') ? color : '#808080';
}
document.getElementById('fac_fa_icon').value = data.fa_icon || '';
// Handle Alliances
document.querySelectorAll('.alliance-checkbox').forEach(cb => cb.checked = false);
document.querySelectorAll('.alliance-label').forEach(lbl => lbl.style.display = 'flex');
// Hide current faction from alliance list
const currentLabel = document.querySelector(`.alliance-label[data-id="${data.id}"]`);
if (currentLabel) currentLabel.style.display = 'none';
if (data.alliance_ids) {
data.alliance_ids.forEach(aid => {
const cb = document.querySelector(`.alliance-checkbox[value="${aid}"]`);
if (cb) cb.checked = true;
});
}
window.scrollTo(0,0);
}
function resetFactionForm() {
document.getElementById('factionForm').reset();
document.getElementById('fac_id').value = 0;
document.getElementById('fac_color').value = '#808080';
document.getElementById('fac_color_picker').value = '#808080';
document.querySelectorAll('.alliance-checkbox').forEach(cb => cb.checked = false);
document.querySelectorAll('.alliance-label').forEach(lbl => lbl.style.display = 'flex');
}
function editResource(data) {
document.getElementById('res_id').value = data.id;
document.getElementById('res_name').value = data.name;
document.getElementById('res_slug').value = data.slug;
document.getElementById('res_icon').value = data.icon || '';
document.getElementById('res_desc').value = data.description || '';
document.getElementById('res_show').checked = (data.show_in_header == 1);
window.scrollTo(0,0);
}
function resetResourceForm() { document.getElementById('resourceForm').reset(); document.getElementById('res_id').value = 0; }
// --- LOOTBOX SYSTEM ---
function addRollRow(count = 1, prob = 100) {
const container = document.getElementById('rolls_container');
const row = document.createElement('div');
row.className = 'sub-form-row';
row.innerHTML = `
<input type="number" name="rolls_count[]" value="${count}" placeholder="Nb total" min="0">
<input type="number" name="rolls_prob[]" value="${prob}" placeholder="Chance %" step="0.01">
<div class="btn-del-row" onclick="this.parentElement.remove()">×</div>
`;
container.appendChild(row);
}
function toggleItemType(cb) {
const row = cb.closest('.sub-form-row');
const probInput = row.querySelector('.item-prob-input');
const typeLabel = row.querySelector('.type-label');
if (cb.checked) {
probInput.style.visibility = 'hidden';
probInput.value = 100;
typeLabel.textContent = 'DIRECT';
typeLabel.style.color = '#a3be8c';
} else {
probInput.style.visibility = 'visible';
typeLabel.textContent = 'POULE';
typeLabel.style.color = '#8c92a3';
}
}
function addItemRow(slug = '', prob = 0, qmin = 1, qmax = 1, isGuaranteed = 0) {
const container = document.getElementById('items_container');
const rowIdx = container.children.length;
const row = document.createElement('div');
row.className = 'sub-form-row';
let options = '<option value="">(Rien)</option>';
resourcesList.forEach(r => {
options += `<option value="${r.slug}" ${slug === r.slug ? 'selected' : ''}>${r.name}</option>`;
});
row.innerHTML = `
<div class="toggle-container">
<label class="switch">
<input type="hidden" name="item_is_guaranteed[${rowIdx}]" value="0">
<input type="checkbox" name="item_is_guaranteed[${rowIdx}]" value="1" ${isGuaranteed ? 'checked' : ''} onchange="toggleItemType(this)">
<span class="slider"></span>
</label>
<span class="type-label" style="color: ${isGuaranteed ? '#a3be8c' : '#8c92a3'}">${isGuaranteed ? 'DIRECT' : 'POULE'}</span>
</div>
<select name="item_slug[${rowIdx}]" style="flex: 2;">${options}</select>
<input type="number" name="item_prob[${rowIdx}]" value="${prob}" class="item-prob-input" style="flex: 1; ${isGuaranteed ? 'visibility:hidden' : ''}" placeholder="Prob %" step="0.01">
<input type="number" name="item_qmin[${rowIdx}]" value="${qmin}" style="flex: 0 0 70px;" placeholder="Min">
<input type="number" name="item_qmax[${rowIdx}]" value="${qmax}" style="flex: 0 0 70px;" placeholder="Max">
<div class="btn-del-row" onclick="this.parentElement.remove()">×</div>
`;
container.appendChild(row);
}
function editLootbox(data) {
document.getElementById('lb_id').value = data.id;
document.getElementById('lb_name').value = data.name;
document.getElementById('lb_slug').value = data.slug;
document.getElementById('lb_desc').value = data.description || '';
document.getElementById('rolls_container').innerHTML = '';
if (data.rolls && data.rolls.length > 0) {
data.rolls.forEach(r => addRollRow(r.roll_count, r.probability));
} else {
addRollRow();
}
document.getElementById('items_container').innerHTML = '';
if (data.items && data.items.length > 0) {
data.items.forEach((i, idx) => addItemRow(i.resource_slug, i.probability, i.quantity_min, i.quantity_max, i.is_guaranteed));
} else {
addItemRow();
}
window.scrollTo(0,0);
}
function resetLootboxForm() {
document.getElementById('lootboxForm').reset();
document.getElementById('lb_id').value = 0;
document.getElementById('rolls_container').innerHTML = '';
document.getElementById('items_container').innerHTML = '';
addRollRow();
addItemRow();
}
<?php if ($tab === 'lootboxes'): ?>
window.onload = function() {
if (document.getElementById('rolls_container').children.length === 0) addRollRow();
if (document.getElementById('items_container').children.length === 0) addItemRow();
};
<?php endif; ?>
function toggleMS(id) {
const d = document.getElementById(id);
d.style.display = d.style.display === 'block' ? 'none' : 'block';
}
function updateMSLabel(containerId) {
const container = document.getElementById(containerId);
const checkboxes = container.querySelectorAll('input[type="checkbox"]:checked');
const display = container.querySelector('.ms-display');
if (checkboxes.length === 0) {
display.innerText = "Toutes / Peu importe";
} else {
const labels = Array.from(checkboxes).map(cb => cb.parentElement.innerText.trim());
display.innerText = labels.join(', ');
}
}
document.addEventListener('click', function(e) {
if (!e.target.closest('.ms-container')) {
document.querySelectorAll('.ms-dropdown').forEach(d => d.style.display = 'none');
}
});
</script>
</body>
</html>