Make RPG attributes (STR/DEX/etc) customizable and editable
- Replace showRPGAttributes boolean with rpgAttributes array in trackerConfig - Add RPG Attributes section in Edit Trackers with add/remove/rename/toggle - Dynamically generate attribute display from config in userStats.js - Add migration from old showRPGAttributes to new rpgAttributes array - Initialize new attributes with default value of 10 in classicStats - Default attributes: STR, DEX, CON, INT, WIS, CHA (all enabled)
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"chat_completion_source": "custom",
|
||||
"openai_model": "gpt-5-2025-08-07",
|
||||
"claude_model": "claude-sonnet-4-0",
|
||||
"openrouter_model": "anthropic/claude-sonnet-4.5",
|
||||
"openrouter_use_fallback": false,
|
||||
"openrouter_group_models": true,
|
||||
"openrouter_sort_models": "context_length",
|
||||
"openrouter_providers": [],
|
||||
"openrouter_allow_fallbacks": false,
|
||||
"openrouter_middleout": "off",
|
||||
"ai21_model": "jamba-1.5-large",
|
||||
"mistralai_model": "mistral-large-latest",
|
||||
"cohere_model": "command-r-plus",
|
||||
"perplexity_model": "",
|
||||
"groq_model": "llama3-70b-8192",
|
||||
"xai_model": "grok-3-beta",
|
||||
"pollinations_model": "openai",
|
||||
"aimlapi_model": "gpt-4o-mini-2024-07-18",
|
||||
"electronhub_model": "gpt-4o-mini",
|
||||
"electronhub_sort_models": "alphabetically",
|
||||
"electronhub_group_models": false,
|
||||
"moonshot_model": "kimi-latest",
|
||||
"fireworks_model": "accounts/fireworks/models/kimi-k2-instruct",
|
||||
"cometapi_model": "gpt-4o",
|
||||
"zai_model": "glm-4.6",
|
||||
"custom_model": "claude-opus-4-1-20250805-thinking-16k-v2",
|
||||
"custom_prompt_post_processing": "semi",
|
||||
"google_model": "gemini-2.0-flash-thinking-exp-01-21",
|
||||
"vertexai_model": "gemini-2.0-flash-001",
|
||||
"nanogpt_model": "gpt-4o-mini",
|
||||
"deepseek_model": "chatgpt-4o-latest",
|
||||
"azure_api_version": "2024-02-15-preview",
|
||||
"azure_openai_model": "",
|
||||
"temperature": 1,
|
||||
"frequency_penalty": 0,
|
||||
"presence_penalty": 0,
|
||||
"top_p": 1,
|
||||
"top_k": 0,
|
||||
"top_a": 1,
|
||||
"min_p": 0,
|
||||
"repetition_penalty": 1,
|
||||
"openai_max_context": 2000000,
|
||||
"openai_max_tokens": 8192,
|
||||
"wrap_in_quotes": false,
|
||||
"names_behavior": -1,
|
||||
"send_if_empty": "",
|
||||
"impersonation_prompt": "Change of plans! Write a response as the user's {{user}} now. Match their style from the conversation history so far.",
|
||||
"new_chat_prompt": "",
|
||||
"new_group_chat_prompt": "",
|
||||
"new_example_chat_prompt": "{{trim}}",
|
||||
"continue_nudge_prompt": "Your last message got cut off. Continue writing it. Do not include any parts of the original one. Respond with a direct continuation only.",
|
||||
"bias_preset_selected": "Marinara's Logit Bias",
|
||||
"max_context_unlocked": false,
|
||||
"wi_format": "{0}",
|
||||
"scenario_format": "{{scenario}}",
|
||||
"personality_format": "{{personality}}{{trim}}",
|
||||
"group_nudge_prompt": "",
|
||||
"stream_openai": true,
|
||||
"show_external_models": false,
|
||||
"assistant_prefill": "",
|
||||
"assistant_impersonation": "",
|
||||
"claude_use_sysprompt": true,
|
||||
"use_makersuite_sysprompt": false,
|
||||
"squash_system_messages": true,
|
||||
"image_inlining": true,
|
||||
"inline_image_quality": "high",
|
||||
"bypass_status_check": false,
|
||||
"continue_prefill": false,
|
||||
"seed": -1,
|
||||
"n": 1
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
[
|
||||
{
|
||||
"scriptName": "RPG: Clean HTML (From Outgoing Prompt)",
|
||||
"findRegex": "/\\s?<(?!\\!--)(?:\"[^\"]*\"|'[^']*'|[^'\">])*>/g",
|
||||
"replaceString": "",
|
||||
"trimStrings": [],
|
||||
"placement": [2],
|
||||
"disabled": false,
|
||||
"markdownOnly": false,
|
||||
"promptOnly": true,
|
||||
"runOnEdit": true,
|
||||
"substituteRegex": 0,
|
||||
"minDepth": null,
|
||||
"maxDepth": null
|
||||
},
|
||||
{
|
||||
"scriptName": "RPG: Clean Tracker Blocks (Keeping Last)",
|
||||
"findRegex": "/```\\n[\\s\\S]*?\\n---\\n[\\s\\S]*?```\\n+/g",
|
||||
"replaceString": "",
|
||||
"trimStrings": [],
|
||||
"placement": [1, 2],
|
||||
"disabled": false,
|
||||
"markdownOnly": false,
|
||||
"promptOnly": true,
|
||||
"runOnEdit": true,
|
||||
"substituteRegex": 0,
|
||||
"minDepth": 3,
|
||||
"maxDepth": null
|
||||
}
|
||||
]
|
||||
@@ -118,6 +118,9 @@ import { ensureHtmlCleaningRegex, detectConflictingRegexScripts } from './src/sy
|
||||
import { setupMemoryRecollectionButton, updateMemoryRecollectionButton } from './src/systems/features/memoryRecollection.js';
|
||||
import { initLorebookLimiter } from './src/systems/features/lorebookLimiter.js';
|
||||
|
||||
// Utility modules
|
||||
import { importAllDefaults } from './src/utils/importDefaults.js';
|
||||
|
||||
// Integration modules
|
||||
import {
|
||||
commitTrackerData,
|
||||
@@ -601,6 +604,14 @@ jQuery(async () => {
|
||||
// Non-critical - continue anyway
|
||||
}
|
||||
|
||||
// Import default preset and regexes if user doesn't have them
|
||||
try {
|
||||
await importAllDefaults();
|
||||
} catch (error) {
|
||||
console.error('[RPG Companion] Failed to import defaults:', error);
|
||||
// Non-critical - continue anyway
|
||||
}
|
||||
|
||||
// Register all event listeners
|
||||
try {
|
||||
registerAllEvents({
|
||||
|
||||
+44
-1
@@ -365,7 +365,14 @@ function migrateToTrackerConfig() {
|
||||
extensionSettings.trackerConfig = {
|
||||
userStats: {
|
||||
customStats: [],
|
||||
showRPGAttributes: true,
|
||||
rpgAttributes: [
|
||||
{ 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,
|
||||
showMoodEmoji: true,
|
||||
@@ -423,6 +430,42 @@ function migrateToTrackerConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate old showRPGAttributes boolean to rpgAttributes array
|
||||
if (extensionSettings.trackerConfig.userStats.showRPGAttributes !== undefined) {
|
||||
const shouldShow = extensionSettings.trackerConfig.userStats.showRPGAttributes;
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes = [
|
||||
{ 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');
|
||||
}
|
||||
|
||||
// Ensure rpgAttributes exists even if no migration was needed
|
||||
if (!extensionSettings.trackerConfig.userStats.rpgAttributes) {
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes = [
|
||||
{ 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 }
|
||||
];
|
||||
}
|
||||
|
||||
// Ensure all rpgAttributes have corresponding values in classicStats
|
||||
if (extensionSettings.classicStats) {
|
||||
for (const attr of extensionSettings.trackerConfig.userStats.rpgAttributes) {
|
||||
if (extensionSettings.classicStats[attr.id] === undefined) {
|
||||
extensionSettings.classicStats[attr.id] = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate old presentCharacters structure to new format
|
||||
if (extensionSettings.trackerConfig.presentCharacters) {
|
||||
const pc = extensionSettings.trackerConfig.presentCharacters;
|
||||
|
||||
+9
-2
@@ -71,8 +71,15 @@ export let extensionSettings = {
|
||||
{ id: 'hygiene', name: 'Hygiene', enabled: true },
|
||||
{ id: 'arousal', name: 'Arousal', enabled: true }
|
||||
],
|
||||
// RPG Attributes toggle
|
||||
showRPGAttributes: true,
|
||||
// RPG Attributes (customizable D&D-style attributes)
|
||||
rpgAttributes: [
|
||||
{ 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: {
|
||||
enabled: true,
|
||||
|
||||
@@ -86,7 +86,14 @@ export function renderUserStats() {
|
||||
{ id: 'hygiene', name: 'Hygiene', enabled: true },
|
||||
{ id: 'arousal', name: 'Arousal', enabled: true }
|
||||
],
|
||||
showRPGAttributes: true,
|
||||
rpgAttributes: [
|
||||
{ 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, showMoodEmoji: true, customFields: ['Conditions'] },
|
||||
skillsSection: { enabled: false, label: 'Skills' }
|
||||
};
|
||||
@@ -171,60 +178,32 @@ export function renderUserStats() {
|
||||
|
||||
html += '</div>'; // Close rpg-stats-left
|
||||
|
||||
// RPG Attributes section (conditionally rendered)
|
||||
if (config.showRPGAttributes) {
|
||||
// RPG Attributes section (dynamically generated from config)
|
||||
const rpgAttributes = config.rpgAttributes || [];
|
||||
const enabledAttributes = rpgAttributes.filter(attr => attr && attr.enabled && attr.name && attr.id);
|
||||
|
||||
if (enabledAttributes.length > 0) {
|
||||
html += `
|
||||
<div class="rpg-stats-right">
|
||||
<div class="rpg-classic-stats">
|
||||
<div class="rpg-classic-stats-grid">
|
||||
<div class="rpg-classic-stat" data-stat="str">
|
||||
<span class="rpg-classic-stat-label">STR</span>
|
||||
`;
|
||||
|
||||
enabledAttributes.forEach(attr => {
|
||||
const value = extensionSettings.classicStats[attr.id] !== undefined ? extensionSettings.classicStats[attr.id] : 10;
|
||||
html += `
|
||||
<div class="rpg-classic-stat" data-stat="${attr.id}">
|
||||
<span class="rpg-classic-stat-label">${attr.name}</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
<button class="rpg-classic-stat-btn rpg-stat-decrease" data-stat="str">−</button>
|
||||
<span class="rpg-classic-stat-value">${extensionSettings.classicStats.str}</span>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-increase" data-stat="str">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-classic-stat" data-stat="dex">
|
||||
<span class="rpg-classic-stat-label">DEX</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
<button class="rpg-classic-stat-btn rpg-stat-decrease" data-stat="dex">−</button>
|
||||
<span class="rpg-classic-stat-value">${extensionSettings.classicStats.dex}</span>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-increase" data-stat="dex">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-classic-stat" data-stat="con">
|
||||
<span class="rpg-classic-stat-label">CON</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
<button class="rpg-classic-stat-btn rpg-stat-decrease" data-stat="con">−</button>
|
||||
<span class="rpg-classic-stat-value">${extensionSettings.classicStats.con}</span>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-increase" data-stat="con">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-classic-stat" data-stat="int">
|
||||
<span class="rpg-classic-stat-label">INT</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
<button class="rpg-classic-stat-btn rpg-stat-decrease" data-stat="int">−</button>
|
||||
<span class="rpg-classic-stat-value">${extensionSettings.classicStats.int}</span>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-increase" data-stat="int">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-classic-stat" data-stat="wis">
|
||||
<span class="rpg-classic-stat-label">WIS</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
<button class="rpg-classic-stat-btn rpg-stat-decrease" data-stat="wis">−</button>
|
||||
<span class="rpg-classic-stat-value">${extensionSettings.classicStats.wis}</span>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-increase" data-stat="wis">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rpg-classic-stat" data-stat="cha">
|
||||
<span class="rpg-classic-stat-label">CHA</span>
|
||||
<div class="rpg-classic-stat-buttons">
|
||||
<button class="rpg-classic-stat-btn rpg-stat-decrease" data-stat="cha">−</button>
|
||||
<span class="rpg-classic-stat-value">${extensionSettings.classicStats.cha}</span>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-increase" data-stat="cha">+</button>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-decrease" data-stat="${attr.id}">−</button>
|
||||
<span class="rpg-classic-stat-value">${value}</span>
|
||||
<button class="rpg-classic-stat-btn rpg-stat-increase" data-stat="${attr.id}">+</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -127,7 +127,14 @@ function resetToDefaults() {
|
||||
{ id: 'hygiene', name: 'Hygiene', enabled: true },
|
||||
{ id: 'arousal', name: 'Arousal', enabled: true }
|
||||
],
|
||||
showRPGAttributes: true,
|
||||
rpgAttributes: [
|
||||
{ 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,
|
||||
showMoodEmoji: true,
|
||||
@@ -212,11 +219,31 @@ function renderUserStatsTab() {
|
||||
html += '</div>';
|
||||
html += '<button class="rpg-btn-secondary" id="rpg-add-stat"><i class="fa-solid fa-plus"></i> Add Custom Stat</button>';
|
||||
|
||||
// RPG Attributes toggle
|
||||
html += '<div class="rpg-editor-toggle-row">';
|
||||
html += `<input type="checkbox" id="rpg-show-rpg-attrs" ${config.showRPGAttributes ? 'checked' : ''}>`;
|
||||
html += '<label for="rpg-show-rpg-attrs">Show RPG Attributes (STR, DEX, etc.)</label>';
|
||||
// RPG Attributes section
|
||||
html += '<h4><i class="fa-solid fa-dice-d20"></i> RPG Attributes</h4>';
|
||||
html += '<div class="rpg-editor-stats-list" id="rpg-editor-attrs-list">';
|
||||
|
||||
const rpgAttributes = config.rpgAttributes || [
|
||||
{ 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 }
|
||||
];
|
||||
|
||||
rpgAttributes.forEach((attr, index) => {
|
||||
html += `
|
||||
<div class="rpg-editor-stat-item" data-index="${index}">
|
||||
<input type="checkbox" ${attr.enabled ? 'checked' : ''} class="rpg-attr-toggle" data-index="${index}">
|
||||
<input type="text" value="${attr.name}" class="rpg-attr-name" data-index="${index}" placeholder="Attribute Name">
|
||||
<button class="rpg-attr-remove" data-index="${index}" title="Remove attribute"><i class="fa-solid fa-trash"></i></button>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
html += '<button class="rpg-btn-secondary" id="rpg-add-attr"><i class="fa-solid fa-plus"></i> Add Attribute</button>';
|
||||
|
||||
// Status Section
|
||||
html += '<h4><i class="fa-solid fa-face-smile"></i> Status Section</h4>';
|
||||
@@ -287,9 +314,41 @@ function setupUserStatsListeners() {
|
||||
extensionSettings.trackerConfig.userStats.customStats[index].name = $(this).val();
|
||||
});
|
||||
|
||||
// RPG attributes toggle
|
||||
$('#rpg-show-rpg-attrs').off('change').on('change', function() {
|
||||
extensionSettings.trackerConfig.userStats.showRPGAttributes = $(this).is(':checked');
|
||||
// Add attribute
|
||||
$('#rpg-add-attr').off('click').on('click', function() {
|
||||
if (!extensionSettings.trackerConfig.userStats.rpgAttributes) {
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes = [];
|
||||
}
|
||||
const newId = 'attr_' + Date.now();
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes.push({
|
||||
id: newId,
|
||||
name: 'NEW',
|
||||
enabled: true
|
||||
});
|
||||
// Initialize value in classicStats if doesn't exist
|
||||
if (extensionSettings.classicStats[newId] === undefined) {
|
||||
extensionSettings.classicStats[newId] = 10;
|
||||
}
|
||||
renderUserStatsTab();
|
||||
});
|
||||
|
||||
// Remove attribute
|
||||
$('.rpg-attr-remove').off('click').on('click', function() {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes.splice(index, 1);
|
||||
renderUserStatsTab();
|
||||
});
|
||||
|
||||
// Toggle attribute
|
||||
$('.rpg-attr-toggle').off('change').on('change', function() {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes[index].enabled = $(this).is(':checked');
|
||||
});
|
||||
|
||||
// Rename attribute
|
||||
$('.rpg-attr-name').off('blur').on('blur', function() {
|
||||
const index = $(this).data('index');
|
||||
extensionSettings.trackerConfig.userStats.rpgAttributes[index].name = $(this).val();
|
||||
});
|
||||
|
||||
// Status section toggles
|
||||
|
||||
Reference in New Issue
Block a user