Skip to content
Snippets Groups Projects
rulesAssistantOptions.js 114 KiB
Newer Older
  • Learn to ignore specific revisions
  • vas's avatar
    vas committed
    			button.checked = selected;
    			button.onchange = () => this.onchange(button.checked);
    
    vas's avatar
    vas committed
    			labelel.onclick = () => button.click();
    
    vas's avatar
    vas committed
    
    
    vas's avatar
    vas committed
    			container.appendChild(labelel);
    			container.appendChild(button);
    
    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.</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());
    
    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>.`;
    
    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"));
    
    			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
    
    
    vas's avatar
    vas 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);
    
    			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 {App.Data.JobDesc[]} [jobs]
    		 * @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
    	}
    
    
    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());
    			this.appendChild(new CurrativesList());
    			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());
    
    			if (V.pit === 1) {
    			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 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());
    			this.appendChild(new LensesList());
    
    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.slaveWear.niceClothes);
    
    			nclothes.sort(function(a, b) { if (a[0] < b[0]) { return -1; } if (a[0] > b[0]) { return 1; } return 0; });
    
    ezsh's avatar
    ezsh committed
    			this._nice = new ListSubSection(this, "Nice", nclothes);
    
    vas's avatar
    vas committed
    
    
    			const hclothes = isItemAccessible.array(App.Data.slaveWear.harshClothes);
    
    			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
    
    
    ezsh's avatar
    ezsh 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.niceCollars);
    
    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.harshCollars);
    
    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));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.aVirginButtplug);
    			this.onchange = (value) => current_rule.set.aVirginButtplug = value;
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}
    
    
    	class ButtplugsOtherList extends ListSelector {
    
    vas's avatar
    vas committed
    		constructor() {
    
    			super("Buttplugs for other slaves", isItemAccessible.array(App.Data.slaveWear.buttplugs));
    
    vas's avatar
    vas committed
    			this.setValue(current_rule.set.buttplug);
    			this.onchange = (value) => current_rule.set.buttplug = value;
    
    vas's avatar
    vas committed
    		}
    
    vas's avatar
    vas committed
    	}