JAI’s Script Documentation (ES5 Sandbox)
Getting Started
Scripts allow you to dynamically modify character behavior during conversations.
Your script has access to a context object that contains character data and chat information.
What are Scripts?
Scripts are JavaScript functions that run during chat conversations to:
Modify character personality based on conversation flow
Update scenario details dynamically
Inject context-aware information
Create adaptive character responses
When Scripts Run
Scripts execute:
Before each character response
After receiving user messages
When conversation context changes
Scripts run synchronously — avoid heavy computations.
Context Object Reference
The context object is your gateway to character and chat data.
Character Properties
[Link] = {
name: string, // Character's name
chat_name: string, // Name used in chat
example_dialogs: string, // Example conversations (modifiable)
personality: string, // Core personality traits (modifiable)
scenario: string // Current scenario/setting (modifiable)
}
Only personality and scenario should be modified in scripts. Other properties are read-only.
Chat Properties
[Link] = {
message_count: number, // Total messages in conversation
last_message: string, // Most recent user message
first_message_date?: Date, // When conversation started (optional)
last_bot_message_date?: Date // Last bot response time (optional)
}
Chat properties are read-only and cannot be modified.
Helper Functions
Helper functions for advanced lorebook functionality:
[Link] = {
sillytavern: {
TranslateSillyTavernLorebook(
context, // ScriptContextV1
loreEntries // SillyTavernLorebookEntry[]
) /* returns ScriptContextV1 */
}
}
TranslateSillyTavernLorebook processes lorebook entries with filters, priorities, and triggers. See the Advanced Lore example for usage.
Sandbox Environment
The script sandbox provides a secure environment with limited JavaScript features.
Available Globals
// Available globals:
Math // [Link], [Link], etc.
JSON // [Link], [Link]
Array // [Link], [Link]
Object // [Link], [Link], [Link], [Link]
String // String constructor
Number // Number constructor
Boolean // Boolean constructor
Date // Date constructor and methods
console // [Link], [Link], [Link]
Map // Map constructor
Set // Set constructor
RegExp // Regular expressions
Limitations (ES5 only)
The following JavaScript features are NOT supported:
ES6+ destructuring (const {chat} = context)
Spread operator (...array)
Template literals with complex expressions
Async/await and Promises
Import/export statements
Classes and class syntax
Generators and iterators
External API calls (fetch, XMLHttpRequest)
DOM manipulation
setTimeout, setInterval
Always access properties directly: [Link].message_count ( ) — not const {message_count} = [Link] ( ).
Return Behavior
Scripts automatically return the modified context. You don't need to add return context at the end.
// Correct - no return needed
if ([Link].message_count > 5) {
[Link] += ', friendly and casual';
}
// Also correct - explicit early exit
if (someCondition) {
return; // Early exit without modifications
}
Code Examples (Quick Patterns)
Dynamic Personality (by length)
// Character becomes more friendly over time
if ([Link].message_count > 10) {
[Link] += ', warmed up to the user and now more friendly';
}
Time-Based Changes
var hour = new Date().getHours();
if (hour < 6 || hour > 22) {
[Link] += "\n\nYou're feeling sleepy and your responses are a bit drowsy.";
[Link] += " It's late at night, and everything is quiet.";
}
Message Analysis
var lastMsg = [Link].last_message.toLowerCase();
if ([Link]('help') || [Link]('assist')) {
[Link] += "\n\nYou're particularly eager to be helpful right now.";
}
// Track emotional keywords
var emotions = ['happy', 'sad', 'angry', 'excited'];
var detectedEmotion = null;
for (var i = 0; i < [Link]; i++) {
if ([Link](emotions[i])) { detectedEmotion = emotions[i]; break; }
}
if (detectedEmotion) {
[Link] += ' The user seems to be feeling ' + detectedEmotion + '.';
}
Best Practices
Performance Tips
Keep scripts lightweight — they run on every message
Avoid complex calculations or deep loops
Don’t make external API calls (not supported)
Avoid ES6+ features like destructuring/spread operators
Cache repeated calculations when possible
The sandbox has limited JS support. Test features before relying on them.
Error Handling
try {
// Your script logic here
if ([Link].last_message) {
// Safe to use last_message
}
} catch (error) {
[Link]('Script error:', error);
// Script continues with original context
}
Debugging Tips
Use [Link]() to inspect values
Test with various message counts/content
Check the Debug Panel for applied changes
Start simple, then add complexity
[Link]('Message count:', [Link].message_count);
[Link]('Last message:', [Link].last_message);
[Link]('Current personality:', [Link]);
Common Patterns
Simple Memory System
Create a basic memory system using the scenario field:
// Extract memories from previous interactions
var memories = [];
if ([Link].last_message && [Link].last_message.toLowerCase().includes('my name is')) {
var nameMatch = [Link].last_message.match(/my name is (\w+)/i);
if (nameMatch) {
[Link]("User's name is " + nameMatch[1]);
}
}
// Add memories to scenario
if ([Link] > 0) {
[Link] += ' Things you remember: ' + [Link](', ');
}
Relationship Development
var messageCount = [Link].message_count;
var relationship = 'stranger';
if (messageCount > 5) relationship = 'acquaintance';
if (messageCount > 15) relationship = 'friend';
if (messageCount > 30) relationship = 'close friend';
[Link] += ', you view the user as a ' + relationship;
// Adjust formality based on relationship
if (relationship === 'close friend') {
[Link] += ', speaks casually and uses informal language';
}
Progressive Example Scripts (Least → Most Complex)
Each example includes: what it does, how it differs, why you’d use it, and full ES5-safe code.
1) Minimal Regex Keyword Match ([Link])
What: Single regex test → append personality.
Diff: Absolute baseline (no arrays/loops).
Use: Tiny, single-purpose trigger.
var message = String([Link].last_message || '');
if (/\b(corleone|mafia|family|godfather)\b/[Link](message)) {
[Link] += ', they are the most powerful and organized crime family in the city, but they don’t touch women or children';
}
2) Minimal .includes() Match (Basic [Link])
What: Single keyword check → append scenario.
Diff: Simpler than regex, still one-off.
Use: Easiest beginner trigger.
if ([Link].last_message.toLowerCase().includes('hello')) {
[Link] += " They greet you warmly.";
}
3) Array-Based Basic Template (Basic Template [Link])
What: Multiple keyword groups in an array; apply personality/scenario.
Diff: Scales without duplicating if blocks.
Use: Maintain many simple triggers in one place.
var keywords = [
{
words: ['hello', 'hi', 'hey'],
scenario: "They greet you warmly.",
personality: ", is feeling friendly and welcoming"
}
];
var message = [Link].last_message.toLowerCase();
for (var i = 0; i < [Link]; i++) {
var entry = keywords[i];
var hasKeyword = false;
for (var j = 0; j < [Link]; j++) {
if ([Link]([Link][j])) { hasKeyword = true; break; }
}
if (hasKeyword) {
if ([Link]) [Link] += [Link];
if ([Link]) [Link] += [Link];
}
}
[Link]('Message count:', [Link].message_count);
4) Simple Lorebook (Priority, Personality-Only) (Simple [Link])
What: Collect matches → sort by priority → apply top personality only.
Diff: Adds conflict resolution via priority.
Use: Ensure only the most important trait applies.
var lorebook = [
{
name: "Godfather / Damien",
keywords: ["godfather", "damien"],
priority: 10,
personality: ", Damien, the Godfather himself, is a calculating and charismatic leader who commands loyalty through quiet intimidation and unshakable control"
},
{
name: "Family",
keywords: ["corleone", "mafia", "family"],
priority: 5,
personality: ", they are the most powerful and organized crime family in the city, but they don’t touch women or children"
}
];
var lastMessage = [Link].last_message.toLowerCase();
var activatedEntries = [];
[Link](function(entry) {
var hasKeyword = [Link](function(keyword) { return [Link](keyword); });
if (hasKeyword) [Link](entry);
});
[Link](function(a, b) { return [Link] - [Link]; });
if ([Link] > 0) {
var top = activatedEntries[0];
if () {
[Link] += [Link];
}
}
5) Simple Array (Personality-Only) (Simple [Link])
What: Array of keyword groups → append personality only.
Diff: Same as #3 but no scenario.
Use: Hidden trait shaping without scene changes.
var lore = [
{
keywords: ['corleone', 'mafia', 'family', 'godfather'],
personality: ', they are the most powerful and organized crime family in the city, but they don’t touch women or children'
}
];
var message = [Link].last_message.toLowerCase();
for (var i = 0; i < [Link]; i++) {
var entry = lore[i], hasKeyword = false;
for (var j = 0; j < [Link]; j++) {
if ([Link]([Link][j])) { hasKeyword = true; break; }
}
if (hasKeyword) [Link] += [Link];
}
6) Simple Lorebook Scenario Array (Simple Lorebook Scenario [Link])
What: Priority + apply personality and scenario (highest only).
Diff: Extends #4 by also adjusting scene.
Use: Keyword-driven lore that sets the scene.
var lorebook = [
{
name: "Godfather / Damien",
keywords: ["godfather", "damien"],
priority: 10,
personality: ", Damien, the Godfather himself, is a calculating and charismatic leader who commands loyalty through quiet intimidation and unshakable control",
scenario: "The Godfather is in a tense meeting with a rival family, his demeanor cool and calculating."
},
{
name: "Family",
keywords: ["corleone", "mafia", "family"],
priority: 5,
personality: ", they are the most powerful and organized crime family in the city, but they don’t touch women or children",
scenario: "The corleone mafia family has spread through the city."
}
];
var lastMessage = [Link].last_message.toLowerCase();
var activatedEntries = [];
[Link](function(entry) {
var hasKeyword = [Link](function(keyword) { return [Link](keyword); });
if (hasKeyword) [Link](entry);
});
[Link](function(a, b) { return [Link] - [Link]; });
if ([Link] > 0) {
var top = activatedEntries[0];
if ([Link] && ) {
[Link] += [Link];
}
if ([Link] && ) {
[Link] += [Link];
}
}
7) Dynamic Lorebook Template (Procedural) (Dynamic Lorebook [Link])
What: Pure if / else checks (no arrays) for lore; includes a time-gated secret.
Diff: Alternate style to #8 (array) that non-coders may find simpler.
Use: Easy copy-paste edits without touching arrays.
/**
* Dynamic Lore Book System
* Character reveals backstory and world knowledge based on keywords
*/
// Analyze last message for lore triggers
var lastMessage = [Link].last_message.toLowerCase();
// Fantasy/Magic lore
if ([Link]('magic') || [Link]('spell') || [Link]('wizard')) {
[Link] += ', knowledgeable about magical arts and ancient spells';
[Link] += ' {{char}} has studied magic for years and can sense magical energies around them.';
}
if ([Link]('dragon') || [Link]('beast') || [Link]('monster')) {
[Link] += ', experienced with dangerous creatures and their behaviors';
[Link] += ' {{char}} has encountered many mythical beasts and knows their weaknesses.';
}
// Historical/Background lore
if ([Link]('war') || [Link]('battle') || [Link]('soldier')) {
if ([Link]('war') || [Link]('battle') || [Link]('soldier')) {
[Link] += ', haunted by memories of past conflicts';
[Link] += ' {{char}} served in the Great War and bears both visible and invisible scars.';
}
if ([Link]('family') || [Link]('parent') || [Link]('childhood')) {
[Link] += ', shaped by a complex family history';
[Link] += ' {{char}} grew up in a noble house but left to forge their own path.';
}
// Location/World lore
if ([Link]('forest') || [Link]('woods') || [Link]('tree')) {
[Link] += ', deeply connected to nature and forest spirits';
[Link] += ' {{char}} spent their youth in the Whispering Woods, learning druidic ways.';
}
if ([Link]('city') || [Link]('town') || [Link]('street')) {
[Link] += ', street-smart and familiar with urban politics';
[Link] += ' {{char}} knows every alley and hidden passage in the capital city.';
}
// Profession/Skill lore
if ([Link]('sword') || [Link]('fight') || [Link]('weapon')) {
[Link] += ', disciplined in the ancient fighting arts';
[Link] += ' {{char}} trained under Master Korin, learning the Seven Sacred Stances.';
}
if ([Link]('book') || [Link]('knowledge') || [Link]('study')) {
[Link] += ', scholarly and well-versed in ancient texts';
[Link] += ' {{char}} spent decades in the Great Library, mastering forbidden knowledge.';
}
// Mysterious/Secret lore - only after some conversation
if ([Link].message_count > 15) {
if ([Link]('secret') || [Link]('hidden') || [Link]('truth')) {
[Link] += ', keeper of ancient secrets that could change everything';
[Link] += ' {{char}} knows the truth about the Sundering, but speaks of it only in whispers.';
}
}
8) Dynamic Lorebook Array (Dynamic Lorebook [Link])
What: Array of lore entries with optional minMessages gates.
Diff: Same features as #7 but data-driven.
Use: Editors can add rows without touching logic.
/**
* Dynamic Lore Book System
* Character reveals backstory and world knowledge based on keywords
*/
// Your Lore Entries
var dynamicLore = [
// === Fantasy/Magic lore ===
{ keywords: ['magic', 'spell', 'wizard'],
personality: ', knowledgeable about magical arts and ancient spells',
scenario: ' {{char}} has studied magic for years and can sense magical energies around them.' },
{ keywords: ['dragon', 'beast', 'monster'],
personality: ', experienced with dangerous creatures and their behaviors',
scenario: ' {{char}} has encountered many mythical beasts and knows their weaknesses.' },
// === Historical/Background lore ===
{ keywords: ['war', 'battle', 'soldier'],
personality: ', haunted by memories of past conflicts',
scenario: ' {{char}} served in the Great War and bears both visible and invisible scars.' },
{ keywords: ['family', 'parent', 'childhood'],
personality: ', shaped by a complex family history',
scenario: ' {{char}} grew up in a noble house but left to forge their own path.' },
// === Location/World lore ===
{ keywords: ['forest', 'woods', 'tree'],
personality: ', deeply connected to nature and forest spirits',
scenario: ' {{char}} spent their youth in the Whispering Woods, learning druidic ways.' },
{ keywords: ['city', 'town', 'street'],
{ keywords: ['city', 'town', 'street'],
personality: ', street-smart and familiar with urban politics',
scenario: ' {{char}} knows every alley and hidden passage in the capital city.' },
// === Profession/Skill lore ===
{ keywords: ['sword', 'fight', 'weapon'],
personality: ', disciplined in the ancient fighting arts',
scenario: ' {{char}} trained under Master Korin, learning the Seven Sacred Stances.' },
{ keywords: ['book', 'knowledge', 'study'],
personality: ', scholarly and well-versed in ancient texts',
scenario: ' {{char}} spent decades in the Great Library, mastering forbidden knowledge.' },
// === Mysterious/Secret lore (Timing Tested) ===
{ keywords: ['secret', 'hidden', 'truth'], minMessages: 0, maxMessages: 15,
personality: ', keeper of ancient secrets is a myth',
scenario: ' {{char}} knows the truth about the Sundering, but will not speak about it.' },
{ keywords: ['secret', 'hidden', 'truth'], minMessages: 16, maxMessages: 30,
personality: ', keeper of ancient secrets that could change everything',
scenario: ' {{char}} knows the truth about the Sundering, but speaks of it only in whispers.' }
];
var lastMessage = [Link].last_message.toLowerCase();
var messageCount = [Link].message_count;
// Loop through each lore entry
for (var i = 0; i < [Link]; i++) {
var entry = dynamicLore[i];
if ([Link] && messageCount < [Link]) continue;
// Check keywords
var hasKeyword = false;
for (var j = 0; j < [Link]; j++) {
if ([Link]([Link][j])) { hasKeyword = true; break; }
}
if (hasKeyword) {
if ([Link]) [Link] += [Link];
if ([Link]) [Link] += [Link];
}
}
9) Dynamic Scenarios Template (Procedural) (Dynamic Scenarios [Link])
What: Location keywords + timed events (specific counts).
Diff: Procedural counterpart to the array-based event script.
Use: Easy knobs for beginners.
/**
* Dynamic Scenario Events
* Triggers special events or changes based on keywords or message count
*/
// Get current conversation context
var lastMessage = [Link].last_message.toLowerCase();
// Location-based events
if ([Link]('restaurant') || [Link]('cafe')) {
[Link] += ' The cozy establishment has ambient sounds of clinking dishes and soft music.';
[Link] += ', notices and comments on the atmosphere around them';
}
if ([Link]('park') || [Link]('outside')) {
[Link] += ' They are outdoors with natural surroundings and fresh air.';
[Link] += ', observant of nature and weather';
}
// Time-based special events
if ([Link].message_count === 10) {
[Link] += ' Suddenly, their phone rings with an unexpected call.';
[Link] += ', momentarily distracted by unexpected interruptions';
}
if ([Link].message_count === 25) {
[Link] += ' The weather suddenly changes around them.';
[Link] += ', reactive to environmental changes';
}
// Keyword-triggered events
if ([Link]('secret')) {
[Link] += ', becomes mysterious when secrets are mentioned';
[Link] += ' {{char}} becomes slightly more mysterious and thoughtful.';
}
if ([Link]('music') || [Link]('song')) {
[Link] += ', enthusiastic about music';
[Link] += ' {{char}} shows enthusiasm about music and might share favorites.';
}
[Link]('Message count:', [Link].message_count);
10) Relationship Progression Template (Relationship Progression [Link])
What: Pure timing → relationship stage changes.
Diff: No keywords; simple pacing arc.
Use: Formal → casual → close tone shifts.
/**
* Dynamic Relationship Progression
* Character's behavior evolves based on conversation length
*/
// Define relationship stages based on message count
var messageCount = [Link].message_count;
if (messageCount < 5) {
// First meeting - formal and cautious
[Link] += ", polite but maintains professional distance";
[Link] += " This is their first meeting, so they are careful and observant.";
} else if (messageCount < 15) {
// Getting comfortable - warming up
[Link] += ", becoming more comfortable and casual";
[Link] += " They are warming up and becoming more relaxed in conversation.";
} else if (messageCount < 30) {
// Friends - open and relaxed
[Link] += ", friendly and open";
[Link] += " They feel comfortable and speak openly as friends.";
} else {
// Close friends - deep connection
[Link] += ", trusting and deeply connected";
[Link] += " They share a deep friendship and trust completely.";
}
[Link]('Message count:', [Link].message_count);
11) Relationship Progression Array (Relationship Progression [Link])
What: Keyword entries and timing entries in one list.
Diff: Combines scene beats with keyword reactions.
Use: Narrative “beats” + contextual color.
/**
* Dynamic Scenario Events
* Array-driven keyword and timing entries
*/
// Your Dynamic Entries
var dynamicEntries = [
// === KEYWORD ENTRIES ===
{ type: 'keyword', words: ['restaurant', 'cafe'],
{ type: 'keyword', words: ['restaurant', 'cafe'],
scenario: ' The cozy establishment has ambient sounds of clinking dishes and soft music.',
personality: ', notices and comments on the atmosphere around them' },
{ type: 'keyword', words: ['park', 'outside'],
scenario: ' They are outdoors with natural surroundings and fresh air.',
personality: ', observant of nature and weather' },
{ type: 'keyword', words: ['secret'],
personality: ', becomes mysterious when secrets are mentioned',
scenario: ' {{char}} becomes slightly more mysterious and thoughtful.' },
{ type: 'keyword', words: ['music', 'song'],
personality: ', enthusiastic about music',
scenario: ' {{char}} shows enthusiasm about music and might share favorites.' },
// === MESSAGE COUNT ENTRIES ===
{ type: 'timing', minMessages: 0, maxMessages: 10,
scenario: ' Suddenly, their phone rings with an unexpected call.',
personality: ', momentarily distracted by unexpected interruptions' },
{ type: 'timing', minMessages: 11, maxMessages: 15,
scenario: ' Suddenly, their phone rings with an unexpected call.',
personality: ', momentarily distracted by unexpected interruptions' },
{ type: 'timing', minMessages: 26, maxMessages: 50,
scenario: ' The weather suddenly changes around them.',
personality: ', reactive to environmental changes' }
];
var lastMessage = [Link].last_message.toLowerCase();
var messageCount = [Link].message_count;
// Loop
for (var i = 0; i < [Link]; i++) {
var entry = dynamicEntries[i];
if ([Link] === 'keyword') {
var hasKeyword = false;
for (var j = 0; j < [Link]; j++) {
if ([Link]([Link][j])) { hasKeyword = true; break; }
}
if (hasKeyword) {
if ([Link]) [Link] += [Link];
if ([Link]) [Link] += [Link];
}
} else if ([Link] === 'timing') {
if (messageCount >= [Link] && messageCount <= [Link]) {
if ([Link]) [Link] += [Link];
if ([Link]) [Link] += [Link];
}
}
}
[Link]('Message count:', [Link].message_count);
12) Advanced Lorebook (Advanced [Link])
What: Multi-pass system with triggers, priority, and probability.
Diff: Entries can cause other entries to activate; random chance gating.
Use: Interconnected, alive-feeling worlds.
/**
* Dynamic Lore Book System
* Multi-pass: triggers + probability + priority
*/
var dynamicLore = [
// === Fantasy/Magic lore ===
{ keywords: ['magic', 'spell', 'wizard'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 0.5,
personality: ', knowledgeable about magical arts and ancient spells',
scenario: ' {{char}} has studied magic for years and can sense magical energies around them.',
triggers: ['knowledge', 'study', 'monster'] },
{ keywords: ['dragon', 'beast', 'monster'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', experienced with dangerous creatures and their behaviors',
scenario: ' {{char}} has encountered many mythical beasts and knows their weaknesses.' },
// === Historical/Background lore ===
{ keywords: ['war', 'battle', 'soldier'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', haunted by memories of past conflicts',
scenario: ' {{char}} served in the Great War and bears both visible and invisible scars.',
triggers: ['war', 'battle'] },
{ keywords: ['family', 'parent', 'childhood'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', shaped by a complex family history',
scenario: ' {{char}} grew up in a noble house but left to forge their own path.' },
// === Location/World lore ===
{ keywords: ['forest', 'woods', 'tree'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', deeply connected to nature and forest spirits',
scenario: ' {{char}} spent their youth in the Whispering Woods, learning druidic ways.' },
{ keywords: ['city', 'town', 'street'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', street-smart and familiar with urban politics',
scenario: ' {{char}} knows every alley and hidden passage in the capital city.',
triggers: ['street', 'alley'] },
// === Profession/Skill lore ===
{ keywords: ['sword', 'fight', 'weapon'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', disciplined in the ancient fighting arts',
scenario: ' {{char}} trained under Master Korin, learning the Seven Sacred Stances.' },
{ keywords: ['book', 'knowledge', 'study'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', scholarly and well-versed in ancient texts',
scenario: ' {{char}} spent decades in the Great Library, mastering forbidden knowledge.',
triggers: ['knowledge', 'study'] },
// === Mysterious/Secret lore (Timing Tested) ===
{ keywords: ['secret', 'hidden', 'truth'], minMessages: 0, maxMessages: 15, priority: 10, probability: 1,
personality: ', keeper of ancient secrets is a myth',
scenario: ' {{char}} knows the truth about the Sundering, but will not speak about it.' },
{ keywords: ['secret', 'hidden', 'truth'], minMessages: 16, maxMessages: 30, priority: 10, probability: 1,
personality: ', keeper of ancient secrets that could change everything',
scenario: ' {{char}} knows the truth about the Sundering, but speaks of it only in whispers.' }
];
var lastMessage = [Link].last_message.toLowerCase();
var messageCount = [Link].message_count;
var activatedEntries = [];
var triggeredKeywords = [];
// First pass: direct matches + collect triggers
for (var i = 0; i < [Link]; i++) {
var entry = dynamicLore[i], hasKeyword = false;
if (messageCount >= [Link] && messageCount <= [Link]) {
if ([Link] && [Link]() > [Link]) continue;
for (var j = 0; j < [Link]; j++) {
if ([Link]([Link][j])) { hasKeyword = true; break; }
}
if (hasKeyword) {
[Link](entry);
if ([Link]) {
for (var k = 0; k < [Link]; k++) {
[Link]([Link][k]);
}
}
}
}
}
// Second pass: entries activated by triggers
if ([Link] > 0) {
for (var a = 0; a < [Link]; a++) {
var e2 = dynamicLore[a], isTriggered = false, already = false;
for (var b = 0; b < [Link]; b++) {
if (activatedEntries[b] === e2) { already = true; break; }
}
if (already) continue;
for (var c = 0; c < [Link]; c++) {
for (var d = 0; d < [Link]; d++) {
if ([Link][c] === triggeredKeywords[d]) { isTriggered = true; break; }
}
if (isTriggered) break;
}
if (isTriggered && messageCount >= [Link] && messageCount <= [Link]) {
if ([Link] && [Link]() > [Link]) continue;
[Link](e2);
}
}
}
// Final: sort by priority and apply
if ([Link] > 0) {
[Link](function(x, y) { return [Link] - [Link]; });
for (var m = 0; m < [Link]; m++) {
var apply = activatedEntries[m];
if ([Link]) [Link] += [Link];
if ([Link]) [Link] += [Link];
}
}
13) Advanced Shifter Lorebook (Advanced Shifter [Link])
What: After a main match, shifter words (e.g., “stars” vs “shadows”) pick a reply variant ( default , light , dark ).
Diff: In-entry branching without duplicate entries.
Use: Flavorful, context-sensitive replies.
/**
* Advanced Lore with Reply Shifters
* Keyword match + shifter variants in a single entry
*/
var dynamicLore = [
{
keywords: ['magic', 'spell', 'wizard'],
minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
shifters: {
light: ['stars', 'astronomy', 'healing', 'light', 'good'],
dark: ['darkness', 'chaos', 'shadows', 'evil', 'unpredictable']
},
replies: {
default: {
personality: ', knowledgeable about magical arts and ancient spells',
scenario: ' {{char}} has studied magic for years and can sense magical energies around them.'
},
light: {
personality: ', finds a creative and positive connection between magic and what they love',
scenario: ' {{char}} notes that magic feels harmonious, like a song from the stars.'
},
dark: {
personality: ', is cautious, knowing that magic can also be a tool for unpredictable and dangerous forces',
scenario: ' {{char}} explains that magic is not without its risks and dangers, especially when dealing with shadows.'
}
}
},
{ keywords: ['war', 'battle', 'soldier'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', haunted by memories of past conflicts',
scenario: ' {{char}} served in the Great War and bears both visible and invisible scars.' },
{ keywords: ['family', 'parent', 'childhood'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', shaped by a complex family history',
scenario: ' {{char}} grew up in a noble house but left to forge their own path.' }
];
var lastMessage = [Link].last_message.toLowerCase();
var messageCount = [Link].message_count;
// Loop through entries
for (var i = 0; i < [Link]; i++) {
var entry = dynamicLore[i], hasKeyword = false, replyToApply = null;
if (messageCount < [Link] || messageCount > [Link]) continue;
if ([Link] && [Link]() > [Link]) continue;
// Main keywords
for (var j = 0; j < [Link]; j++) {
if ([Link]([Link][j])) { hasKeyword = true; break; }
}
if (hasKeyword) {
if ([Link]) {
var shifterFound = false;
var categories = [Link]([Link]);
for (var k = 0; k < [Link]; k++) {
var cat = categories[k], words = [Link][cat];
for (var l = 0; l < [Link]; l++) {
if ([Link](words[l])) {
replyToApply = [Link][cat]; shifterFound = true; break;
}
}
if (shifterFound) break;
}
if (!shifterFound && [Link] && [Link]) {
replyToApply = [Link];
}
} else {
replyToApply = entry; // fallback to entry fields
}
if (replyToApply) {
if ([Link]) [Link] += [Link];
if ([Link]) [Link] += [Link];
}
}
}
14) Memory System (Memory [Link])
What: Detect hobby words + “favorite/love/like” patterns → memory-like adjustments.
Diff: Not lore; a lightweight personalization layer.
Use: Make the bot “remember” interests within the session.
/**
* Conversation Memory System
* Character remembers and references earlier parts of the conversation
* Character remembers and references earlier parts of the conversation
*/
// Analyze last message for interests and preferences
var lastMessage = [Link].last_message.toLowerCase();
// Detect hobbies mentioned in last message
var hobbies = ['reading', 'gaming', 'cooking', 'sports', 'art', 'music'];
var mentionedHobbies = [];
for (var i = 0; i < [Link]; i++) {
if ([Link](hobbies[i])) [Link](hobbies[i]);
}
// Detect preference expressions
var hasPreferences = [Link]('favorite') ||
[Link]('love') ||
[Link]('like');
// Add memory-based personality traits
if ([Link] > 0) {
[Link] += ", remembers {{user}}'s interest in " + [Link](' and ');
[Link] += ' {{char}} shows interest in ' + [Link](' and ') + ' topics.';
}
if (hasPreferences) {
[Link] += ", attentive to {{user}}'s preferences and opinions";
[Link] += ' {{char}} pays careful attention to what {{user}} likes and dislikes.';
}
// Add general memory-focused behavior
[Link] += ', has good memory for conversation details';
[Link] += ' {{char}} remembers important things {{user}} has shared.';
15) Likes & Dislikes (Likes and [Link])
What: Preconfigured lists for likes/dislikes; mirrors them into personality/scenario.
Diff: Structured categories vs freeform detection.
Use: Quick preference hooks for many topics.
/**
* Conversation Memory System
* Character remembers and references earlier parts of the conversation
*/
var lastMessage = [Link].last_message.toLowerCase();
// Your Interests
var interests = {
likes: ['pizza', 'movies', 'music', 'hiking', 'sports'],
dislikes: ['spiders', 'loud noises', 'waking up early', 'crowds']
};
var categories = [Link](interests);
for (var i = 0; i < [Link]; i++) {
var category = categories[i];
var mentionedItems = [];
var items = interests[category];
for (var j = 0; j < [Link]; j++) {
if ([Link](items[j])) [Link](items[j]);
}
if ([Link] > 0) {
if (category === 'likes') {
[Link] += ", remembers {{user}}'s interest in " + [Link](' and ');
[Link] += ' {{char}} shows interest in ' + [Link](' and ') + ' topics.';
} else if (category === 'dislikes') {
[Link] += ", remembers {{user}}'s dislike of " + [Link](' and ');
[Link] += ' {{char}} pays careful attention to avoid ' + [Link](' and ') + ' topics.';
}
}
}
16) Hybrid: Likes/Dislikes + Lore (Likes, Dislikes, and Advanced Prompt [Link])
What: Merge preference detection with lore replies that switch phrasing based on likes/dislikes.
Diff: Most adaptive; personality+scene tuned by who the user is and what keyword fired.
Use: Responsive, player-tailored worldbuilding.
/**
* Hybridized Lore and Memory System
* Character reveals lore based on keywords and user's likes and dislikes
*/
// YOUR LIKES AND DISLIKES
var interests = {
likes: ['art', 'cooking', 'traveling', 'animals', 'coffee', 'stars', 'astronomy', 'creative arts'],
dislikes: ['spiders', 'loud noises', 'waking up early', 'crowds', 'bugs', 'mornings', 'traffic', 'cold weather', 'darkness', 'chaos', 'shadows']
};
// YOUR LORE ENTRIES
var dynamicLore = [
{
keywords: ['magic', 'spell', 'wizard'],
minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
replies: {
default: { personality: ', knowledgeable about magical arts and ancient spells',
scenario: ' {{char}} has studied magic for years and can sense magical energies around them.' },
onLike: { personality: ', finds a creative and positive connection between magic and what they love',
scenario: ' {{char}} notes that magic feels harmonious, like a song from the stars.' },
onDislike:{ personality: ', is cautious, knowing that magic can also be a tool for unpredictable and dangerous forces',
scenario: ' {{char}} explains that magic is not without its risks and dangers, especially when dealing with shadows.' }
}
},
{ keywords: ['war', 'battle', 'soldier'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', haunted by memories of past conflicts',
scenario: ' {{char}} served in the Great War and bears both visible and invisible scars.' },
{ keywords: ['family', 'parent', 'childhood'], minMessages: 0, maxMessages: 999999999, priority: 10, probability: 1,
personality: ', shaped by a complex family history',
scenario: ' {{char}} grew up in a noble house but left to forge their own path.' }
];
// === SYSTEM PLUMBING ===
var lastMessage = [Link].last_message.toLowerCase();
var messageCount = [Link].message_count;
// First: detect mentioned likes/dislikes
var mentionedLikes = [];
var mentionedDislikes = [];
var categories = [Link](interests);
for (var i = 0; i < [Link]; i++) {
var category = categories[i];
var items = interests[category];
for (var j = 0; j < [Link]; j++) {
if ([Link](items[j])) {
if (category === 'likes') [Link](items[j]);
if (category === 'dislikes') [Link](items[j]);
}
}
}
// Second: evaluate lore
for (var a = 0; a < [Link]; a++) {
var entry = dynamicLore[a], hasKeyword = false, replyToApply = null;
if (messageCount < [Link] || messageCount > [Link]) continue;
if ([Link] && [Link]() > [Link]) continue;
for (var b = 0; b < [Link]; b++) {
if ([Link]([Link][b])) { hasKeyword = true; break; }
}
if (hasKeyword) {
if ([Link]) {
if ([Link] > 0 && [Link]) replyToApply = [Link];
else if ([Link] > 0 && [Link]) replyToApply = [Link];
else if ([Link]) replyToApply = [Link];
} else {
replyToApply = entry;
}
if (replyToApply) {
if ([Link]) [Link] += [Link];
if ([Link]) [Link] += [Link];
}
}
}
Final Notes for ES5/Sandbox Success
Prefer arrays of entries for editor-friendly systems; prefer procedural if/else you want to see step by step.
Use priority to avoid over-firing many entries; use min/max message gates to pace reveals.
Add shifters or conditional replies for flavor without duplicating entries.
Keep debug logs during development; remove them for production bots.
Only modify [Link] and [Link] .
```