:: Rules Assistant Options [script]

// rewrite of the rules assistant options page in javascript
// uses an object-oriented widget pattern
// wrapped in a closure so as not to polute the global namespace
// the widgets are generic enough to be reusable; if similar user interfaces are ported to JS, we could move the classes to the global scope

window.rulesAssistantOptions = (function() {
	"use strict"

	let V
	let r = ""

	function rulesAssistantOptions(element) {
		V = State.variables
		V.nextButton = "Back to Main"
		V.nextLink = "Main"
		V.returnTo = "Main"
		V.showEncyclopedia = 1
		V.encyclopedia = "Personal Assistant"
		const root = new Root(element)
	}

	function onreturn(e, cb) {
		if (e.keyCode === 13) cb()
	}

	// create a new rule and reload
	function newRule(root) {
		const id = generateNewID()
		V.defaultRules.push({
			ID: id,
			name: `Rule ${id}`,
			condition: {
				function: false,
				data: {},
				excludeSpecialSlaves: false,
				assignment: [],
				excludeAssignment: [],
				selectedSlaves: [],
				excludedSlaves: [],
				facility: [],
				excludeFacility: [],
			},
			set: {
				releaseRules: "no default setting",
				clitSetting: "no default setting",
				clitSettingXY: "no default setting",
				clitSettingXX: "no default setting",
				clitSettingEnergy: "no default setting",
				speechRules: "no default setting",
				clothes: "no default setting",
				collar: "no default setting",
				shoes: "no default setting",
				virginAccessory: "no default setting",
				aVirginAccessory: "no default setting",
				vaginalAccessory: "no default setting",
				aVirginDickAccessory: "no default setting",
				dickAccessory: "no default setting",
				bellyAccessory: "no default setting",
				aVirginButtplug: "no default setting",
				buttplug: "no default setting",
				eyeColor: "no default setting",
				makeup: "no default setting",
				nails: "no default setting",
				hColor: "no default setting",
				hLength: "no default setting",
				hStyle: "no default setting",
				pubicHColor: "no default setting",
				pubicHStyle: "no default setting",
				nipplesPiercing: "no default setting",
				areolaePiercing: "no default setting",
				clitPiercing: "no default setting",
				vaginaLube: "no default setting",
				vaginaPiercing: "no default setting",
				dickPiercing: "no default setting",
				anusPiercing: "no default setting",
				lipsPiercing: "no default setting",
				tonguePiercing: "no default setting",
				earPiercing: "no default setting",
				nosePiercing: "no default setting",
				eyebrowPiercing: "no default setting",
				navelPiercing: "no default setting",
				corsetPiercing: "no default setting",
				boobsTat: "no default setting",
				buttTat: "no default setting",
				vaginaTat: "no default setting",
				dickTat: "no default setting",
				lipsTat: "no default setting",
				anusTat: "no default setting",
				shouldersTat: "no default setting",
				armsTat: "no default setting",
				legsTat: "no default setting",
				backTat: "no default setting",
				stampTat: "no default setting",
				curatives: "no default setting",
				livingRules: "no default setting",
				relationshipRules: "no default setting",
				standardPunishment: "no default setting",
				standardReward: "no default setting",
				diet: "no default setting",
				dietCum: "no default setting",
				dietMilk: "no default setting",
				muscles: "no default setting",
				XY: "no default setting",
				XX: "no default setting",
				gelding: "no default setting",
				preg: "no default setting",
				growth_boobs: "no default setting",
				growth_butt: "no default setting",
				growth_lips: "no default setting",
				growth_dick: "no default setting",
				growth_balls: "no default setting",
				aphrodisiacs: "no default setting",
				autoSurgery: 0,
				autoBrand: 0,
				pornFameSpending: "no default setting",
				dietGrowthSupport: 0,
				eyewear: "no default setting",
				setAssignment: "no default setting",
				facilityRemove: false,
				removalAssignment: "rest",
				surgery_eyes: "no default setting",
				surgery_lactation: "no default setting",
				surgery_prostate: "no default setting",
				surgery_cosmetic: "no default setting",
				surgery_accent: "no default setting",
				surgery_shoulders: "no default setting",
				surgery_shouldersImplant: "no default setting",
				surgery_boobs: "no default setting",
				surgery_hips: "no default setting",
				surgery_hipsImplant: "no default setting",
				surgery_butt: "no default setting",
				surgery_faceShape: "no default setting",
				surgery_lips: "no default setting",
				surgery_holes: "not default setting",
				underArmHColor: "no default setting",
				underArmHStyle: "no default setting",
				drug: "no default setting",
				eyes: "no default setting",
				pregSpeed: "no default setting",
				bellyImplantVol: -1,
			}
		})
		V.currentRule = V.defaultRules[V.defaultRules.length-1]
		reload(root)
	}

	function removeRule(root) {
		const idx = V.defaultRules.findIndex(rule => rule.ID === V.currentRule.ID)
		V.defaultRules.splice(idx, 1)
		V.currentRule = idx < V.defaultRules.length ? idx : V.defaultRules.length - 1
		reload(root)
	}

	function lowerPriority(root) {
		if (V.defaultRules.length === 1) return // nothing to swap with
		const idx = V.defaultRules.findIndex(rule => rule.ID === V.currentRule.ID)
		if (idx === 0) return // no lower rule
		arraySwap(V.defaultRules, idx, idx-1)
		reload(root)
	}

	function higherPriority(root) {
		if (V.defaultRules.length === 1) return // nothing to swap with
		const idx = V.defaultRules.findIndex(rule => rule.ID === V.currentRule.ID)
		if (idx === V.defaultRules.length - 1) return // no higher rule
		arraySwap(V.defaultRules, idx, idx+1)
		reload(root)
	}

	function changeName(name, root) {
		if (name === V.currentRule.name) return
		V.currentRule = name
		reload(root)
	}

	// reload the passage
	function reload(root) {
		root.element.remove()
		rulesAssistantOptions()
	}

	// the Element class wraps around a DOM element and adds extra functionality
	// this is safer than extending DOM objects directly
	// it also turns DOM manipulation into an implementation detail
	class Element {
		constructor(...args) {
			this.parent = null
			this.element = this.render(...args)
			this.children = []
		}

		appendChild(child) {
			child.parent = this
			this.children.push(child)
			this.element.appendChild(child.element)
		}

		// return the first argument to simplify creation of basic container items
		render(...args) {
			return args[0]
		}
	}

	// list of clickable elements
	// has a short explanation (the prefix) and a value display
	// value display can optionally be an editable text input field
	// it can be "bound" to a variable by setting its "onchange" method
	class List extends Element {
		constructor(prefix, textinput=false) {
			super(prefix, textinput)
			this.selectedItem = null
			this.value = this.element.querySelector(".rajs-value")
		}

		render(prefix, textinput) {
			const elem = document.createElement("div")
			const label = document.createElement("span")
			label.innerHTML = prefix
			let value
			if (textinput) {
				value = document.createElement("input")
				value.classList.add("rajs-value")
				// call the variable binding when the input field is no longer being edited, and when the enter key is pressed
				value.onfocusout = () => { this.inputEdited() }
				value.onkeypress = (e) => { onreturn(e, () => { this.inputEdited() })}
			} else {
				value = document.createElement("strong")
			}
			value.setAttribute("type", "text")
			elem.appendChild(label)
			elem.appendChild(value)
			elem.classList.add("rajs-list")
			return elem
		}

		inputEdited() {
			if (this.selectedItem) this.selectedItem.deselect()
			this.propagateChange()
		}

		selectItem(item) {
			if (this.selectedItem) this.selectedItem.deselect()
			this.selectedItem = item
			setValue(item.setValue)
			this.propagateChange()
		}

		selectValue(what) {
			this.children.some(child => {
				if (child.data === what) {
					child.select()
					return true
				}
				else return false
			})
		}

		setValue(what) {
			if (this.value.tagName === "input")
				this.value.value = what
			else
				this.value.innerHTML = what
		}

		getValue(what) {
			return (this.value.tagName === "input" ? this.parse(this.value.value) : this.value.innerHTML)
		}

		// customisable input field parser / sanity checker
		parse(what) { return what }

		propagateChange() {
			if (this.onchange instanceof Function)
				this.onchange(this.getValue(), this.selectedItem.data)
		}
	}

	const parse = {
		integer(string) {
			let n = parseInt(string, 10)
			return n === NaN? 0: n
		},
		boobs(string) {
			return Math.clamp(parse.integer(string), 0, 48000)
		},
		butt(string) {
			return Math.clamp(parse.integer(string), 0, 10)
		},
		lips(string) {
			return Math.clamp(parse.integer(string), 0, 100)
		},
		dick(string) {
			return Math.clamp(parse.integer(string), 0, 10)
		},
		balls(string) {
			return Math.clamp(parse.integer(string), 0, 10)
		},
	}

	// a clickable item of a list
	class ListItem extends Element {
		constructor(displayvalue, setvalue, data) {
			super(displayvalue)
			this.setvalue = setvalue !== undefined ? setvalue : displayvalue
			this.data = data !== undefined ? data : this.setvalue !== undefined ? this.setvalue : displayvalue
			this.selected = false
		}

		render(displayvalue) {
			const elem = document.createElement("span")
			elem.classList.add("rajs-listitem")
			elem.innerHTML = displayvalue
			elem.onclick = () => { return this.select() }
			return elem
		}

		select() {
			if (this.selected) return false
			this.parent.selectItem(this)
			this.elem.classList.add("selected")
			this.selected = true
			return true
		}

		deselect() {
			this.elem.classList.remove("selected")
			this.selected = false
		}
	}

	// a way to organise lists with too many elements in subsections
	// children are bound to the master list
	class ListSubSection extends Element {
		render(label) {
			const elem = document.createElement("em")
			elem.innerText = label + ":"
			return elem
		}

		appendChild(child) {
			super.appendChild(child)
			child.parent = this.parent
			this.parent.children.push(child)
		}
	}

	// similar to list, but is just a collection of buttons
	class Options extends Element {
		constructor(elements=[]) {
			elements.forEach(element => { this.appendChild(element) })
		}

		render() {
			const elem = document.createElement("div")
			elem.classList.add("rajs-list")
			return elem
		}
	}

	// options equivalent of ListItem
	class OptionsItem extends Element {
		constructor(label, onclick) {
			super(label)
			this.label = label
			this.onclick = onclick
		}
		render(label, onclick) {
			const elem = document.createElement("span")
			elem.classList.add("rajs-listitem")
			elem.innerHTML = label
			elem.onclick = () => { return this.onclick(this) }
			return elem
		}
	}

	class ButtonList extends Element {
		render(label) {
			const elem = document.createElement("div")
			const labelel = document.createElement("span")
			labelel.innerhTML = label += ":"
			elem.appendChild(labelel)
			return elem
		}

		getSelection() {
			return (this.children
				.filter(child => child.selected)
				.map(child => child.setvalue)
			)
		}

		onchange() { return }
	}

	class ButtonItem extends Element {
		constructor(label, setvalue, selected=false) {
			super(label, selected)
			this.selected = selected
			this.setvalue = setvalue ? setvalue : label
		}

		render(label, selected) {
			const container = document.createElement("div")
			container.classList.add("rajs-listitem")

			const labelel = document.createElement("span")
			labelel.innerHTML = label

			const button = document.createElement("input")
			button.setAttribute("type", "checkbox")
			button.checked = selected
			button.onchange = () => this.onchange(button.checked)

			container.appendChild(labelel)
			container.appendChild(button)

			return container
		}

		onchange(value) {
			this.selected = value
			parent.onchange(this)
		}
	}

	// rule import field
	class NewRuleField extends Element {
		constructor(root) {
			super()
			this.root = root
		}

		render() {
			const container = document.createElement("div")
			const textarea = document.createElmenet("textarea")
			textarea.placeholder = "Paste your rule here"
			container.appendChild(textarea)
			this.textarea = textarea
			const button = document.createElement("button")
			button.name = "Load"
			button.onclick = () => { this.loadNewRule() }
			container.appendChild(button)
			return container
		}

		loadNewRule() {
			const text = this.textarea.value
			try {
				const rule = JSON.parse(text)
				if (!rule.ID) rule.ID = generateNewID()
				reload(this.root)
			} catch (e) {
				alert(e)
			}
		}
	}

	// the base element, parent of all elements
	class Root extends Element {
		constructor() {
			super()
			if(V.defaultRules.length === 0) {
				const paragraph = document.createElement("p")
				paragraph.innerHTML = "<strong>No rules</strong>"
				this.appendChild(new Element(paragraph))
				this.appendChild(new NoRules(this))
				return
			}
			this.appendChild(new RuleSelector(this))
			this.appendChild(new RuleOptions(this))
		}

		render(element) {
			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 'no default setting' option to identify areas I should not address.</em>`
			element.appendChild(greeting)
			return element
		}
	}

	// optoins displayed when there are no rules
	class NoRules extends Options {
		constructor(root) {
			super()
			this.root = root
			const newrule = new OptionsItem("Add a new rule", () => { newRule(this.root) })
			this.appendChild(newrule)
			const importrule = new OptionsItem("Import a rule", () => { this.root.appendChild(new NewRuleField()) })
			this.appendChild(importrule)
		}
	}

	// buttons for selecting the current rule
	class RuleSelector extends List {
		constructor(root) {
			super("Current rule:")
			if (!V.currentRule) V.currentRule = V.defaultRules[0]
			V.defaultRules.forEach(rule => {
				const item = new ListItem(rule.name, rule.name, rule)
				this.appendChild(item)
				if (rule.ID === V.currentRule.ID) item.select()
			})
			this.onchange = function (rulename, rule) {
				V.currentRule = rule
				reload(root)
			}
		}
	}

	// buttons for doing transformations on rules
	class RuleOptions extends Options {
		constructor(root) {
			super()
			this.appendChild(new OptionsItem("New Rule", () => newRule(root)))
			this.appendChild(new OptionsItem("Remove Rule", () => removeRule(root)))
			this.appendChild(new OptionsItem("Apply rules", () => this.appendChild(new ApplicationLog())))
			this.appendChild(new OptionsItem("Lower Priotity", () => lowerPriority(root)))
			this.appendChild(new OptionsItem("Higher Priority", () => higherPriority(root)))
			this.appendChild(new OptionsItem("Rename", () => this.appendChild(new RenameField(root))))
			this.appendChild(new OptionsItem("Export this rule", () => this.appendChild(new ExportField())))
			this.appendChild(new OptionsItem("Export all rules", () => this.appendChild(new ExportField(true))))
			this.appendChild(new OptionsItem("Import a rule", () => this.appendChild(new NewRuleField())))
		}
	}

	class ApplicationLog extends Element {
		render() {
			const elem = document.createElement("div")
			elem.innerHTML = DefaultRules()
			return elem
		}
	}

	class RenameField extends Element {
		constructor(root) {
			super()
			this.element.onfocusout = () => changeName(this.element.value, root)
			this.element.onkeypress = (e) => onreturn(e, () => changeName(this.element.value, root))
		}

		render() {
			const elem = document.createElement("div")
			elem.setAttribute("type", "text")
			elem.setAttribute("value", V.currentRule.name)
		}
	}

	class ExportField extends Element {
		render(all=false) {
			const element = document.createElement("textarea")
			element.value = all ? JSON.stringify(V.currentRule) : map(i => JSON.stringify(i), V.defaultRules).join("\n\n")
			return element
		}
	}

	// parent section for condition editing
	class ConditionEditor extends Element {
		constructor() {
			super()
			this.appendChild(new ConditionFunction())
			this.appendChild(new AssignmentInclusion())
			this.appendChild(new FacilityInclusion())
			this.appendChild(new SpecialExclusion())
			this.appendChild(new SpecificInclusionExclusion())
		}

		render() {
			const element = document.createElement("div")
			return element
		}
	}

	class ConditionFunction extends Element {
		constructor() {
			super()
			this.fnlist = new List("Activation function:")
			this.fneditor = null
			["Never", "Always", "Custom"].forEach(i => this.fnlist.appendChild(i))
			["Devotion", "Trust", "Health", "Sex drive", "Weight", "Age", "Body Age", "Visible Age", "Muscles", "Lactation", "Pregnancy", "Pregnancy Multiples", "Belly Implant", "Belly Size"].forEach(i => this.fnlist.appendChild(i, this.getAttribute(i)))
			this.fnlist.onchange = () => this.fnchanged

			switch(V.currentRule.condition.function) {
				case "Never":
				case "Always":
					break
				case "Custom":
					this.appendChild(new CustomEditor(V.currentRule.condition.data))
					break
				default:
					this.appendChild(new RangeEditor(V.currentRule.condition.function, V.currentRule.condition.data))
					break
			}
		}

		render() {
			return document.createElement("div")
		}

		getAttribute(what) {
			return {
				"Devotion": "devotion",
				"Trust": "trust",
				"Health": "health",
				"Sex drive": "energy",
				"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",
			}[what]
		}

		fnchanged(value) {
			if (this.fneditor !== null) {
				this.fneditor.element.remove()
				this.fneditor = null
			}
			switch(value) {
				case "Never":
					V.currentRule.condition.function = false
					V.currentRule.condition.data = {}
					break
				case "Always":
					V.currentRule.condition.function = true
					V.currentRule.condition.data = {}
					break
				case "Custom":
					V.currentRule.condition.function = "custom"
					V.currentRule.condition.data = {}
					this.appendChild(new CustomEditor(V.currentRule.condition.data))
					break
				default:
					V.currentRule.condition.function = "between"
					V.currentRule.condition.data = { attribute: value, value: [null, null] }
					this.appendChild(new RangeEditor(V.currentRule.condition.data))
					break
			}
		}
	}

	class CustomEditor extends Element {
		constructor(data) {
			if (data.length === 0) data = "function(slave) { return slave.slaveName === 'Fancy Name'; }"
			super(data)
			this.elem.onfocusout = () => V.currentRule.data = this.elem.value
		}

		render(data) {
			const elem = document.createElement("textarea")
			elem.setAttribute(value, data)
			return elem
		}
	}

	class RangeEditor extends Element {
		render(data) {
			const elem = document.createElement("div")

			const min = document.createElement("input")
			min.setAttribute("type", "text")
			min.value = data.between[0]
			min.onkeypress = e => onreturn(e, () => this.setmin(min.value))
			min.onfocusout = e => this.setmin(min.value)
			elem.appendChild(min)

			const max = document.createElement("input")
			max.setAttribute("type", "text")
			max.value = data.between[0]
			max.onkeypress = e => onreturn(e, () => this.setmax(max.value))
			max.onfocusout = e => this.setmax(max.value)
			elem.appendChild(max)

			const infobar = document.createElement("div")
			infobar.innerHTML = this.info(data.attribute)
			elem.appendChild(infobar)

			return elem
		}

		parse(value) {
			value = value.strip()
			if (value === "null") value = null
			else {
				value = parseInt(value)
				if (value === NaN) value = null
			}
			return value
		}

		setmin(value) {
			V.currentRule.data.between[0] = this.parse(value)
		}

		setmax(value) {
			V.currentRule.data.between[1] = this.parse(value)
		}

		info(attribute) {
			return "TODO"
		}
	}

	class AssignmentInclusion extends ButtonList() {
		constructor() {
			super("Apply to assignments")
			["Rest", "Fucktoy", "Subordinate Slave", "House Servant", "Confined", "Whore", "Public Servant", "Classes", "Milked", "Gloryhole"].forEach(
				i => this.appendChild(new ButtonItem(i, this.getAttribute(i), V.currentRule.condition.assignment.includes(i))))
		}

		onchange() {
			V.currentRule.condition.assignment = this.getSelection()
		}

		getAttribute(what) {
			return {
				"Rest": "rest",
				"Fucktoy": "please you",
				"Subordinate Slave": "be a subordinate slave",
				"House Servant": "be a servant",
				"Confined": "stay confined",
				"Whore": "whore",
				"Public Servant": "serve the public",
				"Classes": "take classes",
				"Milked": "get milked",
				"Gloryhole": "work a glory hole",
			}[what]
		}
	}

	class FacilityInclusion extends ButtonList() {
		constructor() {
			super("Apply to assignments")
			const facilities = []
			if (V.HGSuite > 0) facilities.push("Head Girl Suite")
			if (V.brothel > 0) facilities.push("Brothel")
			if (V.club > 0) facilities.push("Club")
			if (V.arcade > 0) facilities.push("Arcade")
			if (V.dairy > 0) facilities.push("Dairy")
			if (V.servantQuarters > 0) facilities.push("Servant Quarters")
			if (V.masterSuite > 0) facilities.push("Master Suite")
			if (V.schoolroom > 0) facilities.push("Schoolroom")
			if (V.spa > 0) facilities.push("Spa")
			if (V.clinic > 0) facilities.push("Clinic")
			if (V.cellblock > 0) facilities.push("Cellblock")
			facilities.forEach(
				i => this.appendChild(new ButtonItem(i, this.getAttribute(i), V.currentRule.condition.facility.includes(i))))
		}

		onchange(value) {
			V.currentRule.condition.facility = this.getSelection()
		}

		getAttribute(what) {
			return {
				"Head Girl Suite": "live with your Head Girl",
				"Brothel": "work in the brothel",
				"Club": "serve in the club",
				"Arcade": "be confined in the arcade",
				"Dairy": "work in the dairy",
				"Servant Quarters": "work as a servant",
				"Master Suite": "serve in the master suite",
				"Schoolroom": "learn in the schoolroom",
				"Spa": "rest in the spa",
				"Clinic": "get treatment in the clinic",
				"Cellblock": "be confined in the cellblock",
			}[what]
		}
	}

	class SpecialExclusion extends List {
		constructor() {
			super("Exclude special slaves:")
			const yes = new ListItem("Yes", "Yes", true)
			const no = new ListItem("No", "No", false)
			this.appendChild(yes)
			this.appendChild(no)
			if (V.currentRule.excludeSpecialSlaves) yes.select()
			this.onchange = (label, value) => V.currentRule.excludeSpecialSlaves = value
		}
	}

	class SpecificInclusionExclusion extends Options {
		constructor() {
			super()
			this.appendChild(new OptionsItem("Limit to specific slaves", () => Engine.display("Rules Slave Select")))
			this.appendChild(new OptionsItem("Exclude specific slaveS", () => Engine.display("Rules Slave Exclude")))
		}
	}

	// parent section for effect editing
	class EffectEditor extends Element {
		constructor() {
			super()
			this.appendChild(new AppearanceSection())
			this.appendChild(new CosmeticSection())
			this.appendChild(new BodyModSection())
			this.appendChild(new AutosurgerySection())
			this.appendChild(new RegimenSection())
			this.appendChild(new BehaviourSection())
		}

		render() {
			const element = document.createElement("div")
			return element
		}
	}

	class AppearanceSection extends Element {
		constructor() {
			super()
			this.appendChild(new ClothesList())
			this.appendChild(new CollarList())
			this.appendChild(new ShoeList())
			this.appendChild(new CorsetList())
			this.appendChild(new VagAccVirginsList())
			this.appendChild(new VagAccAVirginsList())
			this.appendChild(new VagAccOtherList())
			if (V.seeDicks !== 0 || V.makeDicks !== 0) {
				this.appendChild(new DickAccVirginsList())
				this.appendChild(new DickAccOtherList())
			}
			this.appendChild(new ButtplugsVirginsList())
			this.appendChild(new ButtplugsOtherList())
			this.appendChild(new ImplantVolumeList())
			this.appendChild(new AutosurgerySwitch())

		}

		render() {
			return document.createElement("div")
		}
	}

	class RegimenSection extends Element {
		constructor() {
			super()
			this.appendChild(new GrowthList())
			this.appendChild(new CurrativesList())
			this.appendChild(new AphrodisiacList())
			this.appendChild(new ContraceptiveList())
			if (V.pregSpeedControl)
				this.appendChild(new PregDrugsList())
			this.appendChild(new FemaleHormonesList())
			this.appendChild(new ShemaleHormonesList())
			this.appendChild(new GeldingHormonesList())
			this.appendChild(new OtherDrugsList())
			this.appendChild(new DietList())
			this.appendChild(new DietGrowthList())
			this.appendChild(new DietBaseList())
			this.appendChild(new MuscleList())
			this.appendChild(new BraceList())
		}

		render() {
			return document.createElement("div")
		}
	}

	class BehaviourSection extends List {
		constructor() {
			super()
			this.appendChild(new LivingStandardList())
			this.appendChild(new PunishmentList())
			this.appendChild(new RewardList())
			this.appendChild(new ReleaseList())
			this.appendChild(new SmartFetishList())
			this.appendChild(new SmartXYAttractionList())
			this.appendChild(new SmartXXAttractionList())
			this.appendChild(new SmartEnergyList())
			this.appendChild(new SpeechList())
			this.appendChild(new RelationshipList())
			if (V.studio === 1)
				this.appendChild(new PornList())
		}

		render() {
			return document.createElement("div")
		}
	}

	class ClothesList extends List {
		constructor() {
			super("Clothes")
			this.appendChild(new ListItem("Select her own outfit", "choosing her own clothes"))

			const nice = new ListSubSection()
			this.appendChild(nice)

			const nclothes = [
				["No default clothes setting", "no default setting"],
				["Bangles", "slutty jewelry"],
				["Bodysuit", "a comfortable bodysuit"],
				["Cheerleader outfit", "a cheerleader outfit"],
				["Clubslut netting", "clubslut netting"],
				["Cutoffs and a t-shirt", "cutoffs and a t-shirt"],
				["Fallen nun", "a fallen nuns habit"],
				["Halter top", "a halter top dress"],
				["Hijab and abaya", "a hijab and abaya"],
				["Latex catsuit", "a latex catsuit"],
				["Leotard", "a leotard"],
				["Maid (nice)", "a nice maid outfit"],
				["Maid (slutty)", "a slutty maid outfit"],
				["Military uniform", "a military uniform"],
				["Mini dress", "a mini dress"],
				["Nice lingerie", "attractive lingerie"],
				["Nurse (nice)", "a nice nurse outfit"],
				["Schoolgirl", "a schoolgirl outfit"],
				["Silken ballgown", "a ball gown"],
				["Skimpy battledress", "battledress"],
				["Slave gown", "a slave gown"],
				["Slutty outfit", "a slutty outfit"],
				["String bikini", "a stirng bikini"],
				["Scalemail bikini", "a scalemail bikini"],
				["Succubus costume", "a succubus outfit"],
				["Suit (nice)", "nice business sattire"],
				["Suit (slutty", "slutty business attire"],
				["Spats and tank top", "spats and a tank top"]
			]
			const fsnclothes = [
				["Body oil (FS)", "body oil"],
				["Bunny outfit (FS)", "a bunny outfit"],
				["Chattel habit (FS)", "a chattel habit"],
				["Conservative clothing (FS)", "conservative clothing"],
				["Harem gauze (FS)", "harem gauze"],
				["Huipil (FS)", "a huipil"],
				["Kimono (FS)", "a kimono"],
				["Maternity dress (FS)", "a maternity dress"],
				["Maternity lingerie (FS)", "attractive lingerie for a pregnant woman"],
				["Slutty qipao (FS)", "a slutty qipao"],
				["Stretch pants and a crop-top (FS)", "stretch pants and a crop-top"],
				["Toga (FS)", "a toga"],
				["Western clothing (FS)", "Western clothing"],
			]
			nclothes.forEach(pair => nice.appendChild(new ListItem(...pair)))
			fsnclothes.forEach(pair => { if (isItemAccessible(pair[1])) nice.appendChild(new ListItem(...pair))})

			harsh = new ListSubSection()
			this.appendChild(harsh)

			const hclothes = [
				["Nude", "no clothing"]
				["Penitent nun", "a penitent nuns habit"],
				["Restrictive latex", "restrictive latex"],
				["Shibari ropes", "shibari ropes"],
				["Uncomfortable straps", "uncomfortable straps"]
			]
			const fshclothes = [
				["Chains (FS)", "chains"],
			]

			hclothes.forEach(pair => nice.appendChild(new ListItem(...pair)))
			fshclothes.forEach(pair => { if (isItemAccessible(pair[1])) nice.appendChild(new ListItem(...pair))})

			this.selectValue(V.currentRule.set.clothes)
			this.onchange = (label, value) => V.currentRule.set.clothes = value
		}
	}

	class CollarList extends List {
		constructor() {
			super("Collar")
			this.appendChild("No default collar setting", "no default setting")
			this.appendChild("No collar", "none")

			const nice = new ListSubSection("Nice")
			this.appendChild(nice)

			const ncollars = [
				["Stylish leather", "stylish leather"],
				["Satin choker", "satin choker"],
				["Silken Ribbon", "silk ribbon"],
				["Heavy Gold", "heavy gold"],
				["Pretty jewelry", "pretty jewelry"],
				["Cowbell", "leather with cowbell"]
			]
			if (V.seeAge !== 0)
				ncollars.push(["Nice retirement counter", "nice retirement counter"])
			const fsncollars = [
				["Bowtie collar", "bowtie"],
				["ancient Egyptian", "ancient Egyptian"],
			]
			ncollars.forEach(pair => nice.appendChild(new ListItem(...pair)))
			fsncollars.forEach(pair => { if (isItemAccessible(pair[1])) nice.appendChild(new ListItem(...pair))})

			const harsh = new ListSubSection("Harsh")
			this.appendChild(harsh)

			const hcollars = [
				["Tight steel", "tight steel"],
				["Uncomfortable leather", "uncomfortable leather"],
				["Pregnancy biometrics", "preg biometrics"],
				["Shock punishment", "shock punishment"],
				["Dildo gag", "dildo gag"],
				["Ball gag", "ball gag"],
				["Bit gag", "bit gag"],
				["Neck corset", "neck corset"],
			]
			if (V.seeAge !== 0)
				harsh.appendChild(["Cruel retirement counter", "cruel retirement counter"])
			if (V.toysBoughtGags === 1)
				harsh.appendChild(["Massive dildo gag", "massive dildo gag"])
			hcollars.forEach(pair => harsh.appendChild(...pair))

			this.selectValue(V.currentRule.set.collar)
			this.onchange = (label, value) => V.currentRule.set.collar = value
		}
	}

	class ShoeList extends List {
		constructor() {
			super("Shoes")
			setup.shoes.forEach(shoes => this.appendChild(new ListItem(shoes)))
			this.selectValue(V.currentRule.set.shoes)
			this.onchange = (label, value) => V.currentRule.set.shoes = value
		}
	}

	class CorsetList extends List {
		constructor() {
			super("Corsetage")
			const bellies = []
			setup.bellyAccessories.forEach(acc => {
				if (acc.fs === undefined && acc.rs === undefined)
					bellies.push([acc.name, acc.value])
				else if (acc.fs === "repopulation" && V.arcologies[0].FSRepopulationFocus !== "unset")
					bellies.push([acc.name + " (FS)", acc.value])
				else if (acc.rs === "boughtBelly" && V.clothesBoughtBelly === 1)
					bellies.push([acc.name + " (Purchased)", acc.value])
			})
			bellies.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.bellyAccessory)
			this.onchange = (label, value) => V.currentRule.set.bellyAccessory
		}
	}

	class VagAccVirginsList extends List {
		constructor() {
			super("Vaginal accessories for virgins")
			const accs = []
			setup.vaginalAccessories.forEach(acc => {
				if (acc.fs === undefined && acc.rs === undefined)
					accs.push([acc.name, acc.value])
				else if (acc.rs === "buyBigDildos" && V.toysBoughtDildos === 1)
					accs.push([acc.name + " (Purchased)", acc.value])
			})
			accs.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.virginAccessory)
			this.onchange = (label, value) => V.currentRule.set.virginAccessory = value
		}
	}

	class VagAccAVirginsList extends List {
		constructor() {
			super("Vaginal accessories for anal virgins")
			const accs = []
			setup.vaginalAccessories.forEach(acc => {
				if (acc.fs === undefined && acc.rs === undefined)
					accs.push([acc.name, acc.value])
				else if (acc.rs === "buyBigDildos" && V.toysBoughtDildos === 1)
					accs.push([acc.name + " (Purchased)", acc.value])
			})
			accs.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.aVirginAccessory)
			this.onchange = (label, value) => V.currentRule.set.aVirginAccessory = value
		}
	}

	class VagAccOtherList extends List {
		constructor() {
			super("Vaginal accessories for other slaves")
			const accs = []
			setup.vaginalAccessories.forEach(acc => {
				if (acc.fs === undefined && acc.rs === undefined)
					accs.push([acc.name, acc.value])
				else if (acc.rs === "buyBigDildos" && V.toysBoughtDildos === 1)
					accs.push([acc.name + " (Purchased)", acc.value])
			})
			accs.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.vaginalAccessory)
			this.onchange = (label, value) => V.currentRule.set.vaginalAccessory = value
		}
	}

	class DickAccVirginsList extends List {
		constructor() {
			super("Dick accessories for anal virgins")
			setup.dickAccessories.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.aVirginDickAccessory)
			this.onchange = (label, value) => V.currentRule.set.aVirginDickAccessory = value
		}
	}

	class DickAccOtherList extends List {
		constructor() {
			super("Dick accessories for other slaves")
			setup.dickAccessories.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.dickAccessory)
			this.onchange = (label, value) => V.currentRule.set.dickAccessory = value
		}
	}

	class ButtplugsVirginsList extends List {
		constructor() {
			super("Buttplugs for anal virgins")
			const accs = []
			setup.buttplugs.forEach(acc => {
				if (acc.fs === undefined && acc.rs === undefined)
					accs.push([acc.name, acc.value])
				else if (acc.rs === "buyBigPlugs" && V.toysBoughtButtPlugs === 1)
					accs.push([acc.name + " (Purchased)", acc.value])
			})
			accs.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.aVirginButtplug)
			this.onchange = (label, value) => V.currentRule.set.aVirginButtplug = value
		}
	}

	class ButtplugsOtherList extends List {
		constructor() {
			super("Buttplugs for other slaves")
			const accs = []
			setup.buttplugs.forEach(acc => {
				if (acc.fs === undefined && acc.rs === undefined)
					accs.push([acc.name, acc.value])
				else if (acc.rs === "buyBigPlugs" && V.toysBoughtButtPlugs === 1)
					accs.push([acc.name + " (Purchased)", acc.value])
			})
			accs.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.buttplug)
			this.onchange = (label, value) => V.currentRule.set.buttplug = value
		}
	}

	class ImplantVolumeList extends List {
		constructor() {
			super("Belly implant target volume (if present)")
			const pairs = [
				["No changes", -1],
				["Empty implant", 0],
				["Early pregnancy", 1500],
				["Second trimester pregnancy", 5000],
				["Full-term pregnancy", 15000],
				["Full-term with twins", 30000],
				["Full-term with triplets", 45000],
				["Full-term with quadruplets", 60000],
				["Full-term with quintuplets", 75000],
				["Full-term with sextuplets", 90000],
				["Full-term with septuplets", 105000],
				["Full-term with octuplets", 120000]
			]
			pairs.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.bellyImplantVol)
			this.onchange = (label, value) => V.currentRule.set.bellyImplantVol = value
		}
	}

	class AutosurgerySwitch extends List {
		constructor() {
			super("Assistant-applied implants (Autosurgery global switch)")
			this.appendChild(new ListItem("Activate", "ACTIVE, STAND CLEAR", 1))
			this.appendChild(new ListItem("Off", "off", 0))
			this.selectValue(V.currentRule.set.autoSurgery)
			this.onchange = (label, value) => V.currentRule.set.autoSurgery = value
		}
	}

	class GrowthList extends Options {
		constructor() {
			super()
			this.sublists = []
			const pairs = [
				["No default setting", () => this.nds()],
				["Girlish figure", () => this.girlish()],
				["Stacked figure", () => this.stacked()],
				["Huge but functional", () => this.huge()],
				["Unlimited", () => this.unlimited()],
				["None", () => this.none()]
			]
			pairs.forEach(pair => this.appendChild(new OptionsItem(...pair)))

			this.breasts = new BreastGrowthList()
			this.butts = new ButtGrowthList()
			this.lips = new LipGrowthList()
			this.sublists.push(this.breasts, this.butts, this.lips)

			if (V.seeDicks > 0 || V.makeDicks > 0) {
				this.dicks = new DickGrowthList()
				this.balls = new BallGrowthList()
				this.sublists.push(this.dicks, this.balls)
			}

			this.sublists.forEach(i => this.appendChild(i))
		}

		render() {
			const elem = document.createElement("div")
			const span = document.createElement("span")
			span.innerHTML = "Growth hormone regimes for healthy slaves:"
			elem.appendChild(span)
			return elem
		}

		nds() {
			[this.breasts, this.butts, this.lips, this.dicks, this.balls].forEach(i => {
				i.setValue("no default change")
				i.propagateChange()
			})
		}

		girlish() {
			this.breasts.setValue(350)
			this.butts.setValue(2)
			this.lips.setValue(25)
			if (this.dicks) this.dicks.setValue(0)
			if (this.balls) this.balls.setValue(0)
			this.sublists.forEach(i => i.propagateChange())
		}

		stacked() {
			this.breasts.setValue(1000)
			this.butts.setValue(4)
			this.lips.setValue(25)
			if (this.dicks) this.dicks.setValue(4)
			if (this.balls) this.balls.setValue(4)
			this.sublists.forEach(i => i.propagateChange())
		}

		huge() {
			this.breasts.setValue(9000)
			this.butts.setValue(10)
			this.lips.setValue(45)
			if (this.dicks) this.dicks.setValue(6)
			if (this.balls) this.balls.setValue(6)
			this.sublists.forEach(i => i.propagateChange())
		}

		unlimited() {
			this.breasts.setValue(48000)
			this.butts.setValue(10)
			this.lips.setValue(100)
			if (this.dicks) this.dicks.setValue(10)
			if (this.balls) this.balls.setValue(6)
			this.sublists.forEach(i => i.propagateChange())
		}

		none() {
			this.sublists.forEach(i => {
				i.setValue(0)
				i.propagateChange()
			})
		}
	}

	class BreastGrowthList extends List {
		constructor() {
			super("Breasts", true)
			[
				["No default setting", "no default setting"],
				["B Cup", 350],
				["D Cup", 1000],
				["Monstrous", 9000],
				["Unlimited", 48000],
				["None", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.setValue(V.currentRule.set.growth_boobs)
			this.onchange = (label, value) => V.currentRule.set.growth_boobs = value
		}
	}

	class ButtGrowthList extends List {
		constructor() {
			super("Butts", true)
			[
				["No default setting", "no default setting"],
				["Cute", 2],
				["Big", 4],
				["Huge", 6],
				["Unlimited", 10],
				["None", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.setValue(V.currentRule.set.growth_butt)
			this.onchange = (label, value) => V.currentRule.set.growth_butt = value
		}
	}

	class LipGrowthList extends List {
		constructor() {
			super("Lips", true)
			[
				["No default setting", "no default setting"],
				["Plump", 25],
				["Beestung", 45],
				["Facepussy", 100],
				["None", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.setValue(V.currentRule.set.growth_lips)
			this.onchange = (label, value) => V.currentRule.set.growth_lips = value
		}
	}

	class DickGrowthList extends List {
		constructor() {
			super("Dicks, if present", true)
			[
				["No default setting", "no default setting"],
				["Above average", 4],
				["Pornstar", 6],
				["Unlimited", 10],
				["None", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.setValue(V.currentRule.set.growth_dick)
			this.onchange = (label, value) => V.currentRule.set.growth_dick = value
		}
	}

	class BallGrowthList extends List {
		constructor() {
			super("Balls, if present", true)
			[
				["No default setting", "no default setting"],
				["Sizeable", 4],
				["Cumslave", 6],
				["Unlimited", 10],
				["None", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.setValue(V.currentRule.set.growth_balls)
			this.onchange = (label, value) => V.currentRule.set.growth_balls = value
		}
	}

	class CurrativesList extends List {
		constructor() {
			super("Health drugs")
			[
				["No default setting", "no default setting"],
				["None", "none", 0],
				["Preventatives", "preventatives", 1],
				["Curatives", "curatives", 2]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.curatives)
			this.onchange = (label, value) => V.currentRule.set.curatives = value
		}
	}

	class AphrodisiacList extends List {
		constructor() {
			super("Aphrodisiacs")
			[
				["No default setting", "no default setting"],
				["None", "none", 0],
				["Standard", "standard", 1],
				["Extreme", "extreme", 2],
				["Anaphrodisiacs", "anaphrodisiacs", -1]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.aphrodisiacs)
			this.onchange = (label, value) => V.currentRule.set.aphrodisiacs = value
		}
	}

	class ContraceptiveList extends List {
		constructor() {
			super("Contraceptives for fertile slaves")
			const drugs =  [
				["No default setting", "no default setting"],
				["Contraceptives", "contraceptives", -1]
				["Fertile", "fertile", 0],
				["Very fertile", "very fertile", 1],
				["Extremely fertile", "extremely fertile", 2],
			]
			if (V.seeHyperPreg === 1 && V.superFertilityDrugs === 1) {
				drugs.push(["Hyper fertile", "hyper fertile", 3])
				drugs.push(["Maximize fertility", "maximize fertility", 4])
			}
			drugs.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.preg)
			this.onchange = (label, value) => V.currentRule.set.preg = value
		}
	}

	class PregDrugsList extends List {
		constructor() {
			super("Pregnancy control agents for pregnant slaves")
			[
				["No changes", "no changes", "no default setting"],
				["None", "none"],
				["Fast gestation", "fast gestation", "fast"],
				["Slow gestation", "slow gestation", "slow"],
				["Birth supressors", "birth supressors", "suppress"],
				["Birth stimulators", "birth stimulators", "stimulate"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.pregSpeed)
			this.onchange = (label, value) => V.currentRule.set.pregSpeed = value
		}
	}

	class FemaleHormonesList extends List {
		constructor() {
			super("Hormones for female slaves")
			[
				["No default setting", "no default setting"],
				["Intensive Female", "intensive female", 2],
				["Female", "female", 1],
				["None", "none", 0],
				["Male", "male", -1],
				["Intensive Male", "intensive male", -2]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.XX)
			this.onchange = (label, value) => V.currentRule.set.XX = value
		}
	}

	class GeldingHormonesList extends List {
		constructor() {
			super("Hormones for geldings")
			[
				["No default setting", "no default setting"],
				["Intensive Female", "intensive female", 2],
				["Female", "female", 1],
				["None", "none", 0],
				["Male", "male", -1],
				["Intensive Male", "intensive male", -2]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.gelding)
			this.onchange = (label, value) => V.currentRule.set.gelding = value
		}
	}

	class ShemaleHormonesList extends List {
		constructor() {
			super("Hormones for shemales")
			[
				["No default setting", "no default setting"],
				["Intensive Female", "intensive female", 2],
				["Female", "female", 1],
				["None", "none", 0],
				["Male", "male", -1],
				["Intensive Male", "intensive male", -2]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.XY)
			this.onchange = (label, value) => V.currentRule.set.XY = value
		}
	}

	class OtherDrugsList extends List {
		constructor() {
			super("Other drugs (Will be overriden by hormones and other drugs where applicable)")
			const drugs = []
			setup.drugs.forEach(drug => {
				if (drug.fs === undefined && drug.rs === undefined)
					drugs.push([drug.name, drug.value])
				else if (drug.rs === "growth" && V.growthStim === 1)
					drugs.push([drug.name + " (Research)", drug.value])
				else if (drug.rs === "pubHorm" && V.precociousPuberty === 1 && V.pubertyHormones === 1)
					drugs.push([drug.name + " (Research)", drug.value])
				else if (drug.rs === "nosag" && V.purchasedSagBGone === 1)
					drugs.push([drug.name + " (Product)", drug.value])
				else if (drug.fs === "slimness" && V.arcologies[0].FSSlimnessEnthusiastResearch === 1)
					drugs.push([drug.name + " (FS)", drug.value])
				else if (drug.fs === "youth" && V.arcologies[0].FSYouthPreferentialistResearch === 1)
					drugs.push([drug.name + " (FS)", drug.value])
			})
			this.selectValue(V.currentRule.set.drug)
			this.onchange = (label, value) => V.currentRule.set.drug = value
		}
	}

	class DietList extends List {
		constructor() {
			super("Slave diets")
			const diets = [
				["no default setting", "no default setting"],
				["Fix fat and skinny slaves", "fix fat and skinny slaves", "attractive"],
				["Curvy", "curvy", 30],
				["Average", "average", 0],
				["Thin", "thin", -30]
			]
			if (V.feeder === 1) {
				diets.push(
					["Feminine", "feminine", "XX"],
					["Masculine", "masculine", "XY"]
				)
				if (V.dietXXY === 1)
					diets.push(["Futanari", "futanari", "XXY"])
			}
			if (V.dietCleanse === 1)
				diets.push(["Cleansing", "promote health", "cleansing"])
			if (V.dietFertility === 1)
				diets.push(["Feritlity", "promote fertility", "fertility"])
			if (V.cumProDiet === 1)
				diets.push(["Cum production", "promote cum production", "cum production"])
			diets.forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.diet)
			this.onchange = (label, value) => V.currentRule.set.diet = value
		}
	}

	class DietGrowthList extends List {
		constructor() {
			super("Diet support for growth drugs")
			[
				["On", "On", 1],
				["Off", "Off", 0]
			].forEach(i => this.appendChild(new ListItem(...i)))
			this.selectValue(V.currentRule.set.dietGrowthSupport)
			this.onchange = (label, value) => V.currentRule.set.dietGrowthSupport = value
		}
	}

	class DietBaseList extends List {
		constructor() {
			super("Diet base")
			// TODO: better data structure?
			[
				["No default setting", "No default setting", {cum: "no default setting", milk: "no default setting"}],
				["Normal Diet", "Normal Diet", {cum: 0, milk: 0}],
				["Cum Added", "Cum Added", {cum: 1, milk: 0}],
				["Milk Added", "Milk Added", {cum: 0, milk: 1}],
				["Cum &amp; Milk Added", "Cum &amp; Milk Added", {cum: 1, milk: 1}],
				["Cum-Based", "Cum-Based", {cum: 2, milk: 0}]
				["Milk-Based", "Milk-Based", {cum: 0, milk: 2}]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue({cum: V.currentRule.set.dietCum, milk: V.currentRule.set.dietMilk})
			this.onchange = (label, value) => {
				V.currentRule.set.dietCum = value.cum
				V.currentRule.set.dietMilk = value.milk
			}
		}
	}

	class MuscleList extends List {
		constructor() {
			super("Muscles", true)
			[
				["No default setting", "no default setting"],
				["None", "None", 0],
				["Toned", "Toned", 20],
				["Ripped", "Ripped", 50],
				["Massive", "Massive", 100],
				["Weak", "Weak", -20]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.setValue(V.currentRule.set.muscles)
			this.onchange = (label, value) => V.currentRule.set.muscles = value
		}
	}

	class BraceList extends List {
		constructor() {
			super("Braces")
			[
				["No default setting", "no default setting"],
				["None", "none"],
				["Straighten", "straighten"],
				["Universal", "universal"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.teeth)
			this.onchange = (label, value) => V.currentRule.set.teeth = value
		}
	}

	class LivingStandardList extends List {
		constructor() {
			super("Living standard")
			[
				["No default setting", "no default setting"],
				["Luxurious", "luxurious"],
				["Normal", "normal"],
				["Spare", "spare"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.livingRules)
			this.onchange = (label, value) => V.currentRule.set.livingRules = value
		}
	}

	class PunishmentList extends List {
		constructor() {
			super("Typical punishment")
			[
				["No default setting", "no default setting"],
				["Confinement", "confinement"],
				["Whipping", "whipping"],
				["Chastity", "chastity"],
				["Situational", "situational"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.standardPunishment)
			this.onchange = (label, value) => V.currentRule.set.standardPunishment = value
		}
	}

	class RewardList extends List {
		constructor() {
			super("Typical reward")
			[
				["No default setting", "no default setting"],
				["Relaxation", "relaxation"],
				["Drugs", "drugs"],
				["Orgasm", "orgasm"],
				["Situational", "situational"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.standardReward)
			this.onchange = (label, value) => V.currentRule.set.standardReward = value
		}
	}

	class ReleaseList extends List {
		constructor() {
			super("Release rules")
			[
				["No default setting", "no default setting"],
				["Permissive", "permissive"],
				["Sapphic", "sapphic"],
				["Masturbation", "masturbation"],
				["Restritive", "restrictive"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.releaseRules)
			this.onchange = (label, value) => V.currentRule.set.releaseRules = value
		}
	}

	class SmartFetishList extends List {
		constructor() {
			super("Smart piercing fetish target")
			[
				["No default setting", "no default setting"],
				["Vanilla", "vanilla"],
				["Oral", "oral"],
				["Anal", "anal"],
				["Boobs", "boobs"],
				["Sub", "submissive"],
				["Dom", "dom"],
				["Humiliation", "humiliation"],
				["Preg", "pregnancy"],
				["Pain", "masochist"],
				["Sadism", "sadist"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.clitSetting)
			this.onchange = (label, value) => V.currentRule.set.clitSetting	= value
		}
	}

	class SmartXYAttractionList extends List {
		constructor() {
			super("Smart piercing XY attraction target")
			[
				["No default setting", "no default setting"],
				["Passionate", "passionate", 100],
				["Attracted", "attracted", 75],
				["Indifferent", "indifferent", 45],
				["None", "none", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.clitSettingXY)
			this.onchange = (label, value) => V.currentRule.set.clitSettingXY = value
		}
	}

	class SmartXXAttractionList extends List {
		constructor() {
			super("Smart piercing XX attraction target")
			[
				["No default setting", "no default setting"],
				["Passionate", "passionate", 100],
				["Attracted", "attracted", 75],
				["Indifferent", "indifferent", 45],
				["None", "none", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.clitSettingXX)
			this.onchange = (label, value) => V.currentRule.set.clitSettingXX = value
		}
	}

	class SmartEnergyList extends List {
		constructor() {
			super("Smart piercing sex drive target")
			[
				["Nympho", "nympho", 100],
				["Sex Addict", "sex addict", 85],
				["Powerful", "powerful", 65],
				["Healthy", "healthy", 45],
				["Weak", "weak", 25],
				["Frigid", "frigid", 0]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.clitSettingEnergy)
			this.onchange = (label, value) => V.currentRule.set.clitSettingEnergy = value
		}
	}

	class SpeechList extends List {
		constructor() {
			super("Speech rules")
			[
				["No default setting", "no default setting"],
				["Permissive", "permissive"],
				["Suppress accents", "accent elimination"],
				["Restrictive", "restrictive"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set)
			this.onchange = (label,value) => V.currentRule.set = value
		}
	}

	class RelationshipList extends List {
		constructor() {
			super("Relationship rules")
			[
				["No default setting", "no default setting"],
				["Permissive", "permissive"],
				["Just friends", "just friends"],
				["Restrictive", "restrictive"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set)
			this.onchange = (label,value) => V.currentRule.set = value
		}
	}

	class PornList extends List {
		constructor() {
			super("Weekly porn publicity subsidy")
			[
				["No default setting", "no default setting"],
				["No broadcasting", "no broadcasting", -1],
				["No subsidy", "no subsidy", 0],
				["1000", "1000", 1000],
				["2000", "2000", 2000],
				["3000", "3000", 3000],
				["4000", "4000", 4000],
				["5000", "5000", 5000]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.pornFameSpending)
			this.onchange = (label,value) => V.currentRule.set.pornFameSpending = value
		}
	}

	class CosmeticSection extends List {
		constructor() {
			this.appendChild(EyewearList)
			this.appendChild(LensesList)
			this.appendChild(MakeupList)
			this.appendChild(NailsList)
			this.appendChild(HairLengthList)
			this.appendChild(HairColourList)
			this.appendChild(HairStyleList)
			this.appendChild(PubicHairColourList)
			this.appendChild(PubicHairStyleList)
			this.appendChild(ArmpitHairColourList)
			this.appendChild(ArmpitHairStyleList)
		}
	}

	class EyewearList extends List {
		constructor() {
			super("Eyewear")
			[
				["no default setting"],
				["correct with contacts"],
				["universal glasses"],
				["blur with glasses"],
				["blur with contacts"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.eyewear)
			this.onchange = (label, value) => V.currentRule.set.eyewear = value
		}
	}

	class LensesList extends Element {
		constructor() {
			super(V.currentRule.set.eyeColor)
			this.appendChild(new OptionsItem("No default Setting", () => this.setValue("no default setting")))
			this.colourlist = new LensesColourList()
			this.shapelist = new LensesShapeList()
			this.appendChild(this.colourlist)
			this.appendChild(this.shapelist)
		}

		render(color) {
			const elem = document.createElement("div")
			elem.innerHTML = "Eye coloring: "
			this.label = document.createElement("strong")
			this.label.innerText = coloring
			elem.appendChild(this.label)
		}

		combine() {
			const lst = []
			if (this.colourlist.value !== "no default setting")
				lst.appendChild(this.colourlist.value)
			if (this.shapelist.value !== "no default setting")
				list.appendChild(this.shapelist.value)
			if (lst.length === 0) return "no default value"
			else return lst.join(" ")
		}

		set_value() {
			const tmp = this.combine()
			this.label.innerText = tmp
			V.currentRule.set.eyeColor = tmp
		}
	}

	class LensesColourList extends Options {
		constructor() {
			super("Color:")
			[
				["no default setting"]
				["blue"],
				["black"],
				["brown"],
				["green"],
				["turquoise"],
				["sky-blue"],
				["hazel"],
				["pale-grey"],
				["white"],
				["pink"],
				["amber"],
				["red"]
			].forEach(i => this.appendChild(new OptionsItem(i, item => {
				this.value = item.label
				this.parent.set_value()
			})))
		}
	}

	class LensesShapeList extends Options {
		constructor() {
			super("Shape:")
			[
				["no default setting"],
				["catlike"],
				["serpent-like"],
				["devilish"],
				["demonic"],
				["hypnotic"],
				["heart-shaped"],
				["wide-eyed"],
				["almond-shaped"],
				["bright"],
				["teary"],
				["vacant"]
			].forEach(i => this.appendChild(new OptionsItem(i, item => {
				this.value = item.label
				this.parent.set_value()
			})))
		}
	}

	class MakeupList extends List {
		constructor() {
			super("Makeup")
			[
				["no default setting"],
				["makeup-free", "makeup-free", 0],
				["nice", "nice", 1],
				["gorgeous", "gorgeous", 2],
				["color-coordinate with hair", "color-coordinate with hair", 3],
				["slutty", "slutty", 4]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.makeup)
			this.onchange = (label, value) => V.currentRule.set.makeup = value
		}
	}

	class NailsList extends List {
		constructor() {
			super("Nails")
			[
				["no default setting"],
				["clipped", "clipped", 0],
				["extended", "extended", 1],
				["color-coordinate with hair", "color-coordinate with hair", 2],
				["sharp and claw-like", "sharp and claw-like", 3],
				["bright and glittery", "bright and glittery", 4],
				["hooker nails", "hooker nails", 5]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.nails)
			this.onchange = (label, value) => V.currentRule.set.nails = value
		}
	}

	class HairLengthList extends List {
		constructor() {
			super("Hair length")
			[
				["no default setting"],
				["very short", "very short", 5],
				["short", "short", 10],
				["shoulder length", "shoulder length", 30],
				["long", "long", 60],
				["very long", "very long", 100],
				["floor length", "floor length", 150]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.hLength)
			this.onchange = (label, value) => V.currentRule.set.hLength = value
		}
	}
	class HairColourList extends List {
		constructor() {
			super("Hair color")
			[
				["no default setting"],
				["blonde"],
				["golden"],
				["platinum blonde"],
				["strawbery-blonde"],
				["copper"],
				["ginger"],
				["red"]
				["green"],
				["blue"],
				["pink"],
				["dark brown"],
				["brown"],
				["auburn"],
				["burgundy"],
				["chocolate"],
				["chestnut"],
				["hazel"],
				["black"],
				["grey"],
				["silver"],
				["white"],
				["blazing red"],
				["neon green"],
				["neon blue"],
				["neon pink"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.hColor)
			this.onchange = (label, value) => V.currentRule.set.hColor = value
		}
	}

	class HairStyleList extends List {
		constructor() {
			super("Hair style")
			[
				["no default setting"],
				["neat"],
				["shaved"],
				["trimmed"],
				["buzzcut"],
				["up"],
				["ponytail"],
				["bun"],
				["curled"],
				["permed"],
				["luxurious"],
				["dreadlocks"],
				["cornrows"],
				["braided"],
				["tails"],
				["afro"],
				["strip"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.hStyle)
			this.onchange = (label, value) => V.currentRule.set.hStyle = value
		}
	}

	class PubicHairColourList extends List {
		constructor() {
			super("Pubic hair color, when present")
			[
				["no default setting"],
				["blonde"],
				["golden"],
				["platinum blonde"],
				["strawerry-blonde"],
				["copper"],
				["ginger"],
				["red"],
				["green"],
				["blue"],
				["pink"],
				["dark brown"],
				["brown"],
				["auburn"],
				["burgundy"],
				["chocolate"],
				["chestnut"],
				["hazel"],
				["black"],
				["grey"],
				["silver"],
				["white"],
				["blazing red"],
				["neon green"],
				["neon blue"],
				["neon pink"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.pubicHColor)
			this.onchange = (label, value) => V.currentRule.set.pubicHColor = value
		}
	}

	class PubicHairStyleList extends List {
		constructor() {
			super("Pubic hairstyle")
			[
				["no default setting"],
				["waxed"],
				["in a strip"],
				["neat"],
				["bushy"],
				["bushy in the front and neat in the rear"],
				["very bushy"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.pubicHStyle)
			this.onchange = (label, value) => V.currentRule.set.pubicHStyle = value
		}
	}

	class ArmpitHairColourList extends List {
		constructor() {
			super("Underarm hair color, when present")
			[
				["no default setting"],
				["blonde"],
				["golden"],
				["platinum blonde"],
				["strawberry-blonde"],
				["copper"],
				["ginger"],
				["red"],
				["green"],
				["blue"],
				["pink"],
				["dark brown"],
				["brown"],
				["auburn"],
				["burgundry"],
				["chocolate"],
				["chestnut"],
				["hazel"],
				["black"],
				["grey"],
				["silver"],
				["white"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.underArmHColor)
			this.onchange = (label, value) => V.currentRule.set.underArmHColor = value
		}
	}

	class ArmpitHairStyleList extends List {
		constructor() {
			super("Underarm hair style")
			[
				["no default setting"],
				["waxed"],
				["shaved"],
				["neat"],
				["bushy"]
			].forEach(pair => this.appendChild(new ListItem(...pair)))
			this.selectValue(V.currentRule.set.underArmHStyle)
			this.onchange = (label, value) => V.currentRule.set.underArmHStyle = value
		}
	}
})()