Allow searching on /sendas via tag=
This commit is contained in:
parent
4594353c72
commit
22d8a654d9
|
@ -187,10 +187,17 @@ export function initDefaultSlashCommands() {
|
||||||
}),
|
}),
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'avatar',
|
name: 'avatar',
|
||||||
description: 'Optional 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 filename or just the character name to pull the avatar from)',
|
||||||
typeList: [ARGUMENT_TYPE.STRING],
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
enumProvider: commonEnumProviders.characters('character'),
|
enumProvider: commonEnumProviders.characters('character'),
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'tag',
|
||||||
|
description: 'Supply one or more tags to filter down to the correct character for the provided name, if multiple characters have the same name. (does not apply to the avatar argument)',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
enumProvider: commonEnumProviders.tagsForChar('all'),
|
||||||
|
acceptsMultiple: true,
|
||||||
|
}),
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'compact',
|
name: 'compact',
|
||||||
description: 'Use compact layout',
|
description: 'Use compact layout',
|
||||||
|
@ -3109,6 +3116,44 @@ async function setNarratorName(_, text) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a character by name, with optional filtering and precedence for avatars
|
||||||
|
* @param {string} name - The name to search for
|
||||||
|
* @param {object} [options={}] - The options for the search
|
||||||
|
* @param {boolean} [options.allowAvatar=false] - Whether to allow searching by avatar
|
||||||
|
* @param {boolean} [options.insensitive=true] - Whether the search should be case insensitive
|
||||||
|
* @param {string[]?} [options.filteredByTags=null] - Tags to filter characters by
|
||||||
|
* @param {any?} [options.preferCurrentChar=null] - The current character to prefer
|
||||||
|
* @returns {any?} - The found character or null if not found
|
||||||
|
*/
|
||||||
|
export function findCharByName(name, { allowAvatar = false, insensitive = true, filteredByTags = null, preferCurrentChar = null } = {}) {
|
||||||
|
const matches = (char) => (allowAvatar && char.avatar === name) || insensitive ? equalsIgnoreCaseAndAccents(char.name, name) : char.name === name;
|
||||||
|
|
||||||
|
// If we have a current char and prefer it, return that if it matches - unless tags are provided, they have precedence
|
||||||
|
if (preferCurrentChar && !filteredByTags && matches(preferCurrentChar)) {
|
||||||
|
return preferCurrentChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter characters by tags if provided
|
||||||
|
let filteredCharacters = characters;
|
||||||
|
if (filteredByTags) {
|
||||||
|
filteredCharacters = characters.filter(char => filteredByTags.every(tag => char.tags.includes(tag)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If allowAvatar is true, search by avatar first
|
||||||
|
if (allowAvatar) {
|
||||||
|
const characterByAvatar = filteredCharacters.find(char => char.avatar === name);
|
||||||
|
if (characterByAvatar) {
|
||||||
|
return characterByAvatar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for a matching character by name
|
||||||
|
let character = filteredCharacters.find(matches);
|
||||||
|
|
||||||
|
return character;
|
||||||
|
}
|
||||||
|
|
||||||
export async function sendMessageAs(args, text) {
|
export async function sendMessageAs(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -3150,24 +3195,21 @@ export async function sendMessageAs(args, text) {
|
||||||
const chatCharacter = this_chid !== undefined ? characters[this_chid] : null;
|
const chatCharacter = this_chid !== undefined ? characters[this_chid] : null;
|
||||||
const isNeutralCharacter = !chatCharacter && name2 === neutralCharacterName && name === neutralCharacterName;
|
const isNeutralCharacter = !chatCharacter && name2 === neutralCharacterName && name === neutralCharacterName;
|
||||||
|
|
||||||
const character = equalsIgnoreCaseAndAccents(chatCharacter.name, name) ? chatCharacter : characters.find(x => equalsIgnoreCaseAndAccents(x.name, name));
|
const character = findCharByName(name, { filteredByTags: args?.tags, preferCurrentChar: chatCharacter });
|
||||||
|
|
||||||
let avatarChar = character;
|
const avatarCharacter = args.avatar ? findCharByName(args.avatar) : character;
|
||||||
if (args.avatar) {
|
if (args.avatar && !avatarCharacter) {
|
||||||
avatarChar = characters.find(x => x.avatar == args.avatar) ?? characters.find(x => equalsIgnoreCaseAndAccents(x.name, args.avatar));
|
toastr.warning(`Character for avatar ${args.avatar} not found`);
|
||||||
if (!avatarChar) {
|
return '';
|
||||||
toastr.warning(`Character for avatar ${args.avatar} not found`);
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let force_avatar, original_avatar;
|
let force_avatar, original_avatar;
|
||||||
if (chatCharacter === avatarChar || isNeutralCharacter) {
|
if (chatCharacter === avatarCharacter || isNeutralCharacter) {
|
||||||
// If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars
|
// If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars
|
||||||
}
|
}
|
||||||
else if (avatarChar && avatarChar.avatar !== 'none') {
|
else if (avatarCharacter && avatarCharacter.avatar !== 'none') {
|
||||||
force_avatar = getThumbnailUrl('avatar', avatarChar.avatar);
|
force_avatar = getThumbnailUrl('avatar', avatarCharacter.avatar);
|
||||||
original_avatar = avatarChar.avatar;
|
original_avatar = avatarCharacter.avatar;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
force_avatar = default_avatar;
|
force_avatar = default_avatar;
|
||||||
|
|
|
@ -193,7 +193,7 @@ export const commonEnumProviders = {
|
||||||
if (charName instanceof SlashCommandClosure) throw new Error('Argument \'name\' does not support closures');
|
if (charName instanceof SlashCommandClosure) throw new Error('Argument \'name\' does not support closures');
|
||||||
const key = searchCharByName(substituteParams(charName), { suppressLogging: true });
|
const key = searchCharByName(substituteParams(charName), { suppressLogging: true });
|
||||||
const assigned = key ? getTagsList(key) : [];
|
const assigned = key ? getTagsList(key) : [];
|
||||||
return tags.filter(it => !key || mode === 'all' || mode === 'existing' && assigned.includes(it) || mode === 'not-existing' && !assigned.includes(it))
|
return tags.filter(it => mode === 'all' || mode === 'existing' && assigned.includes(it) || mode === 'not-existing' && !assigned.includes(it))
|
||||||
.map(tag => new SlashCommandEnumValue(tag.name, null, enumTypes.command, enumIcons.tag));
|
.map(tag => new SlashCommandEnumValue(tag.name, null, enumTypes.command, enumIcons.tag));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue