Update /ask with new char find functionality

d6e52dbb9727ff67ec7d52b664b17efcb363c208

Wolfsblvt <wolfsblvt@gmail.com>

1 files changed, +65 -41Showing whitespace changes
public/scripts/slash-commands.js+65 -41
@@ -247,7 +247,7 @@ export function initDefaultSlashCommands() {
247247 namedArgumentList: [
248248 SlashCommandNamedArgument.fromProps({
249249 name: 'name',
250250 description: 'Character name - or unique character identifier (avatar key)',
251251 typeList: [ARGUMENT_TYPE.STRING],
252252 isRequired: true,
253253 enumProvider: commonEnumProviders.characters('character'),
@@ -255,7 +255,7 @@ export function initDefaultSlashCommands() {
255255 }),
256256 SlashCommandNamedArgument.fromProps({
257257 name: 'avatar',
258258 description: 'Character avatar override (Can be either avatar filenamekey or just the character name to pull the avatar from)',
259259 typeList: [ARGUMENT_TYPE.STRING],
260260 enumProvider: commonEnumProviders.characters('character'),
261261 }),
@@ -288,6 +288,9 @@ export function initDefaultSlashCommands() {
288288 <pre><code>/sendas name="Chloe" Hello, guys!</code></pre>
289289 will send "Hello, guys!" from "Chloe".
290290 </li>
291+ <li>
292+ <pre><code>/sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.</code></pre>
293+ will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss".
291294 </ul>
292295 </div>
293296 <div>
@@ -509,7 +512,7 @@ export function initDefaultSlashCommands() {
509512 namedArgumentList: [
510513 SlashCommandNamedArgument.fromProps({
511514 name: 'name',
512515 description: 'characterCharacter name - or unique character identifier (avatar key)',
513516 typeList: [ARGUMENT_TYPE.STRING],
514517 isRequired: true,
515518 enumProvider: commonEnumProviders.characters('character'),
@@ -2558,26 +2561,22 @@ async function askCharacter(args, text) {
25582561 return '';
25592562 }
25602563
2561- let name = '';
2564+ if (!args.name) {
2562-
2563- if (args?.name) {
2564- name = args.name.trim();
2565-
2566- if (!name) {
25672565 toastr.warning('You must specify a name of the character to ask.');
25682566 return '';
25692567 }
2570- }
25712568
25722569 const prevChId = this_chid;
25732570
25742571 // Find the character
2575- const chId = characters.findIndex((e) => e.name === name || e.avatar === name);
2572+ const character = findChar({ name: args?.name });
2576- if (!characters[chId] || chId === -1) {
2573+ if (!character) {
25772574 toastr.error('Character not found.');
25782575 return '';
25792576 }
25802577
2578+ const chId = getCharIndex(character);
2579+
25812580 if (text) {
25822581 const mesText = getRegexedString(text.trim(), regex_placement.SLASH_COMMAND);
25832582 // 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) {
25882587 // Override character and send a user message
25892588 setCharacterId(String(chId));
25902589
2591- const character = characters[chId];
2590+ const { name, force_avatar, original_avatar } = getNameAndAvatarForMessage(character, args?.name);
2592- let force_avatar, original_avatar;
25932591
2594- if (character && character.avatar !== 'none') {
2592+ setCharacterName(name);
2595- force_avatar = getThumbnailUrl('avatar', character.avatar);
2596- original_avatar = character.avatar;
2597- }
2598- else {
2599- force_avatar = default_avatar;
2600- original_avatar = default_avatar;
2601- }
2602-
2603- setCharacterName(character.name);
26042593
26052594 const restoreCharacter = () => {
26062595 if (String(this_chid) !== String(chId)) {
@@ -2613,7 +2602,7 @@ async function askCharacter(args, text) {
26132602 // Only force the new avatar if the character name is the same
26142603 // This skips if an error was fired
26152604 const lastMessage = chat[chat.length - 1];
26162605 if (lastMessage && lastMessage?.name === character.name) {
26172606 lastMessage.force_avatar = force_avatar;
26182607 lastMessage.original_avatar = original_avatar;
26192608 }
@@ -2624,7 +2613,7 @@ async function askCharacter(args, text) {
26242613 // Run generate and restore previous character
26252614 try {
26262615 eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter);
26272616 toastr.info(`Asking ${character.name} something...`);
26282617 askResult = await Generate('ask_command');
26292618 } catch (error) {
26302619 restoreCharacter();
@@ -3215,6 +3204,41 @@ export function validateArrayArg(arg, name, { allowUndefined = true } = {}) {
32153204 return arg;
32163205}
32173206
3207+
3208+/**
3209+ * Retrieves the name and avatar information for a message
3210+ *
3211+ * 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,
3212+ * explicitly implement this in the code using this.
3213+ *
3214+ * @param {object?} character - The character object to get the avatar data for
3215+ * @param {string?} name - The name to get the avatar data for
3216+ * @returns {{name: string, force_avatar: string, original_avatar: string}} An object containing the name for the message, forced avatar URL, and original avatar
3217+ */
3218+export function getNameAndAvatarForMessage(character, name = null) {
3219+ const isNeutralCharacter = !character && name2 === neutralCharacterName && name === neutralCharacterName;
3220+ const currentChar = characters[this_chid];
3221+
3222+ let force_avatar, original_avatar;
3223+ if (character?.avatar === currentChar?.avatar || isNeutralCharacter) {
3224+ // If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars
3225+ }
3226+ else if (character && character.avatar !== 'none') {
3227+ force_avatar = getThumbnailUrl('avatar', character.avatar);
3228+ original_avatar = character.avatar;
3229+ }
3230+ else {
3231+ force_avatar = default_avatar;
3232+ original_avatar = default_avatar;
3233+ }
3234+
3235+ return {
3236+ name: character?.name || name,
3237+ force_avatar: force_avatar,
3238+ original_avatar: original_avatar,
3239+ };
3240+}
3241+
32183242/**
32193243 * Finds a character by name, with optional filtering and precedence for avatars
32203244 * @param {object} [options={}] - The options for the search
@@ -3273,6 +3297,19 @@ export function findChar({ name = null, allowAvatar = true, insensitive = true,
32733297 return matchingCharacters[0] || null;
32743298}
32753299
3300+/**
3301+ * Gets the index of a character based on the character object
3302+ * @param {object} char - The character object to find the index for
3303+ * @throws {Error} If the character is not found
3304+ * @returns {number} The index of the character in the characters array
3305+ */
3306+export function getCharIndex(char) {
3307+ if (!char) throw new Error('Character is undefined');
3308+ const index = characters.findIndex(c => c.avatar === char.avatar);
3309+ if (index === -1) throw new Error(`Character not found: ${char.avatar}`);
3310+ return index;
3311+}
3312+
32763313export async function sendMessageAs(args, text) {
32773314 if (!text) {
32783315 return '';
@@ -3319,23 +3356,10 @@ export async function sendMessageAs(args, text) {
33193356 return '';
33203357 }
33213358
3322- const isNeutralCharacter = !character && name2 === neutralCharacterName && name === neutralCharacterName;
3359+ const { name: nameForMessage, force_avatar, original_avatar } = getNameAndAvatarForMessage(avatarCharacter, name);
3323-
3324- let force_avatar, original_avatar;
3325- if (character === avatarCharacter || isNeutralCharacter) {
3326- // If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars
3327- }
3328- else if (avatarCharacter && avatarCharacter.avatar !== 'none') {
3329- force_avatar = getThumbnailUrl('avatar', avatarCharacter.avatar);
3330- original_avatar = avatarCharacter.avatar;
3331- }
3332- else {
3333- force_avatar = default_avatar;
3334- original_avatar = default_avatar;
3335- }
33363360
33373361 const message = {
33383362 name: character?.name || namenameForMessage,
33393363 is_user: false,
33403364 is_system: isSystem,
33413365 send_date: getMessageTimeStamp(),