/**
* User Stats Rendering Module
* Handles rendering of the user stats panel with progress bars and classic RPG stats
*/
import { getContext } from '../../../../../../extensions.js';
import { user_avatar } from '../../../../../../../script.js';
import {
extensionSettings,
lastGeneratedData,
committedTrackerData,
$userStatsContainer,
FALLBACK_AVATAR_DATA_URI
} from '../../core/state.js';
import {
saveSettings,
saveChatData,
updateMessageSwipeData
} from '../../core/persistence.js';
import { getSafeThumbnailUrl } from '../../utils/avatars.js';
import { buildInventorySummary } from '../generation/promptBuilder.js';
/**
* Renders the user stats panel with health bars, mood, inventory, and classic stats.
* Includes event listeners for editable fields.
*/
export function renderUserStats() {
if (!extensionSettings.showUserStats || !$userStatsContainer) {
return;
}
const stats = extensionSettings.userStats;
const userName = getContext().name1;
// Initialize lastGeneratedData.userStats if it doesn't exist
if (!lastGeneratedData.userStats) {
lastGeneratedData.userStats = `Health: ${stats.health}%\nSatiety: ${stats.satiety}%\nEnergy: ${stats.energy}%\nHygiene: ${stats.hygiene}%\nArousal: ${stats.arousal}%\n${stats.mood}: ${stats.conditions}\nInventory: ${stats.inventory}`;
}
// Get user portrait - handle both default-user and custom persona folders
// Use a base64-encoded SVG placeholder as fallback to avoid 400 errors
let userPortrait = FALLBACK_AVATAR_DATA_URI;
if (user_avatar) {
// Try to get the thumbnail using our safe helper
const thumbnailUrl = getSafeThumbnailUrl('persona', user_avatar);
if (thumbnailUrl) {
userPortrait = thumbnailUrl;
}
}
// Create gradient from low to high color
const gradient = `linear-gradient(to right, ${extensionSettings.statBarColorLow}, ${extensionSettings.statBarColorHigh})`;
const html = `
Health:
${stats.health}%
Satiety:
${stats.satiety}%
Energy:
${stats.energy}%
Hygiene:
${stats.hygiene}%
Arousal:
${stats.arousal}%
${stats.mood}
${stats.conditions}
STR
${extensionSettings.classicStats.str}
DEX
${extensionSettings.classicStats.dex}
CON
${extensionSettings.classicStats.con}
INT
${extensionSettings.classicStats.int}
WIS
${extensionSettings.classicStats.wis}
CHA
${extensionSettings.classicStats.cha}
`;
$userStatsContainer.html(html);
// Add event listeners for editable stat values
$('.rpg-editable-stat').on('blur', function() {
const field = $(this).data('field');
const textValue = $(this).text().replace('%', '').trim();
let value = parseInt(textValue);
// Validate and clamp value between 0 and 100
if (isNaN(value)) {
value = 0;
}
value = Math.max(0, Math.min(100, value));
// Update the setting
extensionSettings.userStats[field] = value;
// Rebuild userStats text with proper inventory format
const stats = extensionSettings.userStats;
const inventorySummary = buildInventorySummary(stats.inventory);
const statsText = `Health: ${stats.health}%\nSatiety: ${stats.satiety}%\nEnergy: ${stats.energy}%\nHygiene: ${stats.hygiene}%\nArousal: ${stats.arousal}%\n${stats.mood}: ${stats.conditions}\n${inventorySummary}`;
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
lastGeneratedData.userStats = statsText;
committedTrackerData.userStats = statsText;
saveSettings();
saveChatData();
updateMessageSwipeData();
// Re-render to update the bar
renderUserStats();
});
// Add event listeners for mood/conditions editing
$('.rpg-mood-emoji.rpg-editable').on('blur', function() {
const value = $(this).text().trim();
extensionSettings.userStats.mood = value || '😐';
// Rebuild userStats text with proper inventory format
const stats = extensionSettings.userStats;
const inventorySummary = buildInventorySummary(stats.inventory);
const statsText = `Health: ${stats.health}%\nSatiety: ${stats.satiety}%\nEnergy: ${stats.energy}%\nHygiene: ${stats.hygiene}%\nArousal: ${stats.arousal}%\n${stats.mood}: ${stats.conditions}\n${inventorySummary}`;
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
lastGeneratedData.userStats = statsText;
committedTrackerData.userStats = statsText;
saveSettings();
saveChatData();
updateMessageSwipeData();
});
$('.rpg-mood-conditions.rpg-editable').on('blur', function() {
const value = $(this).text().trim();
extensionSettings.userStats.conditions = value || 'None';
// Rebuild userStats text with proper inventory format
const stats = extensionSettings.userStats;
const inventorySummary = buildInventorySummary(stats.inventory);
const statsText = `Health: ${stats.health}%\nSatiety: ${stats.satiety}%\nEnergy: ${stats.energy}%\nHygiene: ${stats.hygiene}%\nArousal: ${stats.arousal}%\n${stats.mood}: ${stats.conditions}\n${inventorySummary}`;
// Update BOTH lastGeneratedData AND committedTrackerData
// This makes manual edits immediately visible to AI
lastGeneratedData.userStats = statsText;
committedTrackerData.userStats = statsText;
saveSettings();
saveChatData();
updateMessageSwipeData();
});
}