Revert "All the features"
This commit is contained in:
@@ -25,7 +25,6 @@ export const defaultSettings = {
|
||||
enabled: true,
|
||||
autoUpdate: true,
|
||||
updateDepth: 4, // How many messages to include in the context
|
||||
messageInterceptionContextDepth: 4, // How many recent messages to send when intercepting user messages
|
||||
generationMode: 'together', // 'separate' or 'together' - whether to generate with main response or separately
|
||||
useSeparatePreset: false, // Use 'RPG Companion Trackers' preset for tracker generation instead of main API model
|
||||
showUserStats: true,
|
||||
@@ -35,8 +34,6 @@ export const defaultSettings = {
|
||||
showThoughtsInChat: true, // Show thoughts overlay in chat
|
||||
alwaysShowThoughtBubble: false, // Auto-expand thought bubble without clicking icon
|
||||
enableHtmlPrompt: false, // Enable immersive HTML prompt injection
|
||||
enableMessageInterception: false, // Enable intercepting user messages with LLM rewrite
|
||||
messageInterceptionActive: true, // Runtime toggle to allow/skip interception
|
||||
// Controls when the extension skips injecting tracker instructions/examples/HTML
|
||||
// into generations that appear to be user-injected instructions. Valid values:
|
||||
// - 'none' -> never skip (legacy behavior: always inject)
|
||||
|
||||
+3
-5
@@ -1,6 +1,5 @@
|
||||
//- No-op in case this is running outside of SillyTavern
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { extension_settings: _extension_settings } = typeof self.SillyTavern !== 'undefined' ? self.SillyTavern.getContext() : { extension_settings: {} };
|
||||
const { extension_settings } = typeof self.SillyTavern !== 'undefined' ? self.SillyTavern.getContext() : { extension_settings: {} };
|
||||
|
||||
class Internationalization {
|
||||
constructor() {
|
||||
@@ -88,9 +87,8 @@ class Internationalization {
|
||||
});
|
||||
}
|
||||
|
||||
getTranslation(key, fallback = null) {
|
||||
// Return translation, or fallback, or the key itself (prevents "null" from showing)
|
||||
return this.translations[key] || fallback || key;
|
||||
getTranslation(key) {
|
||||
return this.translations[key] || null;
|
||||
}
|
||||
|
||||
async setLanguage(lang) {
|
||||
|
||||
+47
-249
@@ -9,9 +9,11 @@ import {
|
||||
extensionSettings,
|
||||
lastGeneratedData,
|
||||
committedTrackerData,
|
||||
setExtensionSettings,
|
||||
updateExtensionSettings,
|
||||
setLastGeneratedData,
|
||||
setCommittedTrackerData
|
||||
setCommittedTrackerData,
|
||||
FEATURE_FLAGS
|
||||
} from './state.js';
|
||||
import { migrateInventory } from '../utils/migration.js';
|
||||
import { validateStoredInventory, cleanItemString } from '../utils/security.js';
|
||||
@@ -76,14 +78,19 @@ export function loadSettings() {
|
||||
}
|
||||
|
||||
updateExtensionSettings(savedSettings);
|
||||
// console.log('[RPG Companion] Settings loaded:', extensionSettings);
|
||||
} else {
|
||||
// console.log('[RPG Companion] No saved settings found, using defaults');
|
||||
}
|
||||
|
||||
// Migrate inventory from v1 (string) to v2 (object) format if needed
|
||||
const migrationResult = migrateInventory(extensionSettings.userStats.inventory);
|
||||
if (migrationResult.migrated) {
|
||||
console.log(`[RPG Companion] Inventory migrated from ${migrationResult.source} to v2 format`);
|
||||
extensionSettings.userStats.inventory = migrationResult.inventory;
|
||||
saveSettings(); // Persist migrated inventory
|
||||
// Migrate inventory if feature flag enabled
|
||||
if (FEATURE_FLAGS.useNewInventory) {
|
||||
const migrationResult = migrateInventory(extensionSettings.userStats.inventory);
|
||||
if (migrationResult.migrated) {
|
||||
console.log(`[RPG Companion] Inventory migrated from ${migrationResult.source} to v2 format`);
|
||||
extensionSettings.userStats.inventory = migrationResult.inventory;
|
||||
saveSettings(); // Persist migrated inventory
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate to trackerConfig if it doesn't exist
|
||||
@@ -92,16 +99,6 @@ export function loadSettings() {
|
||||
migrateToTrackerConfig();
|
||||
saveSettings(); // Persist migration
|
||||
}
|
||||
|
||||
// Migrate to new stats/skills format with descriptions
|
||||
if (migrateStatsAndSkillsFormat()) {
|
||||
saveSettings(); // Persist migration
|
||||
}
|
||||
|
||||
// Migrate quests from legacy format to structured format
|
||||
if (migrateQuestsFormat()) {
|
||||
saveSettings(); // Persist migration
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[RPG Companion] Error loading settings:', error);
|
||||
console.error('[RPG Companion] Error details:', error.message, error.stack);
|
||||
@@ -143,13 +140,6 @@ export function saveChatData() {
|
||||
quests: extensionSettings.quests,
|
||||
lastGeneratedData: lastGeneratedData,
|
||||
committedTrackerData: committedTrackerData,
|
||||
// Structured data (JSON format)
|
||||
inventoryV3: extensionSettings.inventoryV3,
|
||||
skillsV2: extensionSettings.skillsV2,
|
||||
skillAbilityLinks: extensionSettings.skillAbilityLinks,
|
||||
infoBoxData: extensionSettings.infoBoxData,
|
||||
charactersData: extensionSettings.charactersData,
|
||||
questsV2: extensionSettings.questsV2,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
@@ -184,6 +174,8 @@ export function updateMessageSwipeData() {
|
||||
infoBox: lastGeneratedData.infoBox,
|
||||
characterThoughts: lastGeneratedData.characterThoughts
|
||||
};
|
||||
|
||||
// console.log('[RPG Companion] Updated message swipe data after user edit');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -195,7 +187,7 @@ export function updateMessageSwipeData() {
|
||||
*/
|
||||
export function loadChatData() {
|
||||
if (!chat_metadata || !chat_metadata.rpg_companion) {
|
||||
// Reset to defaults if no data exists (new chat)
|
||||
// Reset to defaults if no data exists
|
||||
updateExtensionSettings({
|
||||
userStats: {
|
||||
health: 100,
|
||||
@@ -211,29 +203,11 @@ export function loadChatData() {
|
||||
onPerson: "None",
|
||||
stored: {},
|
||||
assets: "None"
|
||||
},
|
||||
skills: "None" // Legacy single-string skills (for Status section)
|
||||
}
|
||||
},
|
||||
quests: {
|
||||
main: "None",
|
||||
optional: []
|
||||
},
|
||||
// Reset structured data fields
|
||||
inventoryV3: {
|
||||
onPerson: [],
|
||||
stored: {},
|
||||
assets: [],
|
||||
simplified: []
|
||||
},
|
||||
skillsV2: {},
|
||||
skillsData: {},
|
||||
skillAbilityLinks: {},
|
||||
skills: { list: [], categories: {} },
|
||||
charactersData: [],
|
||||
infoBoxData: null,
|
||||
questsV2: {
|
||||
main: null,
|
||||
optional: []
|
||||
}
|
||||
});
|
||||
setLastGeneratedData({
|
||||
@@ -273,59 +247,18 @@ export function loadChatData() {
|
||||
};
|
||||
}
|
||||
|
||||
// Restore last generated data (sanitize null values in infoBox)
|
||||
// Restore last generated data
|
||||
if (savedData.lastGeneratedData) {
|
||||
const sanitizedData = { ...savedData.lastGeneratedData };
|
||||
if (sanitizedData.infoBox && typeof sanitizedData.infoBox === 'string') {
|
||||
// Remove lines that contain "null" values
|
||||
sanitizedData.infoBox = sanitizedData.infoBox
|
||||
.split('\n')
|
||||
.filter(line => !line.match(/:\s*null\s*$/i) && !line.match(/:\s*undefined\s*$/i))
|
||||
.join('\n');
|
||||
}
|
||||
setLastGeneratedData(sanitizedData);
|
||||
setLastGeneratedData({ ...savedData.lastGeneratedData });
|
||||
}
|
||||
|
||||
// Restore committed tracker data (sanitize null values in infoBox)
|
||||
// Restore committed tracker data
|
||||
if (savedData.committedTrackerData) {
|
||||
const sanitizedData = { ...savedData.committedTrackerData };
|
||||
if (sanitizedData.infoBox && typeof sanitizedData.infoBox === 'string') {
|
||||
// Remove lines that contain "null" values
|
||||
sanitizedData.infoBox = sanitizedData.infoBox
|
||||
.split('\n')
|
||||
.filter(line => !line.match(/:\s*null\s*$/i) && !line.match(/:\s*undefined\s*$/i))
|
||||
.join('\n');
|
||||
}
|
||||
setCommittedTrackerData(sanitizedData);
|
||||
setCommittedTrackerData({ ...savedData.committedTrackerData });
|
||||
}
|
||||
|
||||
// Restore structured data (JSON format)
|
||||
if (savedData.inventoryV3) {
|
||||
extensionSettings.inventoryV3 = savedData.inventoryV3;
|
||||
}
|
||||
if (savedData.skillsV2) {
|
||||
extensionSettings.skillsV2 = savedData.skillsV2;
|
||||
}
|
||||
if (savedData.skillAbilityLinks) {
|
||||
extensionSettings.skillAbilityLinks = savedData.skillAbilityLinks;
|
||||
}
|
||||
if (savedData.infoBoxData) {
|
||||
extensionSettings.infoBoxData = savedData.infoBoxData;
|
||||
}
|
||||
if (savedData.charactersData) {
|
||||
extensionSettings.charactersData = savedData.charactersData;
|
||||
}
|
||||
if (savedData.questsV2) {
|
||||
extensionSettings.questsV2 = savedData.questsV2;
|
||||
}
|
||||
|
||||
// Migrate quests from legacy format to structured format if needed
|
||||
if (migrateQuestsFormat()) {
|
||||
saveChatData(); // Persist migrated quests to chat metadata
|
||||
}
|
||||
|
||||
// Migrate inventory from v1 (string) to v2 (object) format if needed
|
||||
if (extensionSettings.userStats.inventory) {
|
||||
// Migrate inventory in chat data if feature flag enabled
|
||||
if (FEATURE_FLAGS.useNewInventory && extensionSettings.userStats.inventory) {
|
||||
const migrationResult = migrateInventory(extensionSettings.userStats.inventory);
|
||||
if (migrationResult.migrated) {
|
||||
console.log(`[RPG Companion] Chat inventory migrated from ${migrationResult.source} to v2 format`);
|
||||
@@ -334,12 +267,16 @@ export function loadChatData() {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate inventory structure (Bug #3 fix)
|
||||
validateInventoryStructure(extensionSettings.userStats.inventory, 'chat');
|
||||
|
||||
// console.log('[RPG Companion] Loaded chat data:', savedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and repairs inventory structure to prevent corruption.
|
||||
* Ensures all v2 fields exist and are the correct type.
|
||||
* Fixes Bug #3: Location disappears when switching tabs
|
||||
*
|
||||
* @param {Object} inventory - Inventory object to validate
|
||||
* @param {string} source - Source of load ('settings' or 'chat') for logging
|
||||
@@ -382,6 +319,7 @@ function validateInventoryStructure(inventory, source) {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate stored field (CRITICAL for Bug #3)
|
||||
if (!inventory.stored || typeof inventory.stored !== 'object' || Array.isArray(inventory.stored)) {
|
||||
console.error(`[RPG Companion] Corrupted stored inventory from ${source}, resetting to empty object`);
|
||||
inventory.stored = {};
|
||||
@@ -432,15 +370,13 @@ function migrateToTrackerConfig() {
|
||||
userStats: {
|
||||
customStats: [],
|
||||
showRPGAttributes: true,
|
||||
alwaysSendAttributes: false,
|
||||
allowAIUpdateAttributes: true,
|
||||
rpgAttributes: [
|
||||
{ id: 'str', name: 'STR', description: '', enabled: true },
|
||||
{ id: 'dex', name: 'DEX', description: '', enabled: true },
|
||||
{ id: 'con', name: 'CON', description: '', enabled: true },
|
||||
{ id: 'int', name: 'INT', description: '', enabled: true },
|
||||
{ id: 'wis', name: 'WIS', description: '', enabled: true },
|
||||
{ id: 'cha', name: 'CHA', description: '', enabled: true }
|
||||
{ id: 'str', name: 'STR', enabled: true },
|
||||
{ id: 'dex', name: 'DEX', enabled: true },
|
||||
{ id: 'con', name: 'CON', enabled: true },
|
||||
{ id: 'int', name: 'INT', enabled: true },
|
||||
{ id: 'wis', name: 'WIS', enabled: true },
|
||||
{ id: 'cha', name: 'CHA', enabled: true }
|
||||
],
|
||||
statusSection: {
|
||||
enabled: true,
|
||||
@@ -503,12 +439,12 @@ function migrateToTrackerConfig() {
|
||||
if (extensionSettings.trackerConfig.userStats.showRPGAttributes !== undefined) {
|
||||
const shouldShow = extensionSettings.trackerConfig.userStats.showRPGAttributes;
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes = [
|
||||
{ id: 'str', name: 'STR', description: '', enabled: shouldShow },
|
||||
{ id: 'dex', name: 'DEX', description: '', enabled: shouldShow },
|
||||
{ id: 'con', name: 'CON', description: '', enabled: shouldShow },
|
||||
{ id: 'int', name: 'INT', description: '', enabled: shouldShow },
|
||||
{ id: 'wis', name: 'WIS', description: '', enabled: shouldShow },
|
||||
{ id: 'cha', name: 'CHA', description: '', enabled: shouldShow }
|
||||
{ id: 'str', name: 'STR', enabled: shouldShow },
|
||||
{ id: 'dex', name: 'DEX', enabled: shouldShow },
|
||||
{ id: 'con', name: 'CON', enabled: shouldShow },
|
||||
{ id: 'int', name: 'INT', enabled: shouldShow },
|
||||
{ id: 'wis', name: 'WIS', enabled: shouldShow },
|
||||
{ id: 'cha', name: 'CHA', enabled: shouldShow }
|
||||
];
|
||||
delete extensionSettings.trackerConfig.userStats.showRPGAttributes;
|
||||
console.log('[RPG Companion] Migrated showRPGAttributes to rpgAttributes array');
|
||||
@@ -517,12 +453,12 @@ function migrateToTrackerConfig() {
|
||||
// Ensure rpgAttributes exists even if no migration was needed
|
||||
if (!extensionSettings.trackerConfig.userStats.rpgAttributes) {
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes = [
|
||||
{ id: 'str', name: 'STR', description: '', enabled: true },
|
||||
{ id: 'dex', name: 'DEX', description: '', enabled: true },
|
||||
{ id: 'con', name: 'CON', description: '', enabled: true },
|
||||
{ id: 'int', name: 'INT', description: '', enabled: true },
|
||||
{ id: 'wis', name: 'WIS', description: '', enabled: true },
|
||||
{ id: 'cha', name: 'CHA', description: '', enabled: true }
|
||||
{ id: 'str', name: 'STR', enabled: true },
|
||||
{ id: 'dex', name: 'DEX', enabled: true },
|
||||
{ id: 'con', name: 'CON', enabled: true },
|
||||
{ id: 'int', name: 'INT', enabled: true },
|
||||
{ id: 'wis', name: 'WIS', enabled: true },
|
||||
{ id: 'cha', name: 'CHA', enabled: true }
|
||||
];
|
||||
}
|
||||
|
||||
@@ -605,141 +541,3 @@ function migrateToTrackerConfig() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates stats and skills to new format with description fields.
|
||||
* - customStats: adds description field
|
||||
* - rpgAttributes: adds description field
|
||||
* - skillsSection.customFields: converts from string array to object array
|
||||
* @returns {boolean} true if any migration was performed
|
||||
*/
|
||||
function migrateStatsAndSkillsFormat() {
|
||||
let migrated = false;
|
||||
|
||||
if (!extensionSettings.trackerConfig?.userStats) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const userStats = extensionSettings.trackerConfig.userStats;
|
||||
|
||||
// Migrate customStats - add description if missing
|
||||
if (userStats.customStats) {
|
||||
for (const stat of userStats.customStats) {
|
||||
if (stat && typeof stat === 'object' && stat.description === undefined) {
|
||||
stat.description = '';
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate rpgAttributes - add description if missing
|
||||
if (userStats.rpgAttributes) {
|
||||
for (const attr of userStats.rpgAttributes) {
|
||||
if (attr && typeof attr === 'object' && attr.description === undefined) {
|
||||
attr.description = '';
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate skillsSection.customFields - convert string array to object array
|
||||
if (userStats.skillsSection?.customFields) {
|
||||
const oldFields = userStats.skillsSection.customFields;
|
||||
const hasOldFormat = oldFields.some(f => typeof f === 'string');
|
||||
|
||||
if (hasOldFormat) {
|
||||
console.log('[RPG Companion] Migrating skill categories to new format');
|
||||
userStats.skillsSection.customFields = oldFields.map((field, index) => {
|
||||
if (typeof field === 'string') {
|
||||
return {
|
||||
id: 'skill_' + Date.now() + '_' + index,
|
||||
name: field,
|
||||
description: '',
|
||||
enabled: true
|
||||
};
|
||||
}
|
||||
// Already an object, ensure it has all fields
|
||||
return {
|
||||
id: field.id || 'skill_' + Date.now() + '_' + index,
|
||||
name: field.name || 'Skill',
|
||||
description: field.description || '',
|
||||
enabled: field.enabled !== false
|
||||
};
|
||||
});
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate character stats - add description if missing
|
||||
if (extensionSettings.trackerConfig?.presentCharacters?.characterStats?.customStats) {
|
||||
for (const stat of extensionSettings.trackerConfig.presentCharacters.characterStats.customStats) {
|
||||
if (stat && typeof stat === 'object' && stat.description === undefined) {
|
||||
stat.description = '';
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (migrated) {
|
||||
console.log('[RPG Companion] Stats/skills format migration complete');
|
||||
}
|
||||
|
||||
return migrated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates quests from legacy format to structured format (questsV2).
|
||||
* Legacy format: quests.main (string), quests.optional (string array)
|
||||
* New format: questsV2.main ({name, description}), questsV2.optional (array of {name, description})
|
||||
* @returns {boolean} true if any migration was performed
|
||||
*/
|
||||
function migrateQuestsFormat() {
|
||||
let migrated = false;
|
||||
|
||||
// Initialize questsV2 if it doesn't exist
|
||||
if (!extensionSettings.questsV2) {
|
||||
extensionSettings.questsV2 = {
|
||||
main: null,
|
||||
optional: []
|
||||
};
|
||||
}
|
||||
|
||||
// Migrate main quest if it exists in legacy format but not in new format
|
||||
// Check if legacy format has data AND new format is empty/null
|
||||
if (extensionSettings.quests?.main &&
|
||||
extensionSettings.quests.main !== 'None' &&
|
||||
extensionSettings.quests.main !== '' &&
|
||||
(!extensionSettings.questsV2.main || !extensionSettings.questsV2.main.name)) {
|
||||
extensionSettings.questsV2.main = {
|
||||
name: extensionSettings.quests.main,
|
||||
description: extensionSettings.quests?.mainDescription || ''
|
||||
};
|
||||
migrated = true;
|
||||
console.log('[RPG Companion] Migrated main quest to structured format:', extensionSettings.quests.main);
|
||||
}
|
||||
|
||||
// Migrate optional quests if they exist in legacy format but not in new format
|
||||
// Check if legacy format has data AND new format is empty
|
||||
if (extensionSettings.quests?.optional &&
|
||||
Array.isArray(extensionSettings.quests.optional) &&
|
||||
extensionSettings.quests.optional.length > 0 &&
|
||||
(!extensionSettings.questsV2.optional || extensionSettings.questsV2.optional.length === 0)) {
|
||||
const descriptions = extensionSettings.quests?.optionalDescriptions || [];
|
||||
extensionSettings.questsV2.optional = extensionSettings.quests.optional
|
||||
.filter(title => title && title !== 'None' && title !== '')
|
||||
.map((title, i) => ({
|
||||
name: title,
|
||||
description: descriptions[i] || ''
|
||||
}));
|
||||
if (extensionSettings.questsV2.optional.length > 0) {
|
||||
migrated = true;
|
||||
console.log('[RPG Companion] Migrated optional quests to structured format:', extensionSettings.questsV2.optional.length, 'quests');
|
||||
}
|
||||
}
|
||||
|
||||
if (migrated) {
|
||||
console.log('[RPG Companion] Quests format migration complete');
|
||||
}
|
||||
|
||||
return migrated;
|
||||
}
|
||||
|
||||
+31
-74
@@ -13,25 +13,15 @@ export let extensionSettings = {
|
||||
enabled: true,
|
||||
autoUpdate: true,
|
||||
updateDepth: 4, // How many messages to include in the context
|
||||
messageInterceptionContextDepth: 4, // How many recent messages to send when intercepting user messages
|
||||
generationMode: 'together', // 'separate' or 'together' - whether to generate with main response or separately
|
||||
useSeparatePreset: false, // Use 'RPG Companion Trackers' preset for tracker generation instead of main API model
|
||||
showUserStats: true,
|
||||
showInfoBox: true,
|
||||
showCharacterThoughts: true,
|
||||
showInventory: true, // Show inventory section (v2 system)
|
||||
useSimplifiedInventory: false, // Use simplified single-list inventory instead of categorized (On Person/Stored/Assets)
|
||||
showSkills: false, // Show skills as separate section (moves skills from Status to own tab)
|
||||
enableItemSkillLinks: false, // Enable linking items to skills (item grants skill, removing item removes skill)
|
||||
deleteSkillWithItem: false, // When true, deleting an item also deletes linked skills. When false (default), just unlinks.
|
||||
showQuests: true, // Show quests section
|
||||
showThoughtsInChat: true, // Show thoughts overlay in chat
|
||||
enableHtmlPrompt: false, // Enable immersive HTML prompt injection
|
||||
customHtmlPrompt: '', // Custom HTML prompt text (empty = use default)
|
||||
customTrackerPrompt: '', // Custom tracker instruction prompt (empty = use default)
|
||||
enableMessageInterception: false, // Enable intercepting user messages with LLM rewrite
|
||||
messageInterceptionActive: true, // Runtime toggle to allow/skip interception
|
||||
customMessageInterceptionPrompt: '', // Custom prompt for message interception (empty = default)
|
||||
skipInjectionsForGuided: 'none', // skip injections for instruct injections and quiet prompts (GuidedGenerations compatibility)
|
||||
enablePlotButtons: true, // Show plot progression buttons above chat input
|
||||
panelPosition: 'right', // 'left', 'right', or 'top'
|
||||
@@ -57,74 +47,42 @@ export let extensionSettings = {
|
||||
arousal: 0,
|
||||
mood: '😐',
|
||||
conditions: 'None',
|
||||
/** @type {InventoryV2} Legacy string-based inventory */
|
||||
/** @type {InventoryV2} */
|
||||
inventory: {
|
||||
version: 2,
|
||||
onPerson: "None",
|
||||
stored: {},
|
||||
assets: "None"
|
||||
},
|
||||
skills: "None" // Legacy single-string skills (for Status section)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Structured inventory v3 - items as objects with name, description, and skill links
|
||||
* @type {{onPerson: Array<{name: string, description: string, grantsSkill?: string}>, stored: Object<string, Array>, assets: Array}}
|
||||
*/
|
||||
inventoryV3: {
|
||||
onPerson: [], // Array of { name, description, grantsSkill? }
|
||||
stored: {}, // { locationName: [{ name, description, grantsSkill? }] }
|
||||
assets: [] // Array of { name, description }
|
||||
statNames: {
|
||||
health: 'Health',
|
||||
satiety: 'Satiety',
|
||||
energy: 'Energy',
|
||||
hygiene: 'Hygiene',
|
||||
arousal: 'Arousal'
|
||||
},
|
||||
/**
|
||||
* Structured skills v2 - abilities as objects with name, description, and item links
|
||||
* Key is the skill category name from config
|
||||
* @type {Object<string, Array<{name: string, description: string, grantedBy?: string}>>}
|
||||
*/
|
||||
skillsV2: {
|
||||
// Example: "Combat": [{ name: "Sword Fighting", description: "Blade proficiency", grantedBy: "Iron Sword" }]
|
||||
},
|
||||
/**
|
||||
* Structured info box data (from JSON parsing)
|
||||
*/
|
||||
infoBoxData: {},
|
||||
/**
|
||||
* Structured characters data (from JSON parsing)
|
||||
*/
|
||||
charactersData: [],
|
||||
/**
|
||||
* Structured quests v2 (from JSON parsing)
|
||||
*/
|
||||
questsV2: {
|
||||
main: null,
|
||||
optional: []
|
||||
},
|
||||
// Legacy fields kept for backwards compatibility
|
||||
skills: { list: [], categories: {} },
|
||||
itemSkillLinks: {},
|
||||
skillAbilityLinks: {},
|
||||
skillsData: {},
|
||||
// Tracker customization configuration
|
||||
trackerConfig: {
|
||||
userStats: {
|
||||
// Array of custom stats (allows add/remove/rename)
|
||||
customStats: [
|
||||
{ id: 'health', name: 'Health', description: '', enabled: true },
|
||||
{ id: 'satiety', name: 'Satiety', description: '', enabled: true },
|
||||
{ id: 'energy', name: 'Energy', description: '', enabled: true },
|
||||
{ id: 'hygiene', name: 'Hygiene', description: '', enabled: true },
|
||||
{ id: 'arousal', name: 'Arousal', description: '', enabled: true }
|
||||
{ id: 'health', name: 'Health', enabled: true },
|
||||
{ id: 'satiety', name: 'Satiety', enabled: true },
|
||||
{ id: 'energy', name: 'Energy', enabled: true },
|
||||
{ id: 'hygiene', name: 'Hygiene', enabled: true },
|
||||
{ id: 'arousal', name: 'Arousal', enabled: true }
|
||||
],
|
||||
// RPG Attributes (customizable D&D-style attributes)
|
||||
showRPGAttributes: true,
|
||||
alwaysSendAttributes: false, // If true, always send attributes; if false, only send with dice rolls
|
||||
allowAIUpdateAttributes: true, // If true, allow AI to update attributes from JSON response; if false, attributes are read-only
|
||||
rpgAttributes: [
|
||||
{ id: 'str', name: 'STR', description: '', enabled: true },
|
||||
{ id: 'dex', name: 'DEX', description: '', enabled: true },
|
||||
{ id: 'con', name: 'CON', description: '', enabled: true },
|
||||
{ id: 'int', name: 'INT', description: '', enabled: true },
|
||||
{ id: 'wis', name: 'WIS', description: '', enabled: true },
|
||||
{ id: 'cha', name: 'CHA', description: '', enabled: true }
|
||||
{ id: 'str', name: 'STR', enabled: true },
|
||||
{ id: 'dex', name: 'DEX', enabled: true },
|
||||
{ id: 'con', name: 'CON', enabled: true },
|
||||
{ id: 'int', name: 'INT', enabled: true },
|
||||
{ id: 'wis', name: 'WIS', enabled: true },
|
||||
{ id: 'cha', name: 'CHA', enabled: true }
|
||||
],
|
||||
// Status section config
|
||||
statusSection: {
|
||||
@@ -132,14 +90,11 @@ export let extensionSettings = {
|
||||
showMoodEmoji: true,
|
||||
customFields: ['Conditions'] // User can edit what to track
|
||||
},
|
||||
// Skills section config - array of skill categories
|
||||
// Optional skills field
|
||||
skillsSection: {
|
||||
enabled: false,
|
||||
label: 'Skills', // User-editable section label
|
||||
customFields: [
|
||||
// Each skill category has id, name, description, enabled
|
||||
// Example: { id: 'combat', name: 'Combat', description: 'Fighting and weapon abilities', enabled: true }
|
||||
]
|
||||
label: 'Skills', // User-editable
|
||||
customFields: [] // Array of skill names
|
||||
}
|
||||
},
|
||||
infoBox: {
|
||||
@@ -181,8 +136,8 @@ export let extensionSettings = {
|
||||
characterStats: {
|
||||
enabled: false,
|
||||
customStats: [
|
||||
{ id: 'health', name: 'Health', description: '', enabled: true },
|
||||
{ id: 'arousal', name: 'Arousal', description: '', enabled: true }
|
||||
{ id: 'health', name: 'Health', enabled: true },
|
||||
{ id: 'arousal', name: 'Arousal', enabled: true }
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -271,6 +226,13 @@ export function addDebugLog(message, data = null) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Feature flags for gradual rollout of new features
|
||||
*/
|
||||
export const FEATURE_FLAGS = {
|
||||
useNewInventory: true // Enable v2 inventory system with categorized storage
|
||||
};
|
||||
|
||||
/**
|
||||
* Fallback avatar image (base64-encoded SVG with "?" icon)
|
||||
* Using base64 to avoid quote-encoding issues in HTML attributes
|
||||
@@ -285,7 +247,6 @@ export let $userStatsContainer = null;
|
||||
export let $infoBoxContainer = null;
|
||||
export let $thoughtsContainer = null;
|
||||
export let $inventoryContainer = null;
|
||||
export let $skillsContainer = null;
|
||||
export let $questsContainer = null;
|
||||
|
||||
/**
|
||||
@@ -355,10 +316,6 @@ export function setInventoryContainer($element) {
|
||||
$inventoryContainer = $element;
|
||||
}
|
||||
|
||||
export function setSkillsContainer($element) {
|
||||
$skillsContainer = $element;
|
||||
}
|
||||
|
||||
export function setQuestsContainer($element) {
|
||||
$questsContainer = $element;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user