module CharacterCreation { interface rangeOptions { label? : string; showValue? : boolean; onChange : (value : number, labelValue : Text, input : HTMLInputElement) => void; minValue : number; maxValue : number; leftLabel? : string; rightLabel? : string; topLabel? : string; value : number; step : number; } function createRange (options : rangeOptions) { let valueNode = document.createTextNode(String(options.value)); let div = document.createElement("div"); div.classList.add("ccOption"); if (options.topLabel != undefined) { let topLabel = document.createElement("div"); topLabel.classList.add("ccOptionTopLabel"); topLabel.appendChild(document.createTextNode(options.topLabel + ":")); div.appendChild(topLabel); } let label = document.createElement("div"); if (options.showValue != false) { label.classList.add("rangeValue"); if (options.label != undefined) { let b = document.createElement("b"); b.appendChild(document.createTextNode(options.label + ": ")); label.appendChild(b); } label.appendChild(valueNode); } let input = document.createElement("input"); input.classList.add("ccRange"); input.type = "range"; input.min = options.minValue.toString(); input.max = options.maxValue.toString(); input.step = options.step.toString(); input.value = options.value.toString(); let onChange = () => { valueNode.nodeValue = input.value; options.onChange(Number(input.value), valueNode, input); } input.addEventListener("change", onChange); let leftButton = document.createElement("a"); leftButton.classList.add("ccButton"); leftButton.addEventListener("click", () => { input.value = String(Number(input.value) - options.step); onChange(); }); Controls.KeyHandler.applyCode(leftButton, Controls.KeyHandler.getFirstKeyCode()); if (options.leftLabel != undefined) { leftButton.appendChild(document.createTextNode(options.leftLabel)); } let rightButton = document.createElement("a"); rightButton.classList.add("ccButton"); rightButton.addEventListener("click", () => { input.value = String(Number(input.value) + options.step); onChange(); }); Controls.KeyHandler.applyCode(rightButton, Controls.KeyHandler.getFirstKeyCode());; if (options.rightLabel != undefined) { rightButton.appendChild(document.createTextNode(options.rightLabel)); } div.appendChild(leftButton); div.appendChild(input); div.appendChild(rightButton); div.appendChild(label); onChange(); return div; } export let CCSexStats = CharacterCreation.rulebook.createAndAddRule({ name : "Character Creation - Sex and Stats", firstPriority : Rule.PRIORITY_HIGH, priority: Rule.PRIORITY_HIGH, code : () => { Elements.startMenu(); let ccDiv = document.createElement("div"); ccDiv.id = "characterCreation"; let ccLeft = document.createElement("div"); ccLeft.id = "ccLeft"; ccDiv.appendChild(ccLeft); let ccRight = document.createElement("div"); ccRight.id = "ccRight"; ccDiv.appendChild(ccRight); let onChange = () => { (new Say(WorldState.player.description)).getHTMLContent().then((value => { while (ccRight.firstChild) ccRight.removeChild(ccRight.firstChild); value.forEach(val => { ccRight.appendChild(val); }); })); }; ccLeft.appendChild(createRange({ minValue : 0, maxValue : 1, step: 1, value : 0, leftLabel : "Male", rightLabel : "Female", topLabel : "Sex", onChange : (value : number, labelValue : Text, input : HTMLInputElement) => { labelValue.nodeValue = (value == 0 ? "Male" : "Female"); ( WorldState.player).removeGenderedParts(); if (value == 0) { ( WorldState.player).addMaleParts(); } else { ( WorldState.player).addFemaleParts(); } // Some stats become different whether te player is male or female, so we have to update them all. let otherInputs = ccDiv.getElementsByTagName("input"); for (let i = 0; i < otherInputs.length; i++) { let otherInput = otherInputs[i]; if (otherInput != input) { otherInput.dispatchEvent(new Event("change")); } } onChange(); } })); ccLeft.appendChild(createRange({ minValue : 0, maxValue : 4, step: 1, value : 2, leftLabel : "Masculine", rightLabel : "Feminine", topLabel : "Gender", onChange : (value : number, labelValue : Text) => { let names = ["Masculine", "Somewhat masculine", "Androgynous", "Somewhat feminine", "Feminine"]; labelValue.nodeValue = names[value]; let player = ( WorldState.player); let intendedValue : number; if (player.isMale()) { let values = [10, 25, 50, 55, 60]; intendedValue = values[value]; } else { let values = [35, 40, 50, 65, 75]; intendedValue = values[value]; } ( WorldState.player).setGenderValue(intendedValue); WorldState.player.setStat(Attributes.GenderIdentity, intendedValue); onChange(); } })); let statsHeader = document.createElement("div"); ccLeft.appendChild(statsHeader); statsHeader.classList.add("ccHeader"); statsHeader.appendChild(document.createTextNode("Stats (")); let maxStats = 12; let statsRemaining = document.createTextNode("4 points remaining"); statsHeader.appendChild(statsRemaining); statsHeader.appendChild(document.createTextNode(")")); let setStat = (attr : Attribute, value : number, input : HTMLInputElement) => { WorldState.player.setStat(attr, value); let remaining = maxStats - WorldState.player.getStat(Attributes.Strength) - WorldState.player.getStat(Attributes.Agility) - WorldState.player.getStat(Attributes.Intelligence) - WorldState.player.getStat(Attributes.Charm); if (remaining < 0) { value += remaining; remaining = 0; input.value = value.toString(); input.dispatchEvent(new Event("change")); return; } statsRemaining.nodeValue = (remaining == 0 ? "Done" : remaining > 1 ? remaining.toString() + " points remaining" : remaining.toString() + " point remaining"); }; ccLeft.appendChild(createRange({ minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Strength", onChange : (value : number, labelValue : Text, input : HTMLInputElement) => { setStat(Attributes.Strength, value, input); onChange(); } })); ccLeft.appendChild(createRange({ minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Agility", onChange : (value : number, labelValue : Text, input : HTMLInputElement) => { setStat(Attributes.Agility, value, input); onChange(); } })); ccLeft.appendChild(createRange({ minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Charm", onChange : (value : number, labelValue : Text, input : HTMLInputElement) => { setStat(Attributes.Charm, value, input); onChange(); } })); ccLeft.appendChild(createRange({ minValue : 1, maxValue : 5, step: 1, value : 2, leftLabel : "-", rightLabel : "+", topLabel : "Intelligence", onChange : (value : number, labelValue : Text, input : HTMLInputElement) => { setStat(Attributes.Intelligence, value, input); onChange(); } })); let creationDone = new Promise((resolve) => { (new Say("Confirm")).getHTML("p", ["choice"]).then(elementArray => { elementArray[0].addEventListener("click", () => { Elements.endMenu(); resolve(); }); Controls.KeyHandler.applyCode(elementArray[0], Controls.KeyHandler.getSecondKeyCode()); Elements.CurrentTurnHandler.print(elementArray[0]); }); }); Elements.CurrentTurnHandler.print(ccDiv); return creationDone; } }); // TODO: Pick origin // TODO: Pick Perks }