Autosave: 20260222-222009

This commit is contained in:
Flatlogic Bot 2026-02-22 22:20:10 +00:00
parent 1bb89f9b7e
commit e33f37b2a1
10 changed files with 741 additions and 88 deletions

474
admin.php
View File

@ -143,15 +143,16 @@ if (isset($_GET['delete_settlement_type'])) {
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 = ?, type = ?, description = ? WHERE id = ?");
$stmt->execute([$name, $type, $description, $id]);
$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, type, description) VALUES (?, ?, ?)");
$stmt->execute([$name, $type, $description]);
$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;
@ -168,6 +169,7 @@ if (isset($_GET['delete_modifier'])) {
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'];
$image_url = null;
if ($id > 0) {
@ -184,11 +186,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
}
}
if ($id > 0) {
$stmt = $db->prepare("UPDATE factions SET name = ?, image_url = ?, fa_icon = ? WHERE id = ?");
$stmt->execute([$name, $image_url, $fa_icon, $id]);
$stmt = $db->prepare("UPDATE factions SET name = ?, slug = ?, image_url = ?, fa_icon = ? WHERE id = ?");
$stmt->execute([$name, $slug, $image_url, $fa_icon, $id]);
} else {
$stmt = $db->prepare("INSERT INTO factions (name, image_url, fa_icon) VALUES (?, ?, ?)");
$stmt->execute([$name, $image_url, $fa_icon]);
$stmt = $db->prepare("INSERT INTO factions (name, slug, image_url, fa_icon) VALUES (?, ?, ?, ?)");
$stmt->execute([$name, $slug, $image_url, $fa_icon]);
}
header("Location: admin.php?tab=factions&success=1");
exit;
@ -201,6 +203,107 @@ if (isset($_GET['delete_faction'])) {
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'];
$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 = ? WHERE id = ?");
$stmt->execute([$name, $slug, $icon, $description, $image_url, $id]);
} else {
$stmt = $db->prepare("INSERT INTO game_resources (name, slug, icon, description, image_url) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$name, $slug, $icon, $description, $image_url]);
}
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;
}
// --- DATA FETCHING ---
$users_list = [];
$objects_list = [];
@ -208,12 +311,13 @@ $statuses_list = [];
$settlement_types_list = [];
$modifiers_list = [];
$factions_list = [];
$resources_list = [];
$lootboxes_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();
// For each object, get its modifiers
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']]);
@ -228,6 +332,20 @@ if ($tab === 'users') {
$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();
} elseif ($tab === 'resources') {
$resources_list = $db->query("SELECT * FROM game_resources ORDER BY name ASC")->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();
}
}
?>
@ -243,7 +361,7 @@ if ($tab === 'users') {
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: 1200px; margin: 0 auto; }
.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; }
@ -269,6 +387,21 @@ if ($tab === 'users') {
.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); }
</style>
</head>
<body>
@ -297,6 +430,8 @@ if ($tab === 'users') {
<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=lootboxes" class="tab-link <?php echo $tab === 'lootboxes' ? 'active' : ''; ?>"><i class="fa-solid fa-box-open"></i> Lootboxes</a>
</div>
<?php if ($tab === 'users'): ?>
@ -384,7 +519,7 @@ if ($tab === 'users') {
</div>
<table>
<thead><tr><th>Visuel</th><th>Nom</th><th>Slug</th><th>Bonus/Malus</th><th>Actions</th></tr></thead>
<thead><tr><th>Visuel</th><th>Nom</th><th>Bonus/Malus</th><th>Slug</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($objects_list as $o): ?>
<tr>
@ -396,7 +531,6 @@ if ($tab === 'users') {
<?php endif; ?>
</td>
<td><strong><?php echo htmlspecialchars($o['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($o['slug']); ?></code></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 = ?");
@ -408,6 +542,7 @@ if ($tab === 'users') {
</span>
<?php endforeach; ?>
</td>
<td><code><?php echo htmlspecialchars($o['slug']); ?></code></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>
@ -429,6 +564,10 @@ if ($tab === 'users') {
<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">
@ -447,7 +586,7 @@ if ($tab === 'users') {
</div>
<table>
<thead><tr><th>Type</th><th>Nom</th><th>Description</th><th>Actions</th></tr></thead>
<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>
@ -458,6 +597,7 @@ if ($tab === 'users') {
</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>
@ -569,6 +709,10 @@ if ($tab === 'users') {
<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>Icône (FontAwesome)</label>
<input type="text" name="fa_icon" id="fac_fa_icon" placeholder="Ex: fa-users">
@ -584,7 +728,7 @@ if ($tab === 'users') {
</div>
<table>
<thead><tr><th>Visuel</th><th>Nom</th><th>Actions</th></tr></thead>
<thead><tr><th>Visuel</th><th>Nom</th><th>Slug</th><th>Actions</th></tr></thead>
<tbody>
<?php foreach ($factions_list as $f): ?>
<tr>
@ -598,6 +742,7 @@ if ($tab === 'users') {
<?php endif; ?>
</td>
<td><strong><?php echo htmlspecialchars($f['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($f['slug']); ?></code></td>
<td>
<button class="btn btn-edit" onclick='editFaction(<?php echo json_encode($f, JSON_HEX_APOS); ?>)'>Editer</button>
<?php if ($f['name'] !== 'Aucune'): ?>
@ -608,20 +753,202 @@ if ($tab === 'users') {
<?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>
<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>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>
<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 === '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;
// Reset checkboxes
document.querySelectorAll('.modifier-checkbox').forEach(cb => cb.checked = false);
// Check assigned modifiers
if (data.modifier_ids) {
data.modifier_ids.forEach(mid => {
const cb = document.querySelector(`.modifier-checkbox[value="${mid}"]`);
@ -630,11 +957,7 @@ if ($tab === 'users') {
}
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 resetObjectForm() { document.getElementById('objectForm').reset(); document.getElementById('obj_id').value = 0; document.querySelectorAll('.modifier-checkbox').forEach(cb => cb.checked = false); }
function editStatus(data) {
document.getElementById('st_id').value = data.id;
@ -658,6 +981,7 @@ if ($tab === 'users') {
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);
@ -667,10 +991,116 @@ if ($tab === 'users') {
function editFaction(data) {
document.getElementById('fac_id').value = data.id;
document.getElementById('fac_name').value = data.name;
document.getElementById('fac_slug').value = data.slug || '';
document.getElementById('fac_fa_icon').value = data.fa_icon || '';
window.scrollTo(0,0);
}
function resetFactionForm() { document.getElementById('factionForm').reset(); document.getElementById('fac_id').value = 0; }
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 || '';
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; ?>
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,50 @@
<?php
require_once __DIR__ . '/config.php';
$db = db();
try {
echo "Starting migration to add database relationships...\n";
// 1. Ensure columns used as foreign keys have indexes
$db->exec("ALTER TABLE celestial_object_types MODIFY COLUMN slug VARCHAR(50) NOT NULL;");
$db->exec("ALTER TABLE celestial_object_statuses MODIFY COLUMN slug VARCHAR(50) NOT NULL;");
$db->exec("ALTER TABLE settlement_types MODIFY COLUMN slug VARCHAR(50) NOT NULL;");
// Ensure UNIQUE indexes exist for slugs being referenced
$db->exec("ALTER TABLE celestial_object_types ADD UNIQUE INDEX IF NOT EXISTS idx_types_slug (slug);");
$db->exec("ALTER TABLE celestial_object_statuses ADD UNIQUE INDEX IF NOT EXISTS idx_statuses_slug (slug);");
$db->exec("ALTER TABLE settlement_types ADD UNIQUE INDEX IF NOT EXISTS idx_settlement_types_slug (slug);");
// Ensure factions.id is indexed (it's the PK, so it is)
// 2. Add foreign keys to 'planets'
echo "Adding foreign keys to 'planets' table...\n";
// Clean up any rogue data first
$db->exec("UPDATE planets SET faction_id = NULL WHERE faction_id NOT IN (SELECT id FROM factions)");
// status and type cleanup was done in shell, but just in case
$db->exec("DELETE FROM planets WHERE status NOT IN (SELECT slug FROM celestial_object_statuses)");
$db->exec("DELETE FROM planets WHERE type NOT IN (SELECT slug FROM celestial_object_types)");
// Add Constraints
$db->exec("ALTER TABLE planets
ADD CONSTRAINT fk_planets_type FOREIGN KEY (type) REFERENCES celestial_object_types(slug) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_planets_status FOREIGN KEY (status) REFERENCES celestial_object_statuses(slug) ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT fk_planets_faction FOREIGN KEY (faction_id) REFERENCES factions(id) ON DELETE SET NULL;");
// 3. Add foreign keys to 'cities'
echo "Adding foreign keys to 'cities' table...\n";
$db->exec("UPDATE cities SET settlement_type_id = NULL WHERE settlement_type_id NOT IN (SELECT id FROM settlement_types)");
$db->exec("ALTER TABLE cities
ADD CONSTRAINT fk_cities_settlement_type FOREIGN KEY (settlement_type_id) REFERENCES settlement_types(id) ON DELETE SET NULL;");
// 4. Add foreign keys to 'celestial_object_type_modifiers'
// This table already has them (checked with SHOW CREATE TABLE)
echo "Migration completed successfully!\n";
} catch (PDOException $e) {
die("Migration failed: " . $e->getMessage() . "\n");
}

View File

@ -0,0 +1,25 @@
<?php
require_once 'db/config.php';
$db = db();
$sqls = [
"CREATE TABLE IF NOT EXISTS lootbox_guaranteed_items (
id INT AUTO_INCREMENT PRIMARY KEY,
lootbox_id INT NOT NULL,
resource_slug VARCHAR(255) NOT NULL,
quantity_min INT NOT NULL DEFAULT 1,
quantity_max INT NOT NULL DEFAULT 1,
FOREIGN KEY (lootbox_id) REFERENCES lootboxes(id) ON DELETE CASCADE,
FOREIGN KEY (resource_slug) REFERENCES game_resources(slug) ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
];
foreach ($sqls as $sql) {
try {
$db->exec($sql);
echo "Executed: " . substr($sql, 0, 50) . "...\n";
} catch (PDOException $e) {
echo "Error: " . $e->getMessage() . "\n";
}
}

View File

@ -0,0 +1,28 @@
<?php
require_once __DIR__ . '/config.php';
$db = db();
try {
// Add slug to factions table
$cols = $db->query("DESCRIBE factions")->fetchAll(PDO::FETCH_COLUMN);
if (!in_array('slug', $cols)) {
// Add slug after name
$db->exec("ALTER TABLE factions ADD COLUMN slug VARCHAR(100) NULL AFTER name");
echo "Column 'slug' added to 'factions' table.\n";
// Populate existing slugs with slugified names
$factions = $db->query("SELECT id, name FROM factions")->fetchAll(PDO::FETCH_ASSOC);
foreach ($factions as $f) {
$slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $f['name'])));
$stmt = $db->prepare("UPDATE factions SET slug = ? WHERE id = ?");
$stmt->execute([$slug, $f['id']]);
}
echo "Existing slugs populated.\n";
} else {
echo "Column 'slug' already exists in 'factions' table.\n";
}
} catch (PDOException $e) {
die("Migration failed: " . $e->getMessage());
}

View File

@ -0,0 +1,29 @@
<?php
require_once __DIR__ . '/config.php';
$pdo = db();
try {
// Add slug column to modifiers table if it doesn't exist
$pdo->exec("ALTER TABLE modifiers ADD COLUMN slug VARCHAR(100) AFTER name");
echo "Column 'slug' added to 'modifiers' table.\n";
// Populate initial slugs based on names
$stmt = $pdo->query("SELECT id, name FROM modifiers");
$modifiers = $stmt->fetchAll(PDO::FETCH_ASSOC);
$updateStmt = $pdo->prepare("UPDATE modifiers SET slug = ? WHERE id = ?");
foreach ($modifiers as $m) {
$slug = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '_', $m['name'])));
$updateStmt->execute([$slug, $m['id']]);
}
echo "Initial slugs populated for 'modifiers' table.\n";
} catch (PDOException $e) {
if ($e->getCode() == '42S21') {
echo "Column 'slug' already exists in 'modifiers' table.\n";
} else {
echo "Error: " . $e->getMessage() . "\n";
}
}

42
db/migrate_lootboxes.php Normal file
View File

@ -0,0 +1,42 @@
<?php
require_once 'db/config.php';
$db = db();
$sqls = [
"CREATE TABLE IF NOT EXISTS lootboxes (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) NOT NULL UNIQUE,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
"CREATE TABLE IF NOT EXISTS lootbox_rolls (
id INT AUTO_INCREMENT PRIMARY KEY,
lootbox_id INT NOT NULL,
roll_count INT NOT NULL DEFAULT 1,
probability DECIMAL(5,2) NOT NULL DEFAULT 100.00,
FOREIGN KEY (lootbox_id) REFERENCES lootboxes(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;",
"CREATE TABLE IF NOT EXISTS lootbox_items (
id INT AUTO_INCREMENT PRIMARY KEY,
lootbox_id INT NOT NULL,
resource_slug VARCHAR(255) NULL,
probability DECIMAL(5,2) NOT NULL DEFAULT 0.00,
quantity_min INT NOT NULL DEFAULT 1,
quantity_max INT NOT NULL DEFAULT 1,
FOREIGN KEY (lootbox_id) REFERENCES lootboxes(id) ON DELETE CASCADE,
FOREIGN KEY (resource_slug) REFERENCES game_resources(slug) ON UPDATE CASCADE ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
];
foreach ($sqls as $sql) {
try {
$db->exec($sql);
echo "Executed: " . substr($sql, 0, 50) . "...\n";
} catch (PDOException $e) {
echo "Error: " . $e->getMessage() . "\n";
}
}

27
db/migrate_resources.php Normal file
View File

@ -0,0 +1,27 @@
<?php
require_once __DIR__ . '/config.php';
$db = db();
try {
$db->exec("CREATE TABLE IF NOT EXISTS game_resources (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
slug VARCHAR(255) NOT NULL UNIQUE,
icon VARCHAR(100) DEFAULT NULL,
image_url VARCHAR(255) DEFAULT NULL,
description TEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
// Insert a default example resource as requested
$stmt = $db->prepare("SELECT COUNT(*) FROM game_resources WHERE slug = ?");
$stmt->execute(['credits']);
if ($stmt->fetchColumn() == 0) {
$db->exec("INSERT INTO game_resources (name, slug, icon, description) VALUES ('Crédits Galactiques', 'credits', 'fa-coins', 'Monnaie standard utilisée pour les transactions interstellaires.')");
}
echo "Migration completed: game_resources table created and example resource added.\n";
} catch (PDOException $e) {
die("Migration failed: " . $e->getMessage() . "\n");
}

View File

@ -22,7 +22,7 @@ $is_admin = ($current_user['role'] === 'admin');
// Fetch Dynamic Types, Statuses, 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 name ASC")->fetchAll(PDO::FETCH_ASSOC);
$statuses_db = $db->query("SELECT * FROM celestial_object_statuses ORDER BY id 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);
@ -199,6 +199,37 @@ function getStatusColor($status, $type, $statuses_map, $object_types_map) {
.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; z-index: 5; }
.slot-icons {
position: absolute;
top: 5px;
right: 5px;
display: flex;
flex-direction: column;
gap: 5px;
align-items: center;
z-index: 6;
}
.faction-icon-sm {
width: 22px;
height: 22px;
filter: drop-shadow(0 0 2px rgba(0,0,0,0.8));
display: flex;
align-items: center;
justify-content: center;
}
.info-icon-sm {
width: 20px;
height: 20px;
font-size: 14px;
color: #ebcb8b;
filter: drop-shadow(0 0 2px rgba(0,0,0,0.8));
display: flex;
align-items: center;
justify-content: center;
}
.object-icon {
position: absolute;
top: 50%;
@ -217,22 +248,9 @@ function getStatusColor($status, $type, $statuses_map, $object_types_map) {
.object-image { width: 90px; height: 90px; object-fit: contain; margin: 0; }
.slot:hover .object-icon { transform: translate(-50%, -50%) scale(1.1); }
.faction-icon {
position: absolute;
top: 5px;
right: 8px;
width: 24px;
height: 24px;
z-index: 6;
filter: drop-shadow(0 0 2px rgba(0,0,0,0.8));
display: flex;
align-items: center;
justify-content: center;
}
.object-name {
position: absolute;
bottom: 12px;
bottom: 8px;
font-size: 11px;
font-weight: bold;
color: #eceff4;
@ -323,13 +341,21 @@ function getStatusColor($status, $type, $statuses_map, $object_types_map) {
$type_info = $object_types_map[$obj['type']] ?? null;
$fac_info = isset($obj['faction_id']) ? ($factions_map[$obj['faction_id']] ?? null) : null;
?>
<div class="faction-icon">
<div class="slot-icons">
<?php if ($fac_info): ?>
<?php if (!empty($fac_info['image_url'])): ?>
<img src="<?php echo htmlspecialchars($fac_info['image_url']); ?>?v=<?php echo time(); ?>" style="width: 100%; height: 100%; object-fit: contain;" title="<?php echo htmlspecialchars($fac_info['name']); ?>">
<?php elseif (!empty($fac_info['fa_icon'])): ?>
<i class="fa-solid <?php echo htmlspecialchars($fac_info['fa_icon']); ?>" style="color: #fff; font-size: 16px;" title="<?php echo htmlspecialchars($fac_info['name']); ?>"></i>
<?php endif; ?>
<div class="faction-icon-sm">
<?php if (!empty($fac_info['image_url'])): ?>
<img src="<?php echo htmlspecialchars($fac_info['image_url']); ?>?v=<?php echo time(); ?>" style="width: 100%; height: 100%; object-fit: contain;" title="<?php echo htmlspecialchars($fac_info['name']); ?>">
<?php elseif (!empty($fac_info['fa_icon'])): ?>
<i class="fa-solid <?php echo htmlspecialchars($fac_info['fa_icon']); ?>" style="color: #fff; font-size: 16px;" title="<?php echo htmlspecialchars($fac_info['name']); ?>"></i>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (!empty($obj['cities'])): ?>
<div class="info-icon-sm" title="Établissements présents">
<i class="fa-solid fa-city"></i>
</div>
<?php endif; ?>
</div>
@ -508,7 +534,7 @@ function getStatusColor($status, $type, $statuses_map, $object_types_map) {
} else {
document.getElementById('form_name').value = '';
document.getElementById('form_type').value = 'empty';
document.getElementById('form_status').value = 'neutral';
document.getElementById('form_status').value = 'sta_empty';
document.getElementById('form_faction').value = document.querySelector('#form_faction option').value;
document.getElementById('form_orbital').value = 0;
document.getElementById('form_terrestrial').value = 0;
@ -523,4 +549,4 @@ function getStatusColor($status, $type, $statuses_map, $object_types_map) {
function closeSectorModal() { document.getElementById('sectorModal').style.display = 'none'; }
</script>
</body>
</html>
</html>

View File

@ -152,13 +152,31 @@ function getStatusColor($status, $statuses_map) {
.slot:hover { background: rgba(136, 192, 208, 0.1); border-color: #88c0d0; z-index: 10; }
.slot-id { position: absolute; top: 5px; left: 8px; font-size: 9px; color: #4c566a; font-weight: bold; z-index: 5; }
.faction-icon {
.slot-icons {
position: absolute;
top: 5px;
right: 8px;
width: 24px;
height: 24px;
right: 5px;
display: flex;
flex-direction: column;
gap: 5px;
align-items: center;
z-index: 6;
}
.faction-icon-sm {
width: 22px;
height: 22px;
filter: drop-shadow(0 0 2px rgba(0,0,0,0.8));
display: flex;
align-items: center;
justify-content: center;
}
.info-icon-sm {
width: 20px;
height: 20px;
font-size: 14px;
color: #ebcb8b;
filter: drop-shadow(0 0 2px rgba(0,0,0,0.8));
display: flex;
align-items: center;
@ -185,7 +203,7 @@ function getStatusColor($status, $statuses_map) {
.object-name {
position: absolute;
bottom: 24px;
bottom: 8px;
font-size: 11px;
font-weight: bold;
color: #eceff4;
@ -197,28 +215,6 @@ function getStatusColor($status, $statuses_map) {
z-index: 3;
text-shadow: 0 0 4px rgba(0,0,0,0.8);
}
.object-status {
position: absolute;
bottom: 12px;
font-size: 8px;
color: #88c0d0;
text-transform: uppercase;
letter-spacing: 1px;
z-index: 3;
text-shadow: 0 0 4px rgba(0,0,0,0.8);
}
.city-label {
position: absolute;
bottom: 2px;
font-size: 8px;
color: #ebcb8b;
text-align: center;
width: 100%;
padding: 0 5px;
box-sizing: border-box;
z-index: 3;
text-shadow: 0 0 4px rgba(0,0,0,0.8);
}
.sector-grid {
display: grid;
@ -311,6 +307,7 @@ function getStatusColor($status, $statuses_map) {
?>
<div class="tooltip-box">
<div class="tooltip-title"><?php echo htmlspecialchars($obj['name']); ?></div>
<div style="font-size: 10px; color: #88c0d0; margin-bottom: 5px;"><i class="fa-solid fa-circle-info"></i> <?php echo $statuses_map[$obj['status']]['name'] ?? ucfirst($obj['status']); ?></div>
<?php if ($fac_info && $fac_info['name'] !== 'Aucune'): ?>
<div style="font-size: 10px; color: #ebcb8b; margin-bottom: 5px;"><i class="fa-solid fa-flag"></i> Faction: <?php echo htmlspecialchars($fac_info['name']); ?></div>
<?php endif; ?>
@ -338,13 +335,21 @@ function getStatusColor($status, $statuses_map) {
<?php endif; ?>
</div>
<div class="faction-icon">
<div class="slot-icons">
<?php if ($fac_info): ?>
<?php if (!empty($fac_info['image_url'])): ?>
<img src="<?php echo htmlspecialchars($fac_info['image_url']); ?>?v=<?php echo time(); ?>" style="width: 100%; height: 100%; object-fit: contain;" title="<?php echo htmlspecialchars($fac_info['name']); ?>">
<?php elseif (!empty($fac_info['fa_icon'])): ?>
<i class="fa-solid <?php echo htmlspecialchars($fac_info['fa_icon']); ?>" style="color: #fff; font-size: 16px;" title="<?php echo htmlspecialchars($fac_info['name']); ?>"></i>
<?php endif; ?>
<div class="faction-icon-sm">
<?php if (!empty($fac_info['image_url'])): ?>
<img src="<?php echo htmlspecialchars($fac_info['image_url']); ?>?v=<?php echo time(); ?>" style="width: 100%; height: 100%; object-fit: contain;" title="<?php echo htmlspecialchars($fac_info['name']); ?>">
<?php elseif (!empty($fac_info['fa_icon'])): ?>
<i class="fa-solid <?php echo htmlspecialchars($fac_info['fa_icon']); ?>" style="color: #fff; font-size: 16px;" title="<?php echo htmlspecialchars($fac_info['name']); ?>"></i>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (!empty($obj['cities'])): ?>
<div class="info-icon-sm" title="Établissements présents">
<i class="fa-solid fa-city"></i>
</div>
<?php endif; ?>
</div>
@ -361,15 +366,6 @@ function getStatusColor($status, $statuses_map) {
<?php endif; ?>
</div>
<span class="object-name"><?php echo htmlspecialchars($obj['name']); ?></span>
<span class="object-status"><?php echo $statuses_map[$obj['status']]['name'] ?? ucfirst($obj['status']); ?></span>
<?php if (!empty($obj['cities'])): ?>
<span class="city-label"><i class="fa-solid fa-city"></i>
<?php
$c_names = array_map(function($c) { return $c['name']; }, $obj['cities']);
echo htmlspecialchars(implode(', ', $c_names));
?>
</span>
<?php endif; ?>
<?php else: ?>
<div style="opacity: 0.05;"><i class="fa-solid fa-circle fa-sm"></i></div>
<?php endif; ?>
@ -415,4 +411,4 @@ function getStatusColor($status, $statuses_map) {
</div>
<?php endif; ?>
</body>
</html>
</html>