Autosave: 20260306-003148

This commit is contained in:
Flatlogic Bot 2026-03-06 00:31:49 +00:00
parent 386719b74f
commit c2a8442240
3 changed files with 537 additions and 129 deletions

643
admin.php
View File

@ -408,8 +408,21 @@ if (isset($_GET['delete_resource'])) {
exit;
}
// Handle Guild System Config
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["action"]) && $_POST["action"] === "update_guild_requirements") {
$db->exec("DELETE FROM guild_creation_requirements");
$stmt = $db->prepare("INSERT INTO guild_creation_requirements (resource_id, quantity) VALUES (?, ?)");
foreach ($_POST as $key => $value) {
if (strpos($key, "res_") === 0 && (int)$value > 0) {
$res_id = (int)str_replace("res_", "", $key);
$stmt->execute([$res_id, (int)$value]);
}
}
header("Location: admin.php?tab=guilds&success=1");
exit;
}
// Handle Grade CRUD
// Handle Lootbox CRUD
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_grade') {
$id = (int)$_POST['id'];
$name = trim($_POST['name']);
@ -423,22 +436,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
exit;
}
$image_url = null;
if ($id > 0) {
$stmt_img = $db->prepare("SELECT image_url FROM grades 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 = "grade_" . time() . "." . $ext;
if (!is_dir("assets/images/grades")) mkdir("assets/images/grades", 0775, true);
$target = "assets/images/grades/" . $filename;
if (move_uploaded_file($_FILES["image"]["tmp_name"], $target)) {
$image_url = $target;
}
}
// Check for overlap if user_type is 'utilisateur'
if ($user_type === 'utilisateur') {
$check = db()->prepare("SELECT id FROM grades WHERE user_type = 'utilisateur' AND id != ? AND NOT (max_level < ? OR min_level > ?)");
@ -451,11 +448,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
try {
if ($id > 0) {
$stmt = db()->prepare("UPDATE grades SET name = ?, slug = ?, user_type = ?, min_level = ?, max_level = ?, image_url = ? WHERE id = ?");
$stmt->execute([$name, $slug, $user_type, $min_level, $max_level, $image_url, $id]);
$stmt = db()->prepare("UPDATE grades SET name = ?, slug = ?, user_type = ?, min_level = ?, max_level = ? WHERE id = ?");
$stmt->execute([$name, $slug, $user_type, $min_level, $max_level, $id]);
} else {
$stmt = db()->prepare("INSERT INTO grades (name, slug, user_type, min_level, max_level, image_url) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$name, $slug, $user_type, $min_level, $max_level, $image_url]);
$stmt = db()->prepare("INSERT INTO grades (name, slug, user_type, min_level, max_level) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$name, $slug, $user_type, $min_level, $max_level]);
}
header('Location: ?tab=ranks&success=1');
exit;
@ -464,7 +461,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
exit;
}
}
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["action"]) && $_POST["action"] === "upsert_lootbox") {
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_lootbox') {
$id = (int)$_POST['id'];
$name = $_POST['name'];
$slug = $_POST['slug'];
@ -712,7 +709,7 @@ if ($tab === 'users') {
</nav>
</div>
<div>
<span style="font-weight: bold; color: #88c0d0;"><?php echo htmlspecialchars($_SESSION["display_name"] ?? $_SESSION["username"]); ?></span>
<span style="font-weight: bold; color: #88c0d0;"><?php echo htmlspecialchars($_SESSION['username']); ?></span>
</div>
</header>
@ -730,7 +727,11 @@ if ($tab === 'users') {
<a href="?tab=users" class="tab-link <?php echo $tab === 'users' ? 'active' : ''; ?>"><i class="fa-solid fa-users"></i> Utilisateurs</a>
<a href="?tab=levels" class="tab-link <?php echo $tab === 'levels' ? 'active' : ''; ?>"><i class="fa-solid fa-layer-group"></i> Niveaux</a>
<a href="?tab=ranks" class="tab-link <?php echo $tab === 'ranks' ? 'active' : ''; ?>"><i class="fa-solid fa-medal"></i> Grades</a>
} elseif ($tab === 'guilds') {
$guild_requirements = $db->query("SELECT r.id, r.name, gr.quantity FROM game_resources r LEFT JOIN guild_creation_requirements gr ON r.id = gr.resource_id")->fetchAll();
<a href="?tab=badges" class="tab-link <?php echo $tab === 'badges' ? 'active' : ''; ?>"><i class="fa-solid fa-id-badge"></i> Titres & Badges</a>
<a href="?tab=guilds" class="tab-link <?php echo $tab === "guilds" ? "active" : ""; ?>"><i class="fa-solid fa-building-shield"></i> Gestion de guilde</a>
</div>
<!-- LIGNE 2 (JEU) -->
@ -859,7 +860,7 @@ if ($tab === 'users') {
<div class="form-card">
<h4>Ajouter / Modifier un Grade</h4>
<form method="POST" id="rankForm" enctype="multipart/form-data">
<form method="POST" id="rankForm">
<input type="hidden" name="action" value="upsert_grade">
<input type="hidden" name="id" id="rank_id" value="0">
<div style="display: flex; gap: 20px; margin-bottom: 15px;">
@ -879,10 +880,6 @@ if ($tab === 'users') {
<option value="admin">Admin</option>
</select>
</div>
<div class="form-group" style="flex: 1;">
<label>Image (PNG)</label>
<input type="file" name="image" accept="image/png">
</div>
</div>
<div style="display: flex; gap: 20px;">
<div class="form-group" style="flex: 1;">
@ -904,7 +901,6 @@ if ($tab === 'users') {
<table>
<thead>
<tr>
<th>Image</th>
<th>Nom</th>
<th>Slug</th>
<th>Type</th>
@ -914,21 +910,14 @@ if ($tab === 'users') {
</thead>
<tbody>
<?php if (empty($ranks_list)): ?>
<tr><td colspan="6" style="text-align: center;">Aucun grade configuré.</td></tr>
<tr><td colspan="5" style="text-align: center;">Aucun grade configuré.</td></tr>
<?php else: ?>
<?php foreach ($ranks_list as $r): ?>
<tr>
<td>
<?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 else: ?>
-
<?php endif; ?>
</td>
<td><strong><?php echo htmlspecialchars($r['name']); ?></strong></td>
<td><code><?php echo htmlspecialchars($r['slug']); ?></code></td>
<td>
<span class="badge"
<span class="badge <?php echo $r['user_type'] === 'admin' ? 'tag-malus' : ($r['user_type'] === 'GM' ? 'tag-bonus' : ''); ?>"
style="background: <?php echo $r['user_type'] === 'admin' ? '#bf616a' : ($r['user_type'] === 'GM' ? '#ebcb8b' : '#88c0d0'); ?>; color: #2e3440; padding: 2px 8px; border-radius: 10px; font-size: 10px; text-transform: uppercase; font-weight: bold;">
<?php echo htmlspecialchars($r['user_type']); ?>
</span>
@ -950,6 +939,29 @@ if ($tab === 'users') {
</tbody>
</table>
} elseif ($tab === 'guilds') {
$guild_requirements = $db->query("SELECT r.id, r.name, gr.quantity FROM game_resources r LEFT JOIN guild_creation_requirements gr ON r.id = gr.resource_id")->fetchAll();
<?php elseif ($tab === 'guilds'): ?>
<h3 style="color: #88c0d0;">Gestion des Guildes</h3>
<div class="form-card">
<h4>Coût de création d'une guilde</h4>
<form method="POST">
<input type="hidden" name="action" value="update_guild_requirements">
<table>
<thead><tr><th>Ressource</th><th>Quantité requise</th></tr></thead>
<tbody>
<?php foreach ($guild_requirements as $req): ?>
<tr>
<td><?php echo htmlspecialchars($req["name"]); ?></td>
<td><input type="number" name="res_<?php echo $req["id"]; ?>" value="<?php echo $req["quantity"] ?: 0; ?>"></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<button type="submit" class="btn btn-add" style="margin-top: 15px;">ENREGISTRER</button>
</form>
</div>
<?php elseif ($tab === 'badges'): ?>
<h3 style="color: #88c0d0;">Titres & Badges</h3>
<div class="form-card">
@ -1679,11 +1691,6 @@ if ($tab === 'users') {
document.getElementById('log_id').value = 0;
document.getElementById('logForm').reset();
}
</script>
<?php endif; ?>
</div>
<script>
function toggleMS(id) {
const d = document.getElementById(id);
@ -1773,96 +1780,474 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
// --- LOOTBOX SYSTEM ---
const resourcesList = <?php echo json_encode($resources_list); ?>;
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();
}
</script>
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));
<?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');
}
});
function editLevel(data) {
document.getElementById("level_id").value = data.id;
document.getElementById("level_name").value = data.name;
document.getElementById("level_slug").value = data.slug;
document.getElementById("level_resource_id").value = data.resource_id;
document.getElementById("level_required_quantity").value = data.required_quantity;
window.scrollTo(0,0);
}
function resetLevelForm() {
document.getElementById("levelForm").reset();
document.getElementById("level_id").value = 0;
const select = document.getElementById("level_resource_id");
for (let i = 0; i < select.options.length; i++) {
if (select.options[i].text.toLowerCase().includes("expérience") || select.options[i].text.toLowerCase().includes("experience")) {
select.selectedIndex = i;
break;
}
}
}
function updateRankFields() {
const type = document.getElementById('rank_type').value;
const min = document.getElementById('rank_min');
const max = document.getElementById('rank_max');
if (type === 'utilisateur') {
min.disabled = false;
max.disabled = false;
min.required = true;
max.required = true;
min.style.opacity = '1';
max.style.opacity = '1';
} else {
addItemRow();
min.disabled = true;
max.disabled = true;
min.required = false;
max.required = false;
min.style.opacity = '0.5';
max.style.opacity = '0.5';
min.value = '';
max.value = '';
}
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();
function editRank(rank) {
document.getElementById('rank_id').value = rank.id;
document.getElementById('rank_name').value = rank.name;
document.getElementById('rank_slug').value = rank.slug;
document.getElementById('rank_type').value = rank.user_type;
document.getElementById('rank_min').value = rank.min_level || '';
document.getElementById('rank_max').value = rank.max_level || '';
updateRankFields();
window.scrollTo({ top: 0, behavior: 'smooth' });
}
<?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 resetRankForm() {
document.getElementById('rankForm').reset();
document.getElementById('rank_id').value = '0';
updateRankFields();
}
// Initial call to set fields on load
document.addEventListener('DOMContentLoaded', function() {
if (document.getElementById('rank_type')) {
updateRankFields();
}
});
</script>
</body>
</html>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

View File

@ -0,0 +1,23 @@
<?php
require_once 'db/config.php';
$pdo = db();
// Tables pour le système de guildes
$pdo->exec("CREATE TABLE IF NOT EXISTS guilds (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");
$pdo->exec("CREATE TABLE IF NOT EXISTS guild_creation_requirements (
id INT AUTO_INCREMENT PRIMARY KEY,
resource_id INT NOT NULL,
quantity INT NOT NULL,
FOREIGN KEY (resource_id) REFERENCES game_resources(id)
)");
$pdo->exec("CREATE TABLE IF NOT EXISTS guild_restrictions (
id INT AUTO_INCREMENT PRIMARY KEY,
restriction_key VARCHAR(255) NOT NULL,
restriction_value TEXT
)");