max(0, intv($_POST['health'] ?? 0)),
'experience' => max(0, intv($_POST['experience'] ?? 0)),
'speed' => max(0, intv($_POST['speed'] ?? 0)),
'race' => trim((string)($_POST['race'] ?? '')),
'looktype' => max(0, intv($_POST['looktype'] ?? 0)),
);
$ok = serverdata_override_set('creatures', $name, $record, $adminName);
// Renaming: the old key must stop winning over the base cache too.
if ($ok && $originalName !== '' && $originalName !== $name) {
serverdata_override_delete('creatures', $originalName, $adminName);
}
if ($ok) {
acp_log('serverdata.creature_save', $name);
acp_flash_success(t_default('acp.crted.saved', '{name} saved.', ['name' => $name]));
} else {
acp_flash_error(t_default('acp.crted.save_failed', 'Could not save - run the pending database migration first (Admin Panel > Migrations).'));
}
acp_redirect('creatures_editor');
}
if ($action === 'delete') {
$name = trim((string)($_POST['name'] ?? ''));
if (serverdata_override_delete('creatures', $name, $adminName)) {
acp_log('serverdata.creature_delete', $name);
acp_flash_success(t_default('acp.crted.removed', '{name} removed.', ['name' => $name]));
} else {
acp_flash_error(t_default('acp.crted.remove_failed', 'Could not remove that creature.'));
}
acp_redirect('creatures_editor');
}
}
$editName = trim((string)($_GET['edit'] ?? ''));
$editing = null;
if ($editName !== '') {
foreach ($creatures as $c) {
if (($c['name'] ?? '') === $editName) {
$editing = $c;
break;
}
}
}
$list = $creatures;
usort($list, static function (array $a, array $b): int {
return strcasecmp((string)($a['name'] ?? ''), (string)($b['name'] ?? ''));
});
?>
= h(t_default('acp.crted.sub', 'Saved separately from the uploaded monster files - a later re-upload will not overwrite this.')) ?>= $editing ? h(t_default('acp.crted.edit_title', 'Edit {name}', ['name' => $editName])) : h(t_default('acp.crted.add_title', 'Add a creature')) ?>
= t_default('acp.crted.list_title', 'Published creatures') ?>