diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 0286fb915..2f2e27fdd 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -247,7 +247,7 @@ export function initDefaultSlashCommands() { namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'name', - description: 'Character name', + description: 'Character name - or unique character identifier (avatar key)', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, enumProvider: commonEnumProviders.characters('character'), @@ -255,7 +255,7 @@ export function initDefaultSlashCommands() { }), SlashCommandNamedArgument.fromProps({ name: 'avatar', - description: 'Character avatar override (Can be either avatar filename or just the character name to pull the avatar from)', + description: 'Character avatar override (Can be either avatar key or just the character name to pull the avatar from)', typeList: [ARGUMENT_TYPE.STRING], enumProvider: commonEnumProviders.characters('character'), }), @@ -288,6 +288,9 @@ export function initDefaultSlashCommands() {
/sendas name="Chloe" Hello, guys!
will send "Hello, guys!" from "Chloe". +
  • +
    /sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.
    + will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss".
    @@ -509,7 +512,7 @@ export function initDefaultSlashCommands() { namedArgumentList: [ SlashCommandNamedArgument.fromProps({ name: 'name', - description: 'character name', + description: 'Character name - or unique character identifier (avatar key)', typeList: [ARGUMENT_TYPE.STRING], isRequired: true, enumProvider: commonEnumProviders.characters('character'), @@ -2558,26 +2561,22 @@ async function askCharacter(args, text) { return ''; } - let name = ''; - - if (args?.name) { - name = args.name.trim(); - - if (!name) { - toastr.warning('You must specify a name of the character to ask.'); - return ''; - } + if (!args.name) { + toastr.warning('You must specify a name of the character to ask.'); + return ''; } const prevChId = this_chid; // Find the character - const chId = characters.findIndex((e) => e.name === name || e.avatar === name); - if (!characters[chId] || chId === -1) { + const character = findChar({ name: args?.name }); + if (!character) { toastr.error('Character not found.'); return ''; } + const chId = getCharIndex(character); + if (text) { const mesText = getRegexedString(text.trim(), regex_placement.SLASH_COMMAND); // Sending a message implicitly saves the chat, so this needs to be done before changing the character @@ -2588,19 +2587,9 @@ async function askCharacter(args, text) { // Override character and send a user message setCharacterId(String(chId)); - const character = characters[chId]; - let force_avatar, original_avatar; + const { name, force_avatar, original_avatar } = getNameAndAvatarForMessage(character, args?.name); - if (character && character.avatar !== 'none') { - force_avatar = getThumbnailUrl('avatar', character.avatar); - original_avatar = character.avatar; - } - else { - force_avatar = default_avatar; - original_avatar = default_avatar; - } - - setCharacterName(character.name); + setCharacterName(name); const restoreCharacter = () => { if (String(this_chid) !== String(chId)) { @@ -2613,7 +2602,7 @@ async function askCharacter(args, text) { // Only force the new avatar if the character name is the same // This skips if an error was fired const lastMessage = chat[chat.length - 1]; - if (lastMessage && lastMessage?.name === character.name) { + if (lastMessage && lastMessage?.name === name) { lastMessage.force_avatar = force_avatar; lastMessage.original_avatar = original_avatar; } @@ -2624,7 +2613,7 @@ async function askCharacter(args, text) { // Run generate and restore previous character try { eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter); - toastr.info(`Asking ${character.name} something...`); + toastr.info(`Asking ${name} something...`); askResult = await Generate('ask_command'); } catch (error) { restoreCharacter(); @@ -3215,6 +3204,41 @@ export function validateArrayArg(arg, name, { allowUndefined = true } = {}) { return arg; } + +/** + * Retrieves the name and avatar information for a message + * + * The name of the character will always have precendence over the one given as argument. If you want to specify a different name for the message, + * explicitly implement this in the code using this. + * + * @param {object?} character - The character object to get the avatar data for + * @param {string?} name - The name to get the avatar data for + * @returns {{name: string, force_avatar: string, original_avatar: string}} An object containing the name for the message, forced avatar URL, and original avatar + */ +export function getNameAndAvatarForMessage(character, name = null) { + const isNeutralCharacter = !character && name2 === neutralCharacterName && name === neutralCharacterName; + const currentChar = characters[this_chid]; + + let force_avatar, original_avatar; + if (character?.avatar === currentChar?.avatar || isNeutralCharacter) { + // If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars + } + else if (character && character.avatar !== 'none') { + force_avatar = getThumbnailUrl('avatar', character.avatar); + original_avatar = character.avatar; + } + else { + force_avatar = default_avatar; + original_avatar = default_avatar; + } + + return { + name: character?.name || name, + force_avatar: force_avatar, + original_avatar: original_avatar, + }; +} + /** * Finds a character by name, with optional filtering and precedence for avatars * @param {object} [options={}] - The options for the search @@ -3273,6 +3297,19 @@ export function findChar({ name = null, allowAvatar = true, insensitive = true, return matchingCharacters[0] || null; } +/** + * Gets the index of a character based on the character object + * @param {object} char - The character object to find the index for + * @throws {Error} If the character is not found + * @returns {number} The index of the character in the characters array + */ +export function getCharIndex(char) { + if (!char) throw new Error('Character is undefined'); + const index = characters.findIndex(c => c.avatar === char.avatar); + if (index === -1) throw new Error(`Character not found: ${char.avatar}`); + return index; +} + export async function sendMessageAs(args, text) { if (!text) { return ''; @@ -3319,23 +3356,10 @@ export async function sendMessageAs(args, text) { return ''; } - const isNeutralCharacter = !character && name2 === neutralCharacterName && name === neutralCharacterName; - - let force_avatar, original_avatar; - if (character === avatarCharacter || isNeutralCharacter) { - // If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars - } - else if (avatarCharacter && avatarCharacter.avatar !== 'none') { - force_avatar = getThumbnailUrl('avatar', avatarCharacter.avatar); - original_avatar = avatarCharacter.avatar; - } - else { - force_avatar = default_avatar; - original_avatar = default_avatar; - } + const { name: nameForMessage, force_avatar, original_avatar } = getNameAndAvatarForMessage(avatarCharacter, name); const message = { - name: character?.name || name, + name: nameForMessage, is_user: false, is_system: isSystem, send_date: getMessageTimeStamp(),