From e33f37b2a1d486e8f0f9f5ee3b76036b6a5eb7e7 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 22 Feb 2026 22:20:10 +0000 Subject: [PATCH] Autosave: 20260222-222009 --- admin.php | 474 +++++++++++++++++- .../obj_planet_ocean_01_1771761133.png | Bin 0 -> 4876 bytes db/add_all_foreign_keys.php | 50 ++ db/add_guaranteed_to_lootboxes.php | 25 + db/add_slug_to_factions.php | 28 ++ db/add_slug_to_modifiers.php | 29 ++ db/migrate_lootboxes.php | 42 ++ db/migrate_resources.php | 27 + gm_console.php | 72 ++- index.php | 82 ++- 10 files changed, 741 insertions(+), 88 deletions(-) create mode 100644 assets/images/celestial/obj_planet_ocean_01_1771761133.png create mode 100644 db/add_all_foreign_keys.php create mode 100644 db/add_guaranteed_to_lootboxes.php create mode 100644 db/add_slug_to_factions.php create mode 100644 db/add_slug_to_modifiers.php create mode 100644 db/migrate_lootboxes.php create mode 100644 db/migrate_resources.php diff --git a/admin.php b/admin.php index 19571c1..68cc25d 100644 --- a/admin.php +++ b/admin.php @@ -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); } @@ -297,6 +430,8 @@ if ($tab === 'users') { Statuts / États Types d'Établissements Factions + Ressources + Lootboxes @@ -384,7 +519,7 @@ if ($tab === 'users') { - + @@ -396,7 +531,6 @@ if ($tab === 'users') { - +
VisuelNomSlugBonus/MalusActions
VisuelNomBonus/MalusSlugActions
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') { Suppr @@ -429,6 +564,10 @@ if ($tab === 'users') { +
+ + +
- + @@ -458,6 +597,7 @@ if ($tab === 'users') { +
TypeNomDescriptionActions
TypeNomDescriptionSlugActions
Suppr @@ -569,6 +709,10 @@ if ($tab === 'users') { +
+ + +
@@ -584,7 +728,7 @@ if ($tab === 'users') {
- + @@ -598,6 +742,7 @@ if ($tab === 'users') { +
VisuelNomActions
VisuelNomSlugActions
@@ -608,20 +753,202 @@ if ($tab === 'users') {
+ + +

Gestion des Ressources

+
+

Ajouter / Modifier une Ressource

+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+ + +
+
+ + + + + + + + + + + + + +
VisuelNomSlugActions
+ + + + + + + + + + Suppr +
+ + +

Système de Lootboxes

+
+

Créer / Modifier une Lootbox

+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ +
+ +
+ + +
+
Nb Total
+
Chance (%)
+
+
+ +
+ +
+ +
+ + +
+ + +
+
Type
+
Ressource / Objet
+
Chance (%)
+
Qté Min
+
Qté Max
+
+
+ +
+ +
+ +
+
+ +
+ + +
+
+
+ + + + + + + + + + + + + + + +
NomSlugObjets Directs (100%)Nb Total (%)Pool Aléatoire (%)Actions
+ + $i['is_guaranteed']); + foreach ($directs as $d): ?> +
+ + (Qté: -) +
+ Aucun"; ?> +
+
+ + +
+ objet(s): + % +
+ +
+
+ + !$i['is_guaranteed']); + foreach ($pool as $i): ?> +
+ (Rien)'; ?>: + % + (Qté: -) +
+ +
+
+ + Suppr +
\ No newline at end of file diff --git a/assets/images/celestial/obj_planet_ocean_01_1771761133.png b/assets/images/celestial/obj_planet_ocean_01_1771761133.png new file mode 100644 index 0000000000000000000000000000000000000000..decd021f7f090c80939bed29b736a8c08fcc8b19 GIT binary patch literal 4876 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"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"); +} diff --git a/db/add_guaranteed_to_lootboxes.php b/db/add_guaranteed_to_lootboxes.php new file mode 100644 index 0000000..56b7880 --- /dev/null +++ b/db/add_guaranteed_to_lootboxes.php @@ -0,0 +1,25 @@ +exec($sql); + echo "Executed: " . substr($sql, 0, 50) . "...\n"; + } catch (PDOException $e) { + echo "Error: " . $e->getMessage() . "\n"; + } +} + diff --git a/db/add_slug_to_factions.php b/db/add_slug_to_factions.php new file mode 100644 index 0000000..219b0cd --- /dev/null +++ b/db/add_slug_to_factions.php @@ -0,0 +1,28 @@ +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()); +} + diff --git a/db/add_slug_to_modifiers.php b/db/add_slug_to_modifiers.php new file mode 100644 index 0000000..dc5c68d --- /dev/null +++ b/db/add_slug_to_modifiers.php @@ -0,0 +1,29 @@ +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"; + } +} + diff --git a/db/migrate_lootboxes.php b/db/migrate_lootboxes.php new file mode 100644 index 0000000..8c057f3 --- /dev/null +++ b/db/migrate_lootboxes.php @@ -0,0 +1,42 @@ +exec($sql); + echo "Executed: " . substr($sql, 0, 50) . "...\n"; + } catch (PDOException $e) { + echo "Error: " . $e->getMessage() . "\n"; + } +} + diff --git a/db/migrate_resources.php b/db/migrate_resources.php new file mode 100644 index 0000000..3245d6c --- /dev/null +++ b/db/migrate_resources.php @@ -0,0 +1,27 @@ +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"); +} + diff --git a/gm_console.php b/gm_console.php index 51b90ca..5dc6475 100644 --- a/gm_console.php +++ b/gm_console.php @@ -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; ?> -
+
- - - - - +
+ + + + + +
+ + + +
+ +
@@ -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'; } - \ No newline at end of file + diff --git a/index.php b/index.php index b71ca87..699e3b5 100644 --- a/index.php +++ b/index.php @@ -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) { ?>
+
Faction:
@@ -338,13 +335,21 @@ function getStatusColor($status, $statuses_map) {
-
+
- - - - - +
+ + + + + +
+ + + +
+ +
@@ -361,15 +366,6 @@ function getStatusColor($status, $statuses_map) {
- - - - - -
@@ -415,4 +411,4 @@ function getStatusColor($status, $statuses_map) {
- + \ No newline at end of file