From 7fdc0b6850825fc4cea2db1ba99ee18d1b79a822 Mon Sep 17 00:00:00 2001 From: Erix <milllner.eric@gmail.com> Date: Wed, 13 Mar 2024 18:35:05 +0000 Subject: [PATCH] Dressing room extras --- css/facilities/dressingRoom.css | 8 +- js/003-data/gameVariableData.js | 1 + src/art/genAI/clothesPromptPart.js | 16 +- src/facilities/dressingRoom/dressingRoom.js | 238 +++++++++++++++++++- 4 files changed, 251 insertions(+), 12 deletions(-) diff --git a/css/facilities/dressingRoom.css b/css/facilities/dressingRoom.css index 65a70082daa..4d8de0900e6 100644 --- a/css/facilities/dressingRoom.css +++ b/css/facilities/dressingRoom.css @@ -13,7 +13,13 @@ } .dressing-room-title { - margin: 0.5rem 1.5rem; + margin: 0.4rem 1.4rem; + display: grid; + align-items: left; +} + +.dressing-room-label { + margin: .1rem; } diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js index 3b9361f56d0..e91ea4f1897 100644 --- a/js/003-data/gameVariableData.js +++ b/js/003-data/gameVariableData.js @@ -198,6 +198,7 @@ App.Data.defaultGameStateVariables = { aiUpscaleScale: 1.75, aiUpscaler: "SwinIR_4x", aiWidth: 512, + customClothesPrompts: {}, showAgeDetail: 1, showAppraisal: 1, diff --git a/src/art/genAI/clothesPromptPart.js b/src/art/genAI/clothesPromptPart.js index 50cfd634dc6..461c3a691b8 100644 --- a/src/art/genAI/clothesPromptPart.js +++ b/src/art/genAI/clothesPromptPart.js @@ -446,7 +446,7 @@ App.Art.GenAI.ClothesPromptPart = class ClothesPromptPart extends App.Art.GenAI. */ getClothes() { let clothes = this.slave.clothes; - if (!clothesPrompts.hasOwnProperty(clothes)) { + if (!clothesPrompts.hasOwnProperty(clothes) && !V.customClothesPrompts.hasOwnProperty(clothes)) { clothes = "no clothing"; } if (this.slave.race === "catgirl") { @@ -512,7 +512,13 @@ App.Art.GenAI.ClothesPromptPart = class ClothesPromptPart extends App.Art.GenAI. * @returns {string} */ positive() { - const basePrompt = clothesPrompts[this.getClothes()]; + let basePrompt; + if (V.customClothesPrompts.hasOwnProperty(this.getClothes()) && V.customClothesPrompts[this.getClothes()].positive !== '') { + basePrompt = V.customClothesPrompts[this.getClothes()]; + } else { + basePrompt = clothesPrompts[this.getClothes()]; + } + const coloredPrompt = this.colorReplacer(basePrompt.positive, basePrompt.colors); return this.bodyPartReplacer(coloredPrompt); } @@ -521,6 +527,10 @@ App.Art.GenAI.ClothesPromptPart = class ClothesPromptPart extends App.Art.GenAI. * @returns {string} */ negative() { - return clothesPrompts[this.getClothes()].negative; + if (V.customClothesPrompts.hasOwnProperty(this.getClothes()) && V.customClothesPrompts[this.getClothes()].negative !== '') { + return V.customClothesPrompts[this.getClothes()].negative; + } else { + return clothesPrompts[this.getClothes()].negative; + } } }; diff --git a/src/facilities/dressingRoom/dressingRoom.js b/src/facilities/dressingRoom/dressingRoom.js index b1ff138c7c0..1727a3c9ddc 100644 --- a/src/facilities/dressingRoom/dressingRoom.js +++ b/src/facilities/dressingRoom/dressingRoom.js @@ -13,6 +13,8 @@ App.UI.DressingRoom.render = function() { App.UI.DressingRoom.modelId = defaultModel?.ID; } + let customClothesPrompts = V.customClothesPrompts; + const el = document.createElement("p"); el.id = "dressing-room"; @@ -57,6 +59,8 @@ App.UI.DressingRoom.render = function() { App.UI.DOM.appendNewElement("h2", el, `Outfits`); + el.append(clothesSearch(model.clothes)); + el.append(clothesBlock()); return el; @@ -109,17 +113,235 @@ App.UI.DressingRoom.render = function() { } } - let txt = clothesProperties.name; + el.appendChild(createLabel()); - App.UI.DOM.appendNewElement( - 'div', - el, - txt, - ['dressing-room-title'] - ); + return el; + function createLabel() { + const label = document.createElement('div'); + label.className = 'dressing-room-label'; - return el; + label.append(createTitle()); + + if (customClothesPrompts[clothingName]) { + jQuery(label).append(createOptions()); + } + + return label; + + /** + * Container for clothing name and links + * @returns {HTMLDivElement} The created title element + */ + function createTitle() { + const title = document.createElement('div'); + title.className = 'dressing-room-title'; + + let hidden = !customClothesPrompts[clothingName]; + let optElem; + + const links = [ + App.UI.DOM.link( + ` Details`, + () => { + if (hidden) { + if (!customClothesPrompts[clothingName]) { + optElem = createOptions(); + jQuery(label).append(optElem); + } + jQuery(label).children(".options-group").show(); + hidden = false; + } else { + jQuery(label).children(".options-group").hide(); + hidden = true; + } + } + ), + App.UI.DOM.link( + ` Reset`, + () => { + if (customClothesPrompts[clothingName]) { + delete customClothesPrompts[clothingName]; + jQuery(label).children(".options-group").remove(); + hidden = true; + } + } + ) + ]; + + const linkStrip = App.UI.DOM.generateLinksStrip(links); + + title.textContent = clothesProperties.name; + + title.append(linkStrip); + + return title; + } + + /** + * Create prompt changing options + * @returns {HTMLDivElement} The created option element + */ + function createOptions() { + const optGroup = new App.UI.OptionsGroup(); + optGroup.customRefresh(() => { + jQuery(label).children(".options-group").remove(); + jQuery(label).append(createOptions()); + }); + + optGroup.addOption( + "Pos Prompt", 'positive', + promptPart()).showTextBox() + .addComment(createComment('positive')); + + optGroup.addOption( + "Neg Prompt", 'negative', + promptPart()).showTextBox() + .addComment(createComment('negative')); + + + let optElem = optGroup.render(); + + optElem.id = clothesProperties.name + " options"; + + return optElem; + + function promptPart() { + if (!customClothesPrompts[clothingName]) { + customClothesPrompts[clothingName] = { + "positive": "", + "negative": "", + }; + } + return customClothesPrompts[clothingName]; + } + } + + /** + * @param {string} type positive | negative + * @returns {string} prompts + */ + function createComment(type) { + if (customClothesPrompts[clothingName] && customClothesPrompts[clothingName][type] !== '') { + return customClothesPrompts[clothingName][type]; + } else if (clothesPrompts[clothingName]) { + return clothesPrompts[clothingName][type]; + } else { + return 'no prompts'; + } + } + } + } + } + + function clothesSearch(clothes) { + const el = document.createElement("div"); + App.UI.DOM.appendNewElement("h4", el, "Search clothes: "); + + const searchBar = document.createElement("input"); + searchBar.type = "text"; + searchBar.addEventListener("change", updateSearch); + searchBar.addEventListener("submit", updateSearch); + + el.appendChild(searchBar); + + let searchMode; + + el.appendChild(createLinkStrip()); + + return el; + + /** onChange Event for search bar */ + function updateSearch(ev) { + const query = ev?.target.value.toLowerCase() ? ev.target.value.toLowerCase() : searchBar.value.toLowerCase(); + + jQuery('#id-dressing-room').children().show().not((i, v) => { + return ifClothesMatch(v); + }).hide(); + + /** + * will match for: + * clothing name, presence in prompts + * FS Conformance + * Returns true if the element matches the search query + */ + function ifClothesMatch(v) { + let match = false; + switch (searchMode) { + case 'names': + match = !!v.id.toLowerCase().match(query); + break; + case 'positive prompts': + match = !!customClothesPrompts[v.id]?.positive.toLowerCase().match(query) || !!clothesPrompts[v.id]?.positive.toLowerCase().match(query); + break; + case 'negative prompts': + match = !!clothesPrompts[v.id]?.negative.toLowerCase().match(query) || !!customClothesPrompts[v.id]?.negative.toLowerCase().match(query); + break; + case 'fs loves': + App.Data.clothes.get(v.id)?.fs?.loves?.forEach((v) => { + match = !!v.toLowerCase().match(query); + }); + break; + case 'fs tolerates': + App.Data.clothes.get(v.id)?.fs?.tolerates?.forEach((v) => { + match = !!v.toLowerCase().match(query); + }); + break; + case 'unlocked': + match = (!!V.arcologies[0][App.Data.clothes.get(v.id)?.fs?.unlocks] || !!App.Data.clothes.get(v.id).requirements || !App.Data.clothes.get(v.id).hasOwnProperty('requirements')) && !!v.id.toLowerCase().match(query); + break; + case 'customized': + match = customClothesPrompts[v.id] && !!v.id.toLowerCase().match(query); + break; + default: + match = false; + break; + } + + return match; + } + } + /** + * + * @returns {HTMLUListElement} linkStrip element populated with searchModes + */ + function createLinkStrip() { + const searchModes = ['customized', 'unlocked', 'names', 'positive prompts', 'negative prompts', 'fs loves', 'fs tolerates']; + let linkStrip; + + if (!searchMode) { + searchMode = searchModes[1]; + } else if (customClothesPrompts[clothes]) { + searchMode = searchModes[0]; + } + + return createLinks(); + + function createLinks() { + const links = [ + App.UI.DOM.disabledLink( + searchMode.toUpperFirst(), + ['Already selected'] + ) + ]; + + searchModes.filter((v) => { + return v !== searchMode; + }).forEach((v) => { + links.push( + App.UI.DOM.link( + v.toUpperFirst(), + () => { + searchMode = v; + jQuery('#search-modes').empty().append(createLinks()); + updateSearch(); + } + )); + }); + linkStrip = App.UI.DOM.generateLinksStrip(links); + linkStrip.id = 'search-modes'; + return linkStrip; + } } } }; -- GitLab