diff --git a/sccharacters.php b/sccharacters.php
index f44d1f7..9e9570a 100644
--- a/sccharacters.php
+++ b/sccharacters.php
@@ -36,6 +36,26 @@ function sccharacters_clean_text(?string $value): string
return trim((string) $value);
}
+function sccharacters_normalize_item_quantity($value): ?int
+{
+ if ($value === null) {
+ return null;
+ }
+
+ $value = trim((string) $value);
+ if ($value === '' || !preg_match('/^\d+$/', $value)) {
+ return null;
+ }
+
+ $quantity = (int) $value;
+
+ if ($quantity <= 0) {
+ return null;
+ }
+
+ return min($quantity, 999999);
+}
+
function sccharacters_is_valid_url(string $value): bool
{
if ($value === '') {
@@ -203,7 +223,7 @@ function sccharacters_parse_item_key(string $item_key): ?array
];
}
-function sccharacters_merge_selected_items(array $staged_items, array $selected_items, array $item_slots, array $item_notes): array
+function sccharacters_merge_selected_items(array $staged_items, array $selected_items, array $item_slots, array $item_notes, array $item_quantities = []): array
{
$selected_items = array_values(array_unique(array_map('strval', $selected_items)));
$staged_count = 0;
@@ -221,6 +241,7 @@ function sccharacters_merge_selected_items(array $staged_items, array $selected_
'source_id' => $parsed['source_id'],
'category' => sccharacters_clean_text($item_slots[$item_key] ?? ''),
'note' => sccharacters_clean_text($item_notes[$item_key] ?? ''),
+ 'quantity' => sccharacters_normalize_item_quantity($item_quantities[$item_key] ?? null),
];
$staged_count++;
}
@@ -627,6 +648,7 @@ function sccharacters_attach_item(
string $source,
int $source_id,
string $requested_category,
+ ?int $quantity,
string $note,
?string &$error_message = null
): bool {
@@ -671,6 +693,7 @@ function sccharacters_attach_item(
cl_sccharacteritem_scobjs_id,
cl_sccharacteritem_scitemcustom_id,
cl_sccharacteritem_slot,
+ cl_sccharacteritem_quantity,
cl_sccharacteritem_note,
cl_sccharacteritem_sort_order
) VALUES (
@@ -679,6 +702,7 @@ function sccharacters_attach_item(
:scobjs_id,
NULL,
:slot,
+ :quantity,
:note,
:sort_order
)'
@@ -688,6 +712,7 @@ function sccharacters_attach_item(
'source' => 'base',
'scobjs_id' => $source_id,
'slot' => $category,
+ 'quantity' => $quantity,
'note' => $note !== '' ? $note : null,
'sort_order' => $sort_order,
]);
@@ -728,6 +753,7 @@ function sccharacters_attach_item(
cl_sccharacteritem_scobjs_id,
cl_sccharacteritem_scitemcustom_id,
cl_sccharacteritem_slot,
+ cl_sccharacteritem_quantity,
cl_sccharacteritem_note,
cl_sccharacteritem_sort_order
) VALUES (
@@ -736,6 +762,7 @@ function sccharacters_attach_item(
NULL,
:scitemcustom_id,
:slot,
+ :quantity,
:note,
:sort_order
)'
@@ -745,6 +772,7 @@ function sccharacters_attach_item(
'source' => 'custom',
'scitemcustom_id' => $source_id,
'slot' => $category,
+ 'quantity' => $quantity,
'note' => $note !== '' ? $note : null,
'sort_order' => $sort_order,
]);
@@ -756,6 +784,79 @@ function sccharacters_attach_item(
return false;
}
+function sccharacters_update_character_item(
+ PDO $db,
+ int $owner_auth_id,
+ int $character_id,
+ int $character_item_id,
+ string $requested_category,
+ ?int $quantity,
+ string $note,
+ ?string &$error_message = null
+): bool {
+ if ($character_id <= 0 || $owner_auth_id <= 0 || $character_item_id <= 0) {
+ $error_message = 'Paramètres de mise à jour invalides.';
+ return false;
+ }
+
+ $stmt_item = $db->prepare(
+ "SELECT
+ ci.cl_sccharacteritem_id,
+ ci.cl_sccharacteritem_source,
+ bo.cl_scobjs_type AS cl_sccharacteritem_base_type,
+ bo.cl_scobjs_subtype AS cl_sccharacteritem_base_subtype,
+ oo.cl_scobjs_type AS cl_sccharacteritem_custom_type,
+ oo.cl_scobjs_subtype AS cl_sccharacteritem_custom_subtype
+ FROM tbl_sccharacteritems ci
+ INNER JOIN tbl_sccharacters c ON c.cl_sccharacter_id = ci.cl_sccharacteritem_character_id
+ LEFT JOIN tbl_scobjs bo ON bo.cl_scobjs_id = ci.cl_sccharacteritem_scobjs_id
+ LEFT JOIN tbl_scitemcustom co ON co.cl_scitemcustom_id = ci.cl_sccharacteritem_scitemcustom_id
+ LEFT JOIN tbl_scobjs oo ON oo.cl_scobjs_id = co.cl_scitemcustom_obj_id
+ WHERE ci.cl_sccharacteritem_id = :character_item_id
+ AND c.cl_sccharacter_id = :character_id
+ AND c.cl_sccharacter_owner_auth_id = :owner_auth_id
+ LIMIT 1"
+ );
+ $stmt_item->execute([
+ 'character_item_id' => $character_item_id,
+ 'character_id' => $character_id,
+ 'owner_auth_id' => $owner_auth_id,
+ ]);
+ $item_row = $stmt_item->fetch();
+
+ if (!$item_row) {
+ $error_message = 'Objet introuvable ou non autorisé.';
+ return false;
+ }
+
+ $is_custom = (string) ($item_row['cl_sccharacteritem_source'] ?? '') === 'custom';
+ $item_type = $is_custom
+ ? (string) ($item_row['cl_sccharacteritem_custom_type'] ?? '')
+ : (string) ($item_row['cl_sccharacteritem_base_type'] ?? '');
+ $item_subtype = $is_custom
+ ? (string) ($item_row['cl_sccharacteritem_custom_subtype'] ?? '')
+ : (string) ($item_row['cl_sccharacteritem_base_subtype'] ?? '');
+ $category = sccharacters_resolve_item_category($requested_category, $item_type, $item_subtype);
+
+ $stmt_update = $db->prepare(
+ 'UPDATE tbl_sccharacteritems
+ SET cl_sccharacteritem_slot = :slot,
+ cl_sccharacteritem_quantity = :quantity,
+ cl_sccharacteritem_note = :note
+ WHERE cl_sccharacteritem_id = :character_item_id
+ AND cl_sccharacteritem_character_id = :character_id'
+ );
+ $stmt_update->execute([
+ 'slot' => $category,
+ 'quantity' => $quantity,
+ 'note' => $note !== '' ? $note : null,
+ 'character_item_id' => $character_item_id,
+ 'character_id' => $character_id,
+ ]);
+
+ return true;
+}
+
$flash = auth_flash_get();
$flash_type = $flash['type'] ?? '';
$flash_message = $flash['message'] ?? '';
@@ -1048,6 +1149,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$character_id = (int) ($_POST['character_id'] ?? 0);
$obj_id = (int) ($_POST['base_obj_id'] ?? 0);
$requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
+ $quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
$note = sccharacters_clean_text($_POST['item_note'] ?? '');
$item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
$item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
@@ -1062,6 +1164,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'base',
$obj_id,
$requested_category,
+ $quantity,
$note,
$error_message
)) {
@@ -1079,6 +1182,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$character_id = (int) ($_POST['character_id'] ?? 0);
$itemcustom_id = (int) ($_POST['custom_item_id'] ?? 0);
$requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
+ $quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
$note = sccharacters_clean_text($_POST['item_note'] ?? '');
$item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'custom');
$item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
@@ -1093,6 +1197,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'custom',
$itemcustom_id,
$requested_category,
+ $quantity,
$note,
$error_message
)) {
@@ -1105,6 +1210,40 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, true, $item_page_context, $item_per_page_context));
exit;
}
+
+ if ($action === 'update_character_item') {
+ $character_item_id = (int) ($_POST['character_item_id'] ?? 0);
+ $character_id = (int) ($_POST['character_id'] ?? 0);
+ $requested_category = sccharacters_clean_text($_POST['item_slot'] ?? '');
+ $quantity = sccharacters_normalize_item_quantity($_POST['item_quantity'] ?? null);
+ $note = sccharacters_clean_text($_POST['item_note'] ?? '');
+ $item_source_context = sccharacters_clean_text($_POST['item_source_context'] ?? 'base');
+ $item_search_context = sccharacters_clean_text($_POST['item_search_context'] ?? '');
+ $item_page_context = max(1, (int) ($_POST['item_page_context'] ?? 1));
+ $item_per_page_context = sccharacters_normalize_item_per_page($_POST['item_per_page_context'] ?? 50);
+ $item_panel_context = (string) ($_POST['item_panel_context'] ?? '') === '1';
+ $error_message = null;
+
+ if (!sccharacters_update_character_item(
+ $db,
+ $current_owner_auth_id,
+ $character_id,
+ $character_item_id,
+ $requested_category,
+ $quantity,
+ $note,
+ $error_message
+ )) {
+ auth_flash_set('error', $error_message ?? 'Impossible de mettre à jour cet objet.');
+ header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
+ exit;
+ }
+
+ auth_flash_set('success', 'Objet mis à jour.');
+ header('Location: ' . sccharacters_build_return_url($character_id, $item_source_context, $item_search_context, $item_panel_context, $item_page_context, $item_per_page_context));
+ exit;
+ }
+
if ($action === 'move_character_category') {
$character_id = (int) ($_POST['character_id'] ?? 0);
$category_key = sccharacters_clean_text($_POST['category_key'] ?? '');
@@ -2082,11 +2221,93 @@ if ($selected_character) {
margin-top: auto;
display: flex;
flex-wrap: wrap;
- gap: 0.6rem;
- align-items: center;
+ gap: 0.75rem;
+ align-items: flex-start;
justify-content: space-between;
}
+ .equipment-action-buttons {
+ display: grid;
+ grid-template-columns: repeat(2, auto);
+ align-items: start;
+ gap: 0.55rem;
+ justify-content: end;
+ }
+
+ .equipment-edit {
+ width: auto;
+ margin-top: 0;
+ }
+
+ .equipment-edit[open] {
+ grid-column: 1 / -1;
+ width: min(100%, 34rem);
+ justify-self: end;
+ }
+
+ .equipment-edit-summary,
+ .equipment-icon-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.45rem;
+ min-width: 2.45rem;
+ height: 2.45rem;
+ min-height: 2.45rem;
+ padding: 0;
+ cursor: pointer;
+ list-style: none;
+ line-height: 1;
+ }
+
+ .equipment-edit-summary::-webkit-details-marker {
+ display: none;
+ }
+
+ .equipment-edit-form {
+ margin-top: 0.85rem;
+ padding: 0.95rem;
+ border-radius: 14px;
+ border: 1px solid rgba(255,255,255,0.08);
+ background: rgba(255,255,255,0.04);
+ display: grid;
+ gap: 0.85rem;
+ width: min(100%, 34rem);
+ }
+
+ .equipment-edit-grid {
+ display: grid;
+ grid-template-columns: minmax(110px, 135px) minmax(0, 1fr);
+ gap: 0.75rem;
+ align-items: start;
+ }
+
+ .equipment-edit-grid textarea {
+ grid-column: 1 / -1;
+ min-height: 96px;
+ resize: vertical;
+ }
+
+ .item-attach-meta textarea {
+ grid-column: 1 / -1;
+ min-height: 72px;
+ resize: vertical;
+ }
+
+ .equipment-edit-form input,
+ .equipment-edit-form select,
+ .equipment-edit-form textarea,
+ .item-attach-meta input,
+ .item-attach-meta select,
+ .item-attach-meta textarea {
+ width: 100%;
+ }
+
+ .equipment-edit-form-actions {
+ display: flex;
+ justify-content: flex-end;
+ }
+
.equipment-reorder-form {
display: none;
}
@@ -2219,13 +2440,13 @@ if ($selected_character) {
.search-result {
padding: 0.95rem;
display: grid;
- grid-template-columns: minmax(0, 1fr) 310px;
+ grid-template-columns: minmax(0, 1fr) 360px;
gap: 1rem;
align-items: start;
}
body.show-item-preview .search-result {
- grid-template-columns: 96px minmax(0, 1fr) 310px;
+ grid-template-columns: 96px minmax(0, 1fr) 360px;
}
.search-result strong { display: block; margin-bottom: 0.25rem; }
@@ -2305,27 +2526,35 @@ if ($selected_character) {
.item-attach-form {
display: grid;
- gap: 0.65rem;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 0.75rem;
+ align-self: stretch;
+ align-items: stretch;
}
.item-attach-meta {
display: grid;
- grid-template-columns: minmax(0, 180px) minmax(0, 1fr);
+ grid-template-columns: minmax(96px, 112px) minmax(0, 1fr);
gap: 0.55rem;
+ align-items: start;
}
.item-attach-actions {
display: flex;
- justify-content: flex-end;
+ align-self: stretch;
}
.item-add-button {
- min-width: 2.75rem;
- min-height: 2.75rem;
+ min-width: 3rem;
+ min-height: 100%;
+ height: 100%;
padding: 0.4rem;
font-size: 1.55rem;
line-height: 1;
font-weight: 700;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
}
.search-results-summary {
@@ -2415,6 +2644,7 @@ if ($selected_character) {
justify-content: flex-start;
}
+ .item-attach-form,
.item-attach-meta,
.search-controls-row {
grid-template-columns: 1fr;
@@ -2426,6 +2656,8 @@ if ($selected_character) {
.item-add-button {
width: 100%;
+ min-height: 2.75rem;
+ height: auto;
}
}
@@ -2803,6 +3035,8 @@ if ($selected_character) {
$item_type,
$item_subtype
);
+ $item_quantity = sccharacters_normalize_item_quantity($character_item_row['cl_sccharacteritem_quantity'] ?? null);
+ $item_title = $item_quantity !== null ? $item_quantity . 'x ' . $item_name : $item_name;
$item_note = trim((string) ($character_item_row['cl_sccharacteritem_note'] ?? ''));
$item_stats = [];
if ($is_custom) {
@@ -2818,7 +3052,7 @@ if ($selected_character) {