Skip to content
Snippets Groups Projects
rulesAssistantOptions.js 113 KiB
Newer Older
  • Learn to ignore specific revisions
  • vas's avatar
    vas committed
    
    
    vas's avatar
    vas committed
    			return container;
    
    vas's avatar
    vas committed
    		}
    
    		onchange(value) {
    
    vas's avatar
    vas committed
    			this.selected = value;
    
    vas's avatar
    vas committed
    			this.parent.onchange(this);
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    vas's avatar
    vas committed
    	// rule import field
    
    vas's avatar
    vas committed
    	class NewRuleField extends Element {
    
    vas's avatar
    vas committed
    			super();
    
    vas's avatar
    vas committed
    		}
    
    		render() {
    
    vas's avatar
    vas committed
    			let element = document.getElementById("importfield");
    
    brickode's avatar
    brickode committed
    			if (element !== null) {
    				return element;
    			}
    
    vas's avatar
    vas committed
    			const container = document.createElement("div");
    
    vas's avatar
    vas committed
    			container.id = "importfield";
    
    vas's avatar
    vas committed
    			const textarea = document.createElement("textarea");
    
    vas's avatar
    vas committed
    			textarea.placeholder = "Paste your rule here";
    			container.appendChild(textarea);
    			this.textarea = textarea;
    			const button = document.createElement("button");
    			button.name = "Load";
    
    vas's avatar
    vas committed
    			button.innerHTML = "Load";
    
    brickode's avatar
    brickode committed
    			button.onclick = () => { this.loadNewRule(); };
    
    vas's avatar
    vas committed
    			container.appendChild(button);
    			return container;
    
    vas's avatar
    vas committed
    		}
    
    		loadNewRule() {
    
    vas's avatar
    vas committed
    			const text = this.textarea.value;
    
    vas's avatar
    vas committed
    			try {
    
    vas's avatar
    vas committed
    				const rule = JSON.parse(text);
    
    Skriv's avatar
    Skriv committed
    				if (Array.isArray(rule)) {
    
    ezsh's avatar
    ezsh committed
    					rule.forEach(r => {
    
    						V.defaultRules.push(App.Entity.Utils.RARuleDatatypeCleanup(r));
    
    ezsh's avatar
    ezsh committed
    					});
    
    DCoded's avatar
    DCoded committed
    				} else {
    
    					V.defaultRules.push(App.Entity.Utils.RARuleDatatypeCleanup(rule));
    
    DCoded's avatar
    DCoded committed
    				}
    
    vas's avatar
    vas committed
    			} catch (e) {
    
    Skriv's avatar
    Skriv committed
    				alert(`Couldn't import that rule:\n${e.message}`);
    
    vas's avatar
    vas committed
    			}
    		}
    	}
    
    
    vas's avatar
    vas committed
    	// the base element, parent of all elements
    
    vas's avatar
    vas committed
    	class Root extends Element {
    
    vas's avatar
    vas committed
    		constructor(element) {
    			super(element);
    
    brickode's avatar
    brickode committed
    			if (V.defaultRules.length === 0) {
    
    vas's avatar
    vas committed
    				const paragraph = document.createElement("p");
    				paragraph.innerHTML = "<strong>No rules</strong>";
    				this.appendChild(new Element(paragraph));
    				this.appendChild(new NoRules(this));
    				return;
    
    vas's avatar
    vas committed
    			}
    
    vas's avatar
    vas committed
    			this.appendChild(new RuleSelector(this));
    			this.appendChild(new RuleOptions(this));
    
    vas's avatar
    vas committed
    			this.appendChild(new ConditionEditor(this));
    
    vas's avatar
    vas committed
    			this.appendChild(new EffectEditor(this));
    
    			App.UI.tabBar.handlePreSelectedTab("appearance", true);
    
    vas's avatar
    vas committed
    		}
    
    		render(element) {
    
    vas's avatar
    vas committed
    			const greeting = document.createElement("p");
    
    			greeting.innerHTML = `<em>${properTitle()}, I will review your slaves and make changes that will have a beneficial effect. Apologies, ${properTitle()}, but this function is... not fully complete. It may have some serious limitations. Please use the '${noDefaultSetting.text}' option to identify areas I should not address.
    			<br>For things like breast, butt, lip, dick and ball injections you need to only set the growth targets in Physical Regimen and I'll try to figure out how to best achieve them, you probably won't need a separate rules for each of them or have to worry about ending the injections.</em>`;
    
    vas's avatar
    vas committed
    			element.appendChild(greeting);
    			return element;
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    klorpa's avatar
    klorpa committed
    	// options displayed when there are no rules
    
    vas's avatar
    vas committed
    	class NoRules extends Options {
    
    vas's avatar
    vas committed
    			super();
    
    			const newrule = new OptionsItem("Add a new rule", () => { newRule(); });
    
    vas's avatar
    vas committed
    			this.appendChild(newrule);
    
    			const importrule = new OptionsItem("Import a rule", () => { root.appendChild(new NewRuleField()); });
    
    vas's avatar
    vas committed
    			this.appendChild(importrule);
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    vas's avatar
    vas committed
    	// buttons for selecting the current rule
    	class RuleSelector extends List {
    
    			super("Current rule", V.defaultRules.map(i => [(i.name + (RuleHasError(i) ? " <span class='yellow'>[!]</span>" : "")), i]), false);
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.name);
    
    Skriv's avatar
    Skriv committed
    			this.onchange = function(rule) {
    
    				V.currentRule = rule.ID;
    
    vas's avatar
    vas committed
    			};
    
    vas's avatar
    vas committed
    		}
    	}
    
    	// buttons for doing transformations on rules
    	class RuleOptions extends Options {
    
    vas's avatar
    vas committed
    			super();
    
    			this.appendChild(new OptionsItem("New Rule", newRule));
    			this.appendChild(new OptionsItem("Remove Rule", removeRule));
    
    vas's avatar
    vas committed
    			this.appendChild(new OptionsItem("Apply rules", () => this.appendChild(new ApplicationLog())));
    
    			this.appendChild(new OptionsItem("Lower Priority", lowerPriority));
    			this.appendChild(new OptionsItem("Higher Priority", higherPriority));
    
    			this.appendChild(new OptionsItem("Rename", rename(this)));
    
    vas's avatar
    vas committed
    			this.appendChild(new OptionsItem("Export this rule", () => this.appendChild(new ExportField(current_rule))));
    			this.appendChild(new OptionsItem("Export all rules", () => this.appendChild(new ExportField(...V.defaultRules))));
    
    			this.appendChild(new OptionsItem("Import rule(s)", () => this.appendChild(new NewRuleField())));
    
    vas's avatar
    vas committed
    		}
    	}
    
    	class ApplicationLog extends Element {
    		render() {
    
    vas's avatar
    vas committed
    			const elem = document.querySelector("#application-log") || document.createElement("div");
    			elem.id = "application-log";
    
    vas's avatar
    vas committed
    			elem.innerHTML = V.slaves.map(slave => DefaultRules(slave)).join("");
    
    vas's avatar
    vas committed
    			return elem;
    
    vas's avatar
    vas committed
    		}
    	}
    
    	class RenameField extends Element {
    
    vas's avatar
    vas committed
    			super();
    
    			this.element.onblur = () => changeName(this.element.value);
    			this.element.onkeypress = (e) => { if (returnP(e)) { changeName(this.element.value); } };
    
    vas's avatar
    vas committed
    		}
    
    		render() {
    
    vas's avatar
    vas committed
    			const elem = document.createElement("input");
    
    vas's avatar
    vas committed
    			elem.setAttribute("type", "text");
    
    vas's avatar
    vas committed
    			elem.setAttribute("value", current_rule.name);
    			return elem;
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    vas's avatar
    vas committed
    	class ExportField extends Element {
    
    vas's avatar
    vas committed
    		render(...args) {
    			let element = document.getElementById("exportfield");
    			if (element === null) {
    
    vas's avatar
    vas committed
    				element = document.createElement("textarea");
    
    vas's avatar
    vas committed
    				element.id = "exportfield";
    			}
    
    vas's avatar
    vas committed
    			element.value = JSON.stringify(args, null, 2);
    
    vas's avatar
    vas committed
    			return element;
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    vas's avatar
    vas committed
    	// parent section for condition editing
    
    vas's avatar
    vas committed
    	class ConditionEditor extends Section {
    
    vas's avatar
    vas committed
    		constructor() {
    
    vas's avatar
    vas committed
    			super("Activation Condition");
    
    vas's avatar
    vas committed
    			this.appendChild(new ConditionFunction());
    			this.appendChild(new AssignmentInclusion());
    
    ezsh's avatar
    ezsh committed
    			this.appendChild(new FacilityHeadAssignmentInclusion());
    
    vas's avatar
    vas committed
    			this.appendChild(new SpecificInclusionExclusion());
    
    i107760's avatar
    i107760 committed
    			this.appendChild(new ApplyRuleOnce());
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    vas's avatar
    vas committed
    	class ConditionFunction extends Element {
    		constructor() {
    
    vas's avatar
    vas committed
    			super();
    
    vas's avatar
    vas committed
    			const items = [
    				["Never", false],
    				["Always", true],
    				["Custom", "custom"],
    				["Devotion", "devotion"],
    				["Trust", "trust"],
    
    				["Health", "health.condition"],
    
    Pregmodder's avatar
    Pregmodder committed
    				["Sex", "genes"],
    
    vas's avatar
    vas committed
    				["Sex drive", "energy"],
    
    Pregmodder's avatar
    Pregmodder committed
    				["Height", "height"],
    
    vas's avatar
    vas committed
    				["Weight", "weight"],
    				["Age", "actualAge"],
    				["Body Age", "physicalAge"],
    				["Visible Age", "visualAge"],
    				["Muscles", "muscles"],
    				["Lactation", "lactation"],
    				["Pregnancy", "preg"],
    				["Pregnancy Multiples", "pregType"],
    				["Belly Implant", "bellyImplant"],
    				["Belly Size", "belly"],
    
    				["Education", "intelligenceImplant"],
    				["Intelligence", "intelligence"],
    				["Fetish", "fetish"],
    
    vas's avatar
    vas committed
    				["Accent", "accent"],
    				["Waist", "waist"],
    
    vas's avatar
    vas committed
    				["Amputation", "amp"],
    
    vas's avatar
    vas committed
    			];
    
    			this.fnlist = new List("Activation function", items, false);
    
    			this.fnlist.setValue(["between", "belongs"].includes(current_rule.condition.function) ? current_rule.condition.data.attribute : current_rule.condition.function);
    
    vas's avatar
    vas committed
    			this.fnlist.onchange = (value) => this.fnchanged(value);
    
    vas's avatar
    vas committed
    			this.appendChild(this.fnlist);
    
    vas's avatar
    vas committed
    			this.fneditor = null;
    
    vas's avatar
    vas committed
    
    
    brickode's avatar
    brickode committed
    			switch (current_rule.condition.function) {
    
    vas's avatar
    vas committed
    				case false:
    				case true:
    
    vas's avatar
    vas committed
    					break;
    
    vas's avatar
    vas committed
    				case "custom":
    
    					this.show_custom_editor(CustomEditor, current_rule.condition.data);
    
    vas's avatar
    vas committed
    					break;
    
    				case "between":
    
    					this.show_custom_editor(RangeEditor, current_rule.condition.function, current_rule.condition.data);
    
    vas's avatar
    vas committed
    					break;
    
    				case "belongs":
    					this.show_custom_editor(ItemEditor, current_rule.condition.function, current_rule.condition.data);
    					break;
    
    vas's avatar
    vas committed
    			}
    		}
    
    
    		betweenP(attribute) {
    			return [
    				"devotion",
    				"trust",
    
    Pregmodder's avatar
    Pregmodder committed
    				"height",
    
    				"weight",
    				"actualAge",
    				"physicalAge",
    				"visualAge",
    				"muscles",
    				"lactation",
    				"preg",
    				"pregType",
    				"bellyImplant",
    				"belly",
    				"intelligenceImplant",
    				"intelligence",
    
    vas's avatar
    vas committed
    				"accent",
    				"waist",
    
    			].includes(attribute);
    		}
    
    		belongsP(attribute) {
    			return [
    				"fetish",
    
    vas's avatar
    vas committed
    				"amp",
    
    Pregmodder's avatar
    Pregmodder committed
    				"genes",
    
    			].includes(attribute);
    		}
    
    
    		show_custom_editor(what, ...args) {
    
    DCoded's avatar
    DCoded committed
    			if (this.custom_editor !== null) { this.hide_custom_editor(); }
    
    			this.custom_editor = new what(...args);
    			this.appendChild(this.custom_editor);
    		}
    
    		hide_custom_editor() {
    			if (this.custom_editor) {
    				this.custom_editor.remove();
    				this.custom_editor = null;
    			}
    		}
    
    
    vas's avatar
    vas committed
    		render() {
    
    Skriv's avatar
    Skriv committed
    			return document.createElement("div");
    
    vas's avatar
    vas committed
    		}
    
    		fnchanged(value) {
    			if (this.fneditor !== null) {
    
    vas's avatar
    vas committed
    				this.fneditor.element.remove();
    				this.fneditor = null;
    
    vas's avatar
    vas committed
    			}
    
    			if (value === true || value === false) {
    				current_rule.condition.function = value;
    				current_rule.condition.data = {};
    				this.hide_custom_editor();
    			} else if (value === "custom") {
    				current_rule.condition.function = "custom";
    				current_rule.condition.data = "";
    				this.show_custom_editor(CustomEditor, current_rule.condition.data);
    			} else if (this.betweenP(value)) {
    				current_rule.condition.function = "between";
    
    brickode's avatar
    brickode committed
    				current_rule.condition.data = {attribute: value, value: [null, null]};
    
    				this.show_custom_editor(RangeEditor, current_rule.condition.function, current_rule.condition.data);
    			} else if (this.belongsP(value)) {
    				current_rule.condition.function = "belongs";
    
    brickode's avatar
    brickode committed
    				current_rule.condition.data = {attribute: value, value: []};
    
    				this.show_custom_editor(ItemEditor, current_rule.condition.function, current_rule.condition.data);
    
    vas's avatar
    vas committed
    			}
    		}
    	}
    
    	class CustomEditor extends Element {
    		constructor(data) {
    
    DCoded's avatar
    DCoded committed
    			if (data.length === 0) { data = "(slave) => slave.slaveName === 'Fancy Name'"; }
    
    vas's avatar
    vas committed
    			super(data);
    
    vas's avatar
    vas committed
    		}
    
    		render(data) {
    
    vas's avatar
    vas committed
    			const elem = document.createElement("div");
    			const textarea = document.createElement("textarea");
    			textarea.innerHTML = data;
    
    			$(textarea).blur(() => {
    				current_rule.condition.data = textarea.value;
    
    				// TODO: this would be a good place to cache the Function object that will be used by RuleHasError and ruleAppliesP
    
    vas's avatar
    vas committed
    			elem.appendChild(textarea);
    
    			if(RuleHasError(current_rule)) {
    
    				const errorMessage = document.createElement("div");
    				$(errorMessage).addClass("yellow");
    
    klorpa's avatar
    klorpa committed
    				errorMessage.innerText = "WARNING: There are errors in this condition. Please ensure the syntax is correct and equality is either '==' or '===', not '='";
    
    vas's avatar
    vas committed
    			const explanation = document.createElement("div");
    
    			explanation.innerHTML = `Insert <kbd>(slave) =></kbd> followed by a valid <a target='_blank' class='link-external' href='https://www.w3schools.com/js/js_comparisons.asp'>JavaScript comparison and/or logical operation</a>. For variable names to use see <a target='_blank' class='link-external' href='https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/slave%20variables%20documentation%20-%20Pregmod.txt'>this list</a>.`;
    
    vas's avatar
    vas committed
    			elem.appendChild(explanation);
    
    vas's avatar
    vas committed
    			return elem;
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    vas's avatar
    vas committed
    	class RangeEditor extends Element {
    
    vas's avatar
    vas committed
    		render(fn, data) {
    
    vas's avatar
    vas committed
    			const elem = document.createElement("div");
    
    vas's avatar
    vas committed
    
    
    vas's avatar
    vas committed
    			const minlabel = document.createElement("label");
    			minlabel.innerHTML = "Lower bound: ";
    			elem.appendChild(minlabel);
    
    
    vas's avatar
    vas committed
    			const min = document.createElement("input");
    			min.setAttribute("type", "text");
    
    Skriv's avatar
    Skriv committed
    			min.value = `${data.value[0]}`;
    
    DCoded's avatar
    DCoded committed
    			min.onkeypress = e => { if (returnP(e)) { this.setmin(min.value); } };
    
    brickode's avatar
    brickode committed
    			min.onblur = e => this.setmin(min.value);
    
    			this.min = min;
    
    vas's avatar
    vas committed
    			elem.appendChild(min);
    
    vas's avatar
    vas committed
    
    
    vas's avatar
    vas committed
    			elem.appendChild(document.createElement("br"));
    
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			const maxLabel = document.createElement("label");
    			maxLabel.innerHTML = "Upper bound: ";
    			elem.appendChild(maxLabel);
    
    vas's avatar
    vas committed
    			const max = document.createElement("input");
    			max.setAttribute("type", "text");
    
    Skriv's avatar
    Skriv committed
    			max.value = `${data.value[1]}`;
    
    DCoded's avatar
    DCoded committed
    			max.onkeypress = e => { if (returnP(e)) { this.setmax(max.value); } };
    
    brickode's avatar
    brickode committed
    			max.onblur = e => this.setmax(max.value);
    
    			this.max = max;
    
    vas's avatar
    vas committed
    			elem.appendChild(max);
    
    vas's avatar
    vas committed
    
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			const infoBar = document.createElement("div");
    			infoBar.innerHTML = this.info(data.attribute);
    			elem.appendChild(infoBar);
    
    vas's avatar
    vas committed
    
    
    vas's avatar
    vas committed
    			return elem;
    
    vas's avatar
    vas committed
    		}
    
    		parse(value) {
    
    			value = value.trim();
    
    DCoded's avatar
    DCoded committed
    			if (value === "null") {
    				value = null;
    			} else {
    
    vas's avatar
    vas committed
    				value = parseInt(value);
    
    DCoded's avatar
    DCoded committed
    				if (isNaN(value)) { value = null; }
    
    vas's avatar
    vas committed
    			}
    
    vas's avatar
    vas committed
    			return value;
    
    vas's avatar
    vas committed
    		}
    
    		setmin(value) {
    
    			current_rule.condition.data.value[0] = this.parse(value);
    
    Skriv's avatar
    Skriv committed
    			this.min.value = `${current_rule.condition.data.value[0]}`;
    
    vas's avatar
    vas committed
    		}
    
    		setmax(value) {
    
    			current_rule.condition.data.value[1] = this.parse(value);
    
    Skriv's avatar
    Skriv committed
    			this.max.value = `${current_rule.condition.data.value[1]}`;
    
    vas's avatar
    vas committed
    		}
    
    		info(attribute) {
    
    vas's avatar
    vas committed
    			return ({
    				"devotion": "Very Hateful: (-∞, -95), Hateful: [-95, -50), Resistant: [-50, -20), Ambivalent: [-20, 20], Accepting: (20, 50], Devoted: (50, 95], Worshipful: (95, ∞)",
    				"trust": "Extremely terrified: (-∞, -95), Terrified: [-95, -50), Frightened: [-50, -20), Fearful: [-20, 20], Careful: (20, 50], Trusting: (50, 95], Total trust: (95, ∞)",
    
    				"health.condition": "Death: (-∞, -100), Near Death: [-100, -90), Extremely Unhealthy: [-90, -50), Unhealthy: [-50, -20), Healthy: [-20, 20], Very Healthy: (20, 50], Extremely Healthy: (50, 90], Unnaturally Healthy: (90, ∞)",
    
    vas's avatar
    vas committed
    				"energy": "Frigid: (-∞, 20], Poor: (20, 40], Average: (40, 60], Powerful: (60, 80], Sex Addict: (80, 100), Nympho: 100",
    				"weight": "Emaciated: (-∞, -95), Skinny: [-95, -30), Thin: [-30, -10), Average: [-10, 10], Plush: (10, 30], Fat: (30, 95], Overweight: (95, ∞)",
    				"lactation": "None: 0, 1: Natural, 2: Lactation implant",
    				"preg": "Barren: -2, On contraceptives: -1, Not pregnant: 0, Pregnancy weeks: [1, ∞)",
    				"pregType": "Fetus count, known only after the 10th week of pregnancy",
    				"bellyImplant": "Volume in CCs. None: -1",
    				"belly": "Volume in CCs, any source",
    
    Pregmodder's avatar
    Pregmodder committed
    				"intelligenceImplant": "Education level. 0: uneducated, 15: educated, 30: advanced education, (0, 15): incomplete education.",
    				"intelligence": "From moronic to brilliant: [-100, 100]",
    
    vas's avatar
    vas committed
    				"accent": "No accent: 0, Nice accent: 1, Bad accent: 2, Can't speak language: 3 and above",
    
    				"waist": "Masculine waist: (95, ∞), Ugly waist: (40, 95], Unattractive waist: (10, 40], Average waist: [-10, 10], Feminine waist: [-40, -10), Wasp waist: [-95, -40), Absurdly narrow: (-∞, -95)",
    
    brickode's avatar
    brickode committed
    			} [attribute] || " ");
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    	class ItemEditor extends Element {
    		render(fn, data) {
    			const elem = document.createElement("div");
    
    			const input = document.createElement("input");
    			input.setAttribute("type", "text");
    			input.value = JSON.stringify(data.value);
    
    DCoded's avatar
    DCoded committed
    			input.onkeypress = e => { if (returnP(e)) { this.setValue(input); } };
    
    brickode's avatar
    brickode committed
    			input.onblur = e => this.setValue(input);
    
    			this.input = input;
    			elem.appendChild(input);
    
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			const infoBar = document.createElement("div");
    			infoBar.innerHTML = this.info(data.attribute);
    			elem.appendChild(infoBar);
    
    
    			return elem;
    		}
    
    		info(attribute) {
    
    Skriv's avatar
    Skriv committed
    			return `Insert a valid JSON array. Known values: ${{
    
    vas's avatar
    vas committed
    				"fetish": "buttslut, cumslut, masochist, sadist, dom, submissive, boobs, pregnancy, none (AKA vanilla)",
    
    vas's avatar
    vas committed
    				"amp": "Amputated: 1, Not amputated: 0",
    
    Pregmodder's avatar
    Pregmodder committed
    				"genes": "XX, XY",
    
    Skriv's avatar
    Skriv committed
    			}[attribute]}`;
    
    klorpa's avatar
    klorpa committed
    
    
    		setValue(input) {
    			try {
    				const arr = JSON.parse(input.value);
    				current_rule.condition.data.value = arr;
    				input.value = JSON.stringify(arr);
    			} catch (e) {
    				alert(e);
    			}
    		}
    	}
    
    
    ezsh's avatar
    ezsh committed
    	class AssignmentInclusionBase extends ButtonList {
    		/**
    		 * @param {string} label
    
    		 * @param {FC.Data.JobDesc[]} [jobs]
    
    ezsh's avatar
    ezsh committed
    		 * @param {App.Entity.Facilities.SingleJobFacility[]} [facilities]
    		 */
    		constructor(label, jobs, facilities) {
    			super(label);
    			this._attributes = {};
    			if (jobs !== undefined) {
    				jobs.forEach(job => {
    					this._attributes[capFirstChar(job.position)] = job.assignment;
    				});
    
    DCoded's avatar
    DCoded committed
    			}
    
    ezsh's avatar
    ezsh committed
    			if (facilities !== undefined) {
    				facilities.forEach(f => {
    					if (f.established && f.desc.defaultJob != null) { /* eslint-disable-line eqeqeq */
    						const displayName = f.name === "the " + f.genericName ? f.genericName : f.name;
    						this._attributes[displayName] = f.desc.jobs[f.desc.defaultJob].assignment;
    					}
    				});
    
    DCoded's avatar
    DCoded committed
    			}
    
    ezsh's avatar
    ezsh committed
    			for (const i in this._attributes) {
    				this.appendChild(new ButtonItem(i, this.getAttribute(i), current_rule.condition.assignment.includes(this.getAttribute(i))));
    
    DCoded's avatar
    DCoded committed
    			}
    
    vas's avatar
    vas committed
    		}
    
    		onchange() {
    
    ezsh's avatar
    ezsh committed
    			const allValues = this.getAllValues();
    			current_rule.condition.assignment = this.getSelection().concat(current_rule.condition.assignment.filter(a => !allValues.includes(a)));
    
    vas's avatar
    vas committed
    		}
    
    		getAttribute(what) {
    
    ezsh's avatar
    ezsh committed
    			return this._attributes[what];
    		}
    	}
    
    
    	class AssignmentInclusion extends AssignmentInclusionBase {
    
    vas's avatar
    vas committed
    		constructor() {
    
    ezsh's avatar
    ezsh committed
    			let facilities = [];
    			for (const f of Object.values(App.Entity.facilities)) {
    				if (f === App.Entity.facilities.penthouse) {
    					continue;
    				}
    				if (f.established) {
    					facilities.push(f);
    				}
    			}
    			super("Apply to assignments and facilities", Object.values(App.Data.Facilities.penthouse.jobs), facilities);
    		}
    	}
    
    	class FacilityHeadAssignmentInclusion extends AssignmentInclusionBase {
    		constructor() {
    			const jobs = [];
    			for (const f of Object.values(App.Entity.facilities)) {
    				if (f.established && f.desc.manager !== null) {
    					jobs.push(f.desc.manager);
    				}
    			}
    			super("Apply to facility heads", jobs);
    
    vas's avatar
    vas committed
    		}
    	}
    
    	class SpecificInclusionExclusion extends Options {
    		constructor() {
    
    vas's avatar
    vas committed
    			super();
    
    vas's avatar
    vas committed
    			this.appendChild(new OptionsItem("Limit to specific slaves", () => this.show_slave_selection()));
    			this.appendChild(new OptionsItem("Exclude specific slaves", () => this.show_slave_exclusion()));
    			this.subwidget = null;
    		}
    
    		show_slave_selection() {
    
    DCoded's avatar
    DCoded committed
    			if (this.subwidget) { this.subwidget.remove(); }
    
    vas's avatar
    vas committed
    			this.subwidget = new SlaveSelection();
    			this.appendChild(this.subwidget);
    		}
    
    		show_slave_exclusion() {
    
    DCoded's avatar
    DCoded committed
    			if (this.subwidget) { this.subwidget.remove(); }
    
    vas's avatar
    vas committed
    			this.subwidget = new SlaveExclusion();
    			this.appendChild(this.subwidget);
    		}
    	}
    
    	class SlaveSelection extends ButtonList {
    		constructor() {
    			super("Include specific slaves");
    			V.slaves.forEach(slave => this.appendChild(new ButtonItem(
    				[slave.slaveName, slave.slaveSurname].join(" "),
    				slave.ID,
    				current_rule.condition.selectedSlaves.includes(slave.ID))));
    		}
    
    
    		onchange() {
    			current_rule.condition.selectedSlaves = this.getSelection();
    		}
    
    vas's avatar
    vas committed
    	}
    
    	class SlaveExclusion extends ButtonList {
    		constructor() {
    			super("Exclude specific slaves");
    			V.slaves.forEach(slave => this.appendChild(new ButtonItem(
    				[slave.slaveName, slave.slaveSurname].join(" "),
    				slave.ID,
    				current_rule.condition.excludedSlaves.includes(slave.ID))));
    		}
    
    
    		onchange() {
    			current_rule.condition.excludedSlaves = this.getSelection();
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    i107760's avatar
    i107760 committed
    	class ApplyRuleOnce extends ButtonItem {
    		constructor() {
    			super("Do not apply rule (and overwrite manual changes) every time rule is executed, but only once per slave", false, (current_rule.condition.applyRuleOnce === true));
    		}
    
    		onchange() {
    			if (!current_rule.condition.applyRuleOnce) {
    				current_rule.condition.applyRuleOnce = true;
    			} else {
    				current_rule.condition.applyRuleOnce = false;
    			}
    		}
    	}
    
    
    vas's avatar
    vas committed
    	// parent section for effect editing
    	class EffectEditor extends Element {
    		constructor() {
    
    vas's avatar
    vas committed
    			super();
    
    			this.appendChild(new AppearanceTab(this.tabButtons_));
    			this.appendChild(new CosmeticTab(this.tabButtons_));
    			this.appendChild(new BodyModTab(this.tabButtons_));
    			this.appendChild(new AutosurgeryTab(this.tabButtons_));
    			this.appendChild(new RegimenTab(this.tabButtons_));
    			this.appendChild(new BehaviourTab(this.tabButtons_));
    			this.appendChild(new OtherTab(this.tabButtons_));
    
    vas's avatar
    vas committed
    		}
    
    		render() {
    
    vas's avatar
    vas committed
    			const element = document.createElement("div");
    
    			element.className = "ra-setters";
    			this.tabButtons_ = document.createElement("div");
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this.tabButtons_.className = "tab-bar";
    
    			element.appendChild(this.tabButtons_);
    
    vas's avatar
    vas committed
    			return element;
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    	class AppearanceTab extends Tab {
    		constructor(tabButtons) {
    			super("appearance", "Appearance", tabButtons);
    
    vas's avatar
    vas committed
    			this.appendChild(new ClothesList());
    			this.appendChild(new CollarList());
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this.appendChild(new GagList());
    			this.appendChild(new MaskList());
    
    vas's avatar
    vas committed
    			this.appendChild(new ShoeList());
    			this.appendChild(new CorsetList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new GlovesList());
    
    vas's avatar
    vas committed
    			this.appendChild(new LeggingsList());
    
    			this.appendChild(new VagChastityList());
    
    vas's avatar
    vas committed
    			this.appendChild(new VagAccVirginsList());
    			this.appendChild(new VagAccAVirginsList());
    			this.appendChild(new VagAccOtherList());
    
    DCoded's avatar
    DCoded committed
    			this.appendChild(new VaginalAttachmentsList());
    
    vas's avatar
    vas committed
    			if (V.seeDicks !== 0 || V.makeDicks !== 0) {
    
    				this.appendChild(new DickChastityList());
    
    vas's avatar
    vas committed
    				this.appendChild(new DickAccVirginsList());
    				this.appendChild(new DickAccOtherList());
    
    vas's avatar
    vas committed
    			}
    
    			this.appendChild(new AnalChastityList());
    
    vas's avatar
    vas committed
    			this.appendChild(new ButtplugsVirginsList());
    			this.appendChild(new ButtplugsOtherList());
    
    			this.appendChild(new ButtplugAttachmentsList());
    
    vas's avatar
    vas committed
    			this.appendChild(new ImplantVolumeList());
    
    	class RegimenTab extends Tab {
    		constructor(tabButtons) {
    
    			super("regimen", "Physical Regimen", tabButtons);
    
    Skriv's avatar
    Skriv committed
    			if (V.arcologies[0].FSAssetExpansionistResearch === 1) {
    
    kopareigns's avatar
    kopareigns committed
    				this.appendChild(new HyperGrowthSwitch());
    
    Skriv's avatar
    Skriv committed
    			}
    
    ezsh's avatar
    ezsh committed
    			this.appendChild(new IntensiveGrowthSwitch());
    
    vas's avatar
    vas committed
    			this.appendChild(new GrowthList());
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this.appendChild(new CurativesList());
    
    vas's avatar
    vas committed
    			this.appendChild(new AphrodisiacList());
    			this.appendChild(new ContraceptiveList());
    
    Pregmodder's avatar
    Pregmodder committed
    			this.appendChild(new AbortionList());
    
    DCoded's avatar
    DCoded committed
    			if (V.pregSpeedControl) {
    
    vas's avatar
    vas committed
    				this.appendChild(new PregDrugsList());
    
    DCoded's avatar
    DCoded committed
    			}
    
    vas's avatar
    vas committed
    			this.appendChild(new FemaleHormonesList());
    			this.appendChild(new ShemaleHormonesList());
    			this.appendChild(new GeldingHormonesList());
    			this.appendChild(new OtherDrugsList());
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			if (V.boughtItem.toys.enema === 1) {
    
    Pregmodder's avatar
    Pregmodder committed
    				this.appendChild(new EnemaList());
    			}
    
    Skriv's avatar
    Skriv committed
    			this.appendChild(new WeightEditor());
    
    vas's avatar
    vas committed
    			this.appendChild(new DietList());
    			this.appendChild(new DietGrowthList());
    			this.appendChild(new DietBaseList());
    
    Pregmodder's avatar
    Pregmodder committed
    			if (V.arcologies[0].FSHedonisticDecadenceResearch === 1) {
    				this.appendChild(new DietSolidFoodList());
    			}
    
    vas's avatar
    vas committed
    			this.appendChild(new MuscleList());
    			this.appendChild(new BraceList());
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    	class BehaviourTab extends Tab {
    		constructor(tabButtons) {
    			super("behavior", "Behavior", tabButtons);
    
    vas's avatar
    vas committed
    			this.appendChild(new AutomaticAssignmentList());
    
    brickode's avatar
    brickode committed
    			if (V.pit) {
    				this.appendChild(new PitAssignmentList());
    
    vas's avatar
    vas committed
    			this.appendChild(new LivingStandardList());
    
    Pregmodder's avatar
    Pregmodder committed
    			this.appendChild(new RestList());
    
    vas's avatar
    vas committed
    			this.appendChild(new PunishmentList());
    			this.appendChild(new RewardList());
    
    			this.appendChild(new ReleaseMasturbationSwitch());
    			this.appendChild(new ReleasePartnerSwitch());
    
    			this.appendChild(new ReleaseFacilityLeaderSwitch());
    
    			this.appendChild(new ReleaseFamilySwitch());
    			this.appendChild(new ReleaseSlavesSwitch());
    			this.appendChild(new ReleaseMasterSwitch());
    
    Pregmodder's avatar
    Pregmodder committed
    			this.appendChild(new ToyHoleList());
    
    vas's avatar
    vas committed
    			this.appendChild(new SmartFetishList());
    			this.appendChild(new SmartXYAttractionList());
    			this.appendChild(new SmartXXAttractionList());
    			this.appendChild(new SmartEnergyList());
    			this.appendChild(new SpeechList());
    			this.appendChild(new RelationshipList());
    
    			this.appendChild(new LactationList());
    
    Pregmodder's avatar
    Pregmodder committed
    			this.appendChild(new MobilityDeviceList());
    
    			if (V.studio === 1) {
    				this.appendChild(new PornBroadcastStatus());
    
    vas's avatar
    vas committed
    				this.appendChild(new PornList());
    
    vas's avatar
    vas committed
    		}
    	}
    
    klorpa's avatar
    klorpa committed
    
    
    	class OtherTab extends Tab {
    		constructor(tabButtons) {
    			super("other", "Other", tabButtons);
    
    			this.appendChild(new ClearLabelSwitch());
    
    vas's avatar
    vas committed
    			this.appendChild(new LabelList());
    
    			this.appendChild(new LabelRemoveList());
    
    		}
    	}
    
    	class ClearLabelSwitch extends BooleanSwitch {
    		constructor() {
    
    			super("Remove all tags (Global switch)", [false, true]);
    
    			this.setValue(current_rule.set.labelTagsClear);
    			this.onchange = (value) => current_rule.set.labelTagsClear = value;
    
    vas's avatar
    vas committed
    
    
    	class CosmeticTab extends Tab {
    		constructor(tabButtons) {
    			super("cosmetic", "Cosmetic", tabButtons);
    
    vas's avatar
    vas committed
    			this.appendChild(new EyewearList());
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this.appendChild(new IrisColorList());
    			this.appendChild(new PupilShapeList());
    			this.appendChild(new ScleraColorList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new EarwearList());
    
    vas's avatar
    vas committed
    			this.appendChild(new MakeupList());
    			this.appendChild(new NailsList());
    			this.appendChild(new HairLengthList());
    
    2hu4u's avatar
    2hu4u committed
    			this.appendChild(new HaircutsList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new HairColorList());
    
    vas's avatar
    vas committed
    			this.appendChild(new HairStyleList());
    
    			this.appendChild(new EyebrowColorList());
    			this.appendChild(new EyebrowStyleList());
    			this.appendChild(new EyebrowFullnessList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new PubicHairColorList());
    
    vas's avatar
    vas committed
    			this.appendChild(new PubicHairStyleList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new ArmpitHairColorList());
    
    vas's avatar
    vas committed
    			this.appendChild(new ArmpitHairStyleList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new SkinColorList());
    
    			this.appendChild(new MarkingsList());
    
    			this.appendChild(new HornColorList());
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    	class BodyModTab extends Tab {
    		constructor(tabButtons) {
    			super("bodyMod", "Body Mod", tabButtons);
    
    vas's avatar
    vas committed
    			this.appendChild(new EarPiercingList());
    			this.appendChild(new NosePiercingList());
    			this.appendChild(new EyebrowPiercingList());
    			this.appendChild(new NavelPiercingList());
    			this.appendChild(new NipplePiercingList());
    			this.appendChild(new AreolaPiercingList());
    			this.appendChild(new LipPiercingList());
    			this.appendChild(new TonguePiercingList());
    			this.appendChild(new ClitPiercingList());
    			this.appendChild(new LabiaPiercingList());
    			this.appendChild(new ShaftPiercingList());
    			this.appendChild(new PerineumPiercingList());
    			this.appendChild(new CorsetPiercingList());
    
    			this.appendChild(new AutoBrandingList());
    			this.appendChild(new BrandingLocationList());
    			this.appendChild(new BrandDesignList());
    
    			this.appendChild(new FaceTattooList());
    			this.appendChild(new ShoulderTattooList());
    			this.appendChild(new ChestTattooList());
    			this.appendChild(new ArmTattooList());
    			this.appendChild(new UpperBackTattooList());
    			this.appendChild(new LowerBackTattooList());
    			this.appendChild(new AbdomenTattooList());
    
    DCoded's avatar
    DCoded committed
    			if (V.seeDicks || V.makeDicks) {
    
    vas's avatar
    vas committed
    				this.appendChild(new DickTattooList());
    
    DCoded's avatar
    DCoded committed
    			}
    
    vas's avatar
    vas committed
    			this.appendChild(new ButtockTattooList());
    			this.appendChild(new AnalTattooList());
    			this.appendChild(new LegTattooList());
    
    klorpa's avatar
    klorpa committed
    
    
    Pregmodder's avatar
    Pregmodder committed
    			this.appendChild(new BirthsTattooList());
    			this.appendChild(new AbortionTattooList());
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    	class AutosurgeryTab extends Tab {
    		constructor(tabButtons) {
    			super("autosurgery", "Autosurgery", tabButtons);
    
    			this.appendChild(new AutosurgerySwitch());
    
    vas's avatar
    vas committed
    			this.appendChild(new VisionSurgeryList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new HearingSurgeryList());
    
    klorpa's avatar
    klorpa committed
    			this.appendChild(new SmellSurgeryList());
    			this.appendChild(new TasteSurgeryList());
    
    vas's avatar
    vas committed
    			this.appendChild(new LactationSurgeryList());
    
    vas's avatar
    vas committed
    			if (V.seeDicks || V.makeDicks) {
    
    vas's avatar
    vas committed
    				this.appendChild(new SemenSurgeryList());
    
    vas's avatar
    vas committed
    				this.appendChild(new VasectomyList());
    			}
    
    vas's avatar
    vas committed
    			this.appendChild(new CosmeticSurgeryList());
    			this.appendChild(new LipSurgeryList());
    			this.appendChild(new ButtSurgeryList());
    			this.appendChild(new BreastSurgeryList());
    			this.appendChild(new TighteningSurgeryList());
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this.appendChild(new TummyTuckSurgeryList());
    
    vas's avatar
    vas committed
    			this.appendChild(new BodyHairSurgeryList());
    			this.appendChild(new HairSurgeryList());
    
    DCoded's avatar
    DCoded committed
    			if (V.bellyImplants > 0) {
    
    vas's avatar
    vas committed
    				this.appendChild(new BellyImplantList());
    
    DCoded's avatar
    DCoded committed
    			}
    
    			this.appendChild(new EarShapeSurgeryList());
    			this.appendChild(new HornSurgeryList());
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    vas's avatar
    vas committed
    	class ClothesList extends List {
    		constructor() {
    			const items = [
    				["Select her own outfit", "choosing her own clothes"]
    			];
    			super("Clothes", items);
    
    
    			const nClothes = isItemAccessible.array(App.Data.clothes, "harsh", !true);
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			nClothes.sort(function(a, b) { if (a[0] < b[0]) { return -1; } if (a[0] > b[0]) { return 1; } return 0; });
    			this._nice = new ListSubSection(this, "Nice", nClothes);
    
    vas's avatar
    vas committed
    
    
    			const hClothes = isItemAccessible.array(App.Data.clothes, "harsh", true);
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			hClothes.sort(function(a, b) { if (a[0] < b[0]) { return -1; } if (a[0] > b[0]) { return 1; } return 0; });
    
    vas's avatar
    vas committed
    
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this._harsh = new ListSubSection(this, "Harsh", hClothes);
    
    vas's avatar
    vas committed
    
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.clothes);
    
    vas's avatar
    vas committed
    			this.onchange = (value) => current_rule.set.clothes = value;
    
    vas's avatar
    vas committed
    		}
    
    ezsh's avatar
    ezsh committed
    
    		_appendContentTo(container) {
    			super._appendContentTo(container);
    			this._nice._appendContentTo(container);
    			this._harsh._appendContentTo(container);
    		}
    
    vas's avatar
    vas committed
    	}
    
    	class CollarList extends List {
    		constructor() {
    			const items = [
    				["No collar", "none"],
    			];
    			super("Collar", items);
    
    
    			const niceCollars = isItemAccessible.array(App.Data.slaveWear.collars, "harsh", false);
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			niceCollars.sort(function(a, b) { if (a[0] < b[0]) { return -1; } if (a[0] > b[0]) { return 1; } return 0; });
    			this._nice = new ListSubSection(this, "Nice", niceCollars);
    
    
    			const harshCollars = isItemAccessible.array(App.Data.slaveWear.collars, "harsh", true);
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			harshCollars.sort(function(a, b) { if (a[0] < b[0]) { return -1; } if (a[0] > b[0]) { return 1; } return 0; });
    			this._harsh = new ListSubSection(this, "Harsh", harshCollars);
    
    vas's avatar
    vas committed
    
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.collar);
    			this.onchange = (value) => current_rule.set.collar = value;
    
    vas's avatar
    vas committed
    		}
    
    ezsh's avatar
    ezsh committed
    
    		_appendContentTo(container) {
    			super._appendContentTo(container);
    			this._nice._appendContentTo(container);
    			this._harsh._appendContentTo(container);
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    	class MaskList extends ListSelector {
    		constructor() {
    
    			const pairs = [["No mask", "none"]].concat(isItemAccessible.array(App.Data.slaveWear.faceAccessory ));
    
    			super("Mask", pairs);
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this.setValue(current_rule.set.faceAccessory );
    			this.onchange = (value) => current_rule.set.faceAccessory  = value;
    		}
    	}
    
    	class GagList extends ListSelector {
    		constructor() {
    
    			const pairs = [["No gag", "none"]].concat(isItemAccessible.array(App.Data.slaveWear.mouthAccessory ));
    
    			super("Gag", pairs);
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    			this.setValue(current_rule.set.mouthAccessory );
    			this.onchange = (value) => current_rule.set.mouthAccessory = value;
    		}
    	}
    
    	class ShoeList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Shoes", isItemAccessible.array(App.Data.slaveWear.shoes));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.shoes);
    			this.onchange = (value) => current_rule.set.shoes = value;
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    	class CorsetList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Corsetage", isItemAccessible.array(App.Data.slaveWear.bellyAccessories));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.bellyAccessory);
    
    vas's avatar
    vas committed
    			this.onchange = (value) => current_rule.set.bellyAccessory = value;
    
    vas's avatar
    vas committed
    		}
    	}
    
    
    klorpa's avatar
    klorpa committed
    	class GlovesList extends ListSelector {
    		constructor() {
    			const items = [
    				["none"],
    				["hand gloves"],
    				["elbow gloves"],
    			];
    
    			super("Arm accessory", items, true);
    
    klorpa's avatar
    klorpa committed
    			this.setValue(current_rule.set.armAccessory);
    			this.onchange = (value) => current_rule.set.armAccessory = value;
    		}
    	}
    
    
    lowercasedonkey's avatar
    lowercasedonkey committed
    	class LeggingsList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    			const items = [
    
    				["none"],
    				["short stockings"],
    				["long stockings"],
    
    vas's avatar
    vas committed
    			];
    
    			super("Leg accessory", items, true);
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.legAccessory);
    			this.onchange = (value) => current_rule.set.legAccessory = value;
    		}
    	}
    
    
    ezsh's avatar
    ezsh committed
    	class VagChastityList extends RadioSelector {
    
    		constructor() {
    			const chaste = [
    
    				["none", 0],
    				["chastity", 1],
    
    ezsh's avatar
    ezsh committed
    			super("Vaginal chastity", chaste, true);
    
    			this.setValue(current_rule.set.chastityVagina);
    			this.onchange = (value) => current_rule.set.chastityVagina = value;
    		}
    
    klorpa's avatar
    klorpa committed
    	}
    
    	class VagAccVirginsList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Vaginal accessories for virgins", isItemAccessible.array(App.Data.slaveWear.vaginalAccessories));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.virginAccessory);
    			this.onchange = (value) => current_rule.set.virginAccessory = value;
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    	class VagAccAVirginsList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Vaginal accessories for anal virgins", isItemAccessible.array(App.Data.slaveWear.vaginalAccessories));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.aVirginAccessory);
    			this.onchange = (value) => current_rule.set.aVirginAccessory = value;
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    	class VagAccOtherList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Vaginal accessories for other slaves", isItemAccessible.array(App.Data.slaveWear.vaginalAccessories));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.vaginalAccessory);
    			this.onchange = (value) => current_rule.set.vaginalAccessory = value;
    
    vas's avatar
    vas committed
    		}
    
    	class VaginalAttachmentsList extends ListSelector {
    
    		constructor() {
    
    			super("Vaginal attachments for slaves with vaginal accessories", isItemAccessible.array(App.Data.slaveWear.vaginalAttachments));
    
    			this.setValue(current_rule.set.vaginalAttachment);
    			this.onchange = (value) => current_rule.set.vaginalAttachment = value;
    		}
    
    vas's avatar
    vas committed
    	}
    
    DCoded's avatar
    DCoded committed
    
    
    ezsh's avatar
    ezsh committed
    	class DickChastityList extends RadioSelector {
    
    		constructor() {
    			const items = [
    
    				["none", 0],
    				["chastity cage", 1],
    
    ezsh's avatar
    ezsh committed
    			super("Penile chastity", items, true);
    
    			this.setValue(current_rule.set.chastityPenis);
    			this.onchange = (value) => current_rule.set.chastityPenis = value;
    		}
    
    klorpa's avatar
    klorpa committed
    	}
    
    vas's avatar
    vas committed
    
    
    	class DickAccVirginsList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Dick accessories for anal virgins", isItemAccessible.array(App.Data.slaveWear.dickAccessories));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.aVirginDickAccessory);
    			this.onchange = (value) => current_rule.set.aVirginDickAccessory = value;
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    	class DickAccOtherList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Dick accessories for other slaves", isItemAccessible.array(App.Data.slaveWear.dickAccessories));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.dickAccessory);
    			this.onchange = (value) => current_rule.set.dickAccessory = value;
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    ezsh's avatar
    ezsh committed
    	class AnalChastityList extends RadioSelector {
    
    		constructor() {
    			const items = [
    
    				["none", 0],
    				["chastity", 1],
    
    ezsh's avatar
    ezsh committed
    			super("Anal chastity", items, true);
    
    			this.setValue(current_rule.set.chastityAnus);
    			this.onchange = (value) => current_rule.set.chastityAnus = value;
    		}
    
    klorpa's avatar
    klorpa committed
    	}
    
    	class ButtplugsVirginsList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Buttplugs for anal virgins", isItemAccessible.array(App.Data.slaveWear.buttplugs));