///
///
///
///
interface Printable {
getPrintedName () : string;
}
interface PrintableElement {
getPrintedElement () : Array;
}
interface SayNoun {
say : Say;
noun : any;
}
class SayableObject {}
class Say {
// TODO: Separate own sequence from processing queue. This way a Say with functions/other says can be reutilized with fresh values.
public sequence : Array = [];
public skipbreaks : boolean = false;
public static LINE_BREAK : Object = new SayableObject();
public static CONDITIONAL_LINE_BREAK : Object = new SayableObject();
public static PARAGRAPH_BREAK : Object = new SayableObject();
public static RUN_PARAGRAPH : Object = new SayableObject();
public static RUN_PARAGRAPH_OFF : Object = new SayableObject();
public static CENTERED : Object = new SayableObject();
public static b : Object = new SayableObject();
public static DO_PARAGRAPH_BREAK = new SayableObject();
public static DO_LINE_BREAK = new SayableObject();
public static COCK = new SayableObject();
public static PUSSY = new SayableObject();
private centered : boolean = false;
public static Action (a : any) {
return new SayAction(a);
}
public static Bold (a : any) {
return new SayBold(a);
}
public static Mention (target : Thing, uppercase = true) : Array {
if (target == WorldState.player) {
return [new SayYou(uppercase)];
} else {
return [new SayThe(uppercase), target];
}
}
public static YouThem (target : Thing, uppercase = true) {
return Say.Mention(target, uppercase);
}
public static YourTheir (target : Thing, uppercase = true) {
if (target == WorldState.player) {
return [new SayYour(uppercase)];
} else {
return [new SayHisHersIts(target, uppercase)];
}
}
public static Article (target : Thing, uppercase = true) {
let arr = [];
if (target.isUnique()) {
arr.push(new SayThe(uppercase));
} else {
arr.push(new SayAn(uppercase));
}
arr.push(target);
return arr;
}
/**
* He, She, It
* @param target
* @param uppercase
* @constructor
*/
public static Subject (target : Thing, uppercase = true) {
return new SayHeSheIt(target, uppercase);
}
/**
* Him, Her, It
* @param target
* @param uppercase
* @constructor
*/
public static Object (target : Thing, uppercase = true) {
return new SayHimHerIt(target, uppercase);
}
/**
* His, Hers, Its
* @param target
* @param uppercase
* @constructor
*/
public static Possessive (target : Thing, uppercase = true) {
return new SayHisHersIts(target, uppercase);
}
public static Speak (speaker : Thing | string, ...message : Array) {
if (typeof speaker == "string") {
return [new SayBold(speaker, ": "), ...message];
} else {
return [new SayBold(...Say.YouThem(speaker), ": "), ...message];
}
}
public constructor (...objs) {
this.add(...objs);
}
public add (...objs : Array string)>) {
for (let i = 0; i < objs.length; i++) {
if (Array.isArray(objs[i])) {
this.sequence.push(...(> objs[i]));
} else {
this.sequence.push(objs[i]);
}
}
return this;
}
public remove (...objs) {
for (let i = 0; i < objs.length; i++) {
let index = this.sequence.indexOf(objs[i]);
if (index >= 0) {
this.sequence.splice(index, 1);
}
}
}
public isEmpty () {
return this.sequence.length < 1;
}
public paragraphs : Array>;
public currentParagraph : Array;
public sequenceRunner : number;
// TODO: Create a single function to get the element of anything
public async getTextOf (index : number, seq : any) : Promise {
let elements = await this.getElementFor(index, seq);
let div = document.createElement("div");
for (let i = 0; i < elements.length; i++) {
if (typeof elements[i] != "number") {
div.appendChild(elements[i]);
}
}
return div.innerText;
}
public doLineBreak (noDouble : boolean) {
if (this.currentParagraph.length > 0 && !this.skipbreaks) {
if (noDouble) {
let lastElement = this.currentParagraph[this.currentParagraph.length - 1];
if (lastElement != undefined && lastElement instanceof Element && lastElement.tagName == "BR") {
return;
}
}
let br = document.createElement("br");
br.classList.add("linebreak");
let ti = document.createElement("span");
ti.classList.add("textIndenter");
this.currentParagraph.push(br, ti);
}
}
public doParagraphBreak () {
if (this.currentParagraph.length > 0 && !this.skipbreaks) {
this.paragraphs.push(this.currentParagraph);
this.currentParagraph = [];
}
}
public async getParagraphs () : Promise>> {
this.paragraphs = [];
this.currentParagraph = [];
this.skipbreaks = false;
for (this.sequenceRunner = 0; this.sequenceRunner < this.sequence.length; this.sequenceRunner++) {
let seq = this.sequence[this.sequenceRunner];
if (seq instanceof OneOf) {
seq = seq.getOne();
}
if (seq == Say.CENTERED) {
this.setCentered(true);
} else if (seq == Say.b) {
let boldObjects = [];
for (let i = this.sequenceRunner + 1; i < this.sequence.length; i++) {
let candidate = this.sequenceRunner[i];
if (candidate == Say.b) {
this.sequence.splice(i, 1);
break;
} else {
boldObjects.push(this.sequence.splice(i, 1));
}
}
if (boldObjects.length > 0) {
let bold = new SayBold(...boldObjects);
this.sequence.splice(this.sequenceRunner + 1, 0, bold);
}
} else if (seq == Say.COCK) {
if (HumanoidPenis != undefined) {
let cock = HumanoidPenis.getSynonym();
this.currentParagraph.push(document.createTextNode(cock))
}
} else if (seq == Say.PUSSY) {
if (HumanoidVagina != undefined) {
let vagina = HumanoidVagina.getSynonym();
this.currentParagraph.push(document.createTextNode(vagina))
}
} else if (seq == Say.LINE_BREAK || seq == Say.CONDITIONAL_LINE_BREAK) {
this.doLineBreak(seq == Say.CONDITIONAL_LINE_BREAK);
} else if (seq == Say.PARAGRAPH_BREAK) {
this.doParagraphBreak();
} else if (seq == Say.RUN_PARAGRAPH) {
this.skipbreaks = true;
} else if (seq == Say.RUN_PARAGRAPH_OFF) {
this.skipbreaks = false;
} else if (typeof seq == "function") {
// not a function, but a class
if (seq.prototype != undefined) {
this.currentParagraph.push(document.createTextNode(seq.name));
} else {
let fObj = (<(s: Say) => any>seq)(this);
if (Array.isArray(fObj)) {
for (let k = fObj.length - 1; k >= 0; k--) {
this.sequence.splice(this.sequenceRunner + 1, 0, fObj[k]);
}
} else if (fObj != undefined) {
this.sequence.splice(this.sequenceRunner + 1, 0, fObj);
}
this.sequence.splice(this.sequenceRunner, 1);
this.sequenceRunner--;
}
} else if (seq.constructor == this.constructor) {
for (let k = ( seq).sequence.length - 1; k >= 0; k--) {
this.sequence.splice(this.sequenceRunner + 1, 0, ( seq).sequence[k]);
}
this.sequence.splice(this.sequenceRunner, 1);
this.sequenceRunner--;
} else if (seq != undefined) {
let elements = await this.getElementFor(this.sequenceRunner, seq);
for (let i = 0; i < elements.length; i++) {
if (elements[i] === Say.DO_LINE_BREAK) {
this.doLineBreak(false);
} else if (elements[i] === Say.DO_PARAGRAPH_BREAK) {
this.doParagraphBreak();
} else {
this.currentParagraph.push(elements[i]);
}
}
}
}
// TODO: Remove line break + text indenter if they are the last in the say
if (this.currentParagraph.length > 0) {
this.paragraphs.push(this.currentParagraph);
}
return this.paragraphs;
}
/**
* Lord Have mercy, I wish to never have to debug this piece of god.
* @param {number} index
* @param {Say | OneOf | Object | Printable | string | number | ((say: Say) => string) | ((say: Say) => Promise) | Element | Text} obj
* @returns {Promise>}
*/
public async getElementFor (index : number, obj : Say | OneOf | Object | Printable | string | number | String | ((say : Say) => string) | ((say : Say) => Promise) | Element | Text) : Promise> {
if (obj instanceof Promise) {
obj = await obj;
}
if (typeof obj == "string" || obj instanceof String) {
return [document.createTextNode( obj)];
} else if (typeof obj == "number" || obj instanceof Number) {
return [document.createTextNode((parseFloat(( obj).toFixed(2))/1).toString())];
} else if (typeof obj == "function") {
let elements = await this.getElementFor(-1, ( obj)(this));
return elements;
} else if (obj instanceof SayImage) {
return [obj.getImageElement()];
} else if (obj instanceof SayLeftRight) {
return (await obj.getPureElements());
} else if (obj instanceof Say) {
let elements = await obj.getPureElements(this);
return elements;
} else if (this.isProperElement(obj)) {
return [ obj];
} else if (obj instanceof Object) {
let elements = await this.printName(obj);
return elements;
}
}
public async getPureElements (say? : Say) : Promise> {
let paragraphs = await this.getParagraphs();
return paragraphs.length == 1 ? paragraphs[0] : Array.prototype.concat.apply([], paragraphs);
}
public setCentered (bool : boolean) {
this.centered = bool;
}
public async getHTML (tagName : string, classList : Array, singleParagraph? : boolean) : Promise> {
let paragraphs = await this.getParagraphs();
// Reduce to single paragraph
if (singleParagraph == true && paragraphs.length > 1) {
paragraphs = [Array.prototype.concat.apply([], paragraphs)];
}
let elements = [];
for (let i = 0, paragraph = paragraphs[i]; paragraph != undefined; paragraph = paragraphs[++i]) {
let parent = document.createElement(tagName);
if (classList.length > 0) {
parent.classList.add(...classList);
}
for (let k = 0, ele = paragraph[k]; ele!= undefined; ele = paragraph[++k]) {
parent.appendChild(ele);
}
elements.push(parent);
if (this.centered) {
parent.classList.add("centered");
}
}
return elements;
}
public getHTMLContent () : Promise> {
return this.getHTML("p", ["content"]);
}
public isProperElement (o) : boolean {
return (
typeof Node === "object" ? o instanceof Node :
o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName==="string"
) || (
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
);
}
public static beforePrinting = new Rulebook("Before printing the name of something");
public static printing = new Rulebook("Printing the name of something");
public static afterPrinting = new Rulebook("After printing the name of something");
public currentNoun : any;
public currentNounElements : Array;
public async printName (thing : any) : Promise> {
this.currentNoun = thing;
this.currentNounElements = [];
let before = Say.beforePrinting.execute({noun : this});
await before;
let print = Say.printing.execute({noun : this});
await print;
let after = Say.afterPrinting.execute({noun : this});
await after;
return this.currentNounElements;
}
public static hisHersIts (target : Thing, startOfSentence? : boolean) {
return new SayHisHersIts(target);
// let result : String;
// if (target == WorldState.player) {
// result = "your";
// } else if (target instanceof Person) {
// // TODO: Figure out whether target is male or female
// result = "his";
// } else {
// result = "its";
// }
// if (startOfSentence == true) {
// result = result.charAt(0).toUpperCase() + result.substr(1, result.length -1);
// }
// return result;
}
}
Say.printing.addRule(new Rule({
name : "Printing the name of a Printable Element",
firstPriority : Rule.PRIORITY_LOW,
code : (rulebook : RulebookRunner) => {
let say = rulebook.noun;
if (( say.currentNoun).getPrintedElement) {
say.currentNounElements.push(...( say.currentNoun).getPrintedElement());
return true; // We only want to print something once, so return true to stop others from running
}
}
}));
Say.printing.addRule(new Rule({
name : "Printing the name of a Printable",
firstPriority : Rule.PRIORITY_LOW,
code : (rulebook : RulebookRunner) => {
let say = rulebook.noun;
if (( say.currentNoun).getPrintedName) {
let thingEle = document.createTextNode(
( say.currentNoun).getPrintedName()
);
say.currentNounElements.push(thingEle);
return true; // We only want to print something once, so return true to stop others from running
}
}
}));
Say.printing.addRule(new Rule({
name : "Printing the name of an unknown object",
firstPriority : Rule.PRIORITY_LOWEST,
priority : Rule.PRIORITY_LOWEST,
code : (rulebook : RulebookRunner) => {
let say = rulebook.noun;
if (( say.currentNoun).getPrintedName) {
say.currentNounElements.push(
(document.createTextNode(( say.currentNoun).toString()))
);
return true; // We only want to print something once, so return true to stop others from running
}
}
}));
// var msg = new Say ("Hello! Welcome to The Obelisk! This is a game with ", johnTheOgre, " so you must be careful!");
//
// var otherSay = new Say (msg, "Will have to learn how to handle dots.");