"use strict";
//@DOC
// ## The Text Processor Function
//@UNDOC
//@DOC
// Returns a string in which all the text processor directives have been resolved, using the optionasl parameters.
// More details [here(https://github.com/ThePix/QuestJS/wiki/The-Text-Processor).
function processText(str, params) {
if (params === undefined) {
params = {tpNoParamsPassed:true};
}
if (typeof str !== "string") {
str = "" + str;
}
params.tpOriginalString = str;
if (params.count) params.item_count = params.count
//log(params)
if (tp.usedStrings.includes(str)) {
params.tpFirstTime = false;
}
else {
tp.usedStrings.push(str);
params.tpFirstTime = true;
}
return tp.processText(str, params);
}
// Most of the text processors are set up in text.js; these are the language specific ones.
const tp = {
text_processors:{},
setLoadString:function(s) {
const parts = s.split("=");
if (parts.length !== 2) return errormsg("Bad format in saved data (" + s + ")")
if (parts[0] !== "TPUsedStrings") return errormsg("Expected TP to be first")
tp.usedStrings = saveLoad.decodeArray(parts[1])
},
getSaveString:function() {
let s = "TPUsedStrings=" + saveLoad.encodeArray(tp.usedStrings);
return s;
},
}
tp.usedStrings = [];
tp.colours = ['#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080', '#ffffff', '#000000']
// Use this to add you custom text processor
// Should take a string array as a parameter (the input text,
// excluding the curly braces, name and colon),
// and return a string.
tp.addDirective = function(name, fn) {
tp.text_processors[name] = fn;
};
tp.comparisons = {
'=':'if',
'==':'if',
'!=':'ifNot',
'!==':'ifNot',
'<>':'ifNot',
'<':'ifLessThan',
'>':'ifMoreThan',
'<=':'ifLessThanOrEqual',
'>=':'ifMoreThanOrEqual',
}
tp.processText = function(str, params) {
const s = tp.findFirstToken(str);
if (s) {
let arr = s.split(":");
let left = arr.shift();
if (typeof tp.text_processors[left] !== "function") {
if (left.startsWith('if ')) {
const data = /if (not |)(\w+)\.(\w+) *([<>=!]{0,3}) *(.*)/.exec(left)
if (data[4] === '') {
arr.unshift(data[3])
arr.unshift(data[2])
left = data[1] === 'not ' ? 'ifNot' : 'if'
}
else {
arr.unshift(data[5])
arr.unshift(data[3])
arr.unshift(data[2])
left = tp.comparisons[data[4]]
}
}
else if (left.match(/^(not)?here /)) {
const ary = left.split(' ')
ary.shift()
left = left.startsWith('here') ? 'ifHere' : 'ifNotHere'
for (const el of ary.reverse()) arr.unshift(el)
}
else if (left === "player") {
arr.unshift(player.name);
left = "show";
}
else if (left === "currentLocation") {
arr.unshift(currentLocation.name);
left = "show";
}
else if (w[left]) {
arr.unshift(left);
left = "show";
}
else if (arr.length === 0) {
arr = left.split(".");
left = "show";
}
else {
errormsg("Attempting to use unknown text processor directive '" + left + "' (" + params.tpOriginalString + ")");
return str;
}
}
str = str.replace("{" + s + "}", tp.text_processors[left](arr, params));
str = tp.processText(str, params);
}
return str
};
// Find the first token. This is the first to end, so
// we get nested.
tp.findFirstToken = function (s) {
const end = s.indexOf("}");
if (end === -1) { return false; }
const start = s.lastIndexOf("{", end);
if (start === -1) {
errormsg("Failed to find starting curly brace in text processor (" + s + ")");
return false;
}
return s.substring(start + 1, end);
};
tp.text_processors.i = function(arr, params) { return "" + arr.join(":") + ""; };
tp.text_processors.b = function(arr, params) { return "" + arr.join(":") + ""; };
tp.text_processors.u = function(arr, params) { return "" + arr.join(":") + ""; };
tp.text_processors.s = function(arr, params) { return "" + arr.join(":") + ""; };
tp.text_processors.code = function(arr, params) { return "" + arr.join(":") + "
"; };
tp.text_processors.sup = function(arr, params) { return "" + arr.join(":") + ""; };
tp.text_processors.sub = function(arr, params) { return "" + arr.join(":") + ""; };
tp.text_processors.huge = function(arr, params) { return '' + arr.join(":") + ''; };
tp.text_processors.big = function(arr, params) { return '' + arr.join(":") + ''; };
tp.text_processors.small = function(arr, params) { return '' + arr.join(":") + ''; };
tp.text_processors.tiny = function(arr, params) { return '' + arr.join(":") + ''; };
tp.text_processors.smallcaps = function(arr, params) { return '' + arr.join(":") + ''; };
tp.text_processors.cap = function(arr, params) {
return sentenceCase(arr.join(":"))
}
tp.text_processors.title = function(arr, params) {
return titleCase(arr.join(":"))
}
tp.text_processors.upper = function(arr, params) {
return arr.join(":").toUpperCase()
}
tp.text_processors.lower = function(arr, params) {
return arr.join(":").toLowerCase()
}
tp.text_processors.rainbow = function(arr, params) {
const s = arr.pop()
const colours = arr.length === 0 ? tp.colours : arr
let result = ''
for (let i = 0; i < s.length; i++) {
result += '' + s.charAt(i) + ''
}
return result
};
tp._charSwap = function(c, upper, lower) {
if (c.match(/[A-Z]/)) return String.fromCharCode(c.charCodeAt(0) - 'A'.charCodeAt(0) + upper)
if (c.match(/[a-z]/)) return String.fromCharCode(c.charCodeAt(0) - 'a'.charCodeAt(0) + lower)
return c
}
// Try 391:3AC for Greek, 402:431 for Cyrillic, 904:904 for Devanagari
tp.text_processors.encode = function(arr, params) {
const upper = parseInt(arr.shift(), 16)
const lower = parseInt(arr.shift(), 16)
const s = arr.shift()
let result = ''
for (let i = 0; i < s.length; i++) {
result += tp._charSwap(s.charAt(i), upper, lower)
}
return result
};
tp.text_processors.rainbow = function(arr, params) {
const s = arr.pop()
const colours = arr.length === 0 ? tp.colours : arr
let result = ''
for (let i = 0; i < s.length; i++) {
result += '' + s.charAt(i) + ''
}
return result
};
tp.text_processors.blur = function(arr, params) {
const n = arr.shift();
return '' + arr.join(":") + "";
};
tp.text_processors.font = function(arr, params) {
const f = arr.shift();
return '' + arr.join(":") + "";
};
tp.text_processors.class = function(arr, params) {
const c = arr.shift()
return '' + arr.join(":") + ''
}
tp.text_processors.colour = function(arr, params) {
const c = arr.shift();
return '' + arr.join(":") + "";
};
tp.text_processors.color = tp.text_processors.colour;
tp.text_processors.back = function(arr, params) {
const c = arr.shift();
return '' + arr.join(":") + "";
};
tp.text_processors.dialogue = function(arr, params) {
let prefix = "'
return prefix + settings.openQuotation + arr.join() + settings.closeQuotation + ""
}
tp.text_processors.random = function(arr, params) {
return arr[Math.floor(Math.random()*arr.length)];
};
tp.text_processors.select = function(arr, params) { return tp.select(arr, params, 'none') }
tp.text_processors.selectNone = function(arr, params) { return tp.select(arr, params, 'none') }
tp.text_processors.selectWrap = function(arr, params) { return tp.select(arr, params, 'wrap') }
tp.text_processors.selectStart = function(arr, params) { return tp.select(arr, params, 'start') }
tp.text_processors.selectEnd = function(arr, params) { return tp.select(arr, params, 'end') }
tp.select = function(arr, params, opt) {
let name = arr.shift()
if (name.match(/\./)) {
const ary = name.split('.')
name = ary[0]
arr.unshift(ary[1])
}
const o = tp._findObject(name, params, arr)
if (!o) errormsg('Failed to find an object called "' + name + '" in text processor select.')
const l = o[arr[0]]
if (l === undefined) errormsg('Failed to find an attribute called "' + arr[0] + '" for "' + name + '" in text processor "select" directive.')
if (Array.isArray(l)) {
const n = o[arr[1]]
if (!l) errormsg('Failed to find a secondary attribute called "' + arr[1] + '" for "' + name + '" in text processor "select" directive.')
return array.value(l, n, opt)
}
if (typeof l === 'number') {
arr.shift()
return array.value(arr, l, opt)
}
errormsg('Failed to do anything with the attribute called "' + arr[1] + '" for "' + name + '" in text processor select - neither an array or an integer.')
};
tp._findObject = function(name, params, arr) {
if (params && params[name]) return typeof params[name] === 'string' ? w[params[name]] : params[name]
if (name === "player") return player
if (name === "currentLocation") return currentLocation
if (name === "settings") return settings
if (name === "params") return params
if (w[name]) return w[name]
const ary = name.split('.')
if (ary.length === 1) return undefined
if (ary.length > 2) {
console.log("The text process cannot handle attributes of attributes, so failed to deal with: " + name)
console.log(ary)
return undefined
}
arr.unshift(ary[1])
return w[ary[0]]
}
tp.text_processors.multi = function(arr, params) {
if (!params.multiple) return ''
return sentenceCase(params.item.alias) + ": "
}
tp.text_processors.show = function(arr, params) {
let name = arr.shift()
if (params[name] !== undefined) {
if (typeof params[name] === 'object') return tp.getWhatever(params[name][arr[0]], params, params[name])
return tp.getWhatever(params[name], params)
}
const obj = tp._findObject(name, params, arr)
if (!obj) return errormsg("Failed to find object '" + name + "' in text processor 'show' (" + params.tpOriginalString + ")")
return tp.getWhatever(obj[arr[0]], params, obj)
}
tp.text_processors.object = tp.text_processors.show
tp.getWhatever = function(val, params, obj) {
if (val === false) return lang.tp_false
if (val === true) return lang.tp_true
if (val === undefined) return ''
if (typeof val === 'string') return val
if (typeof val === 'number') return val.toString()
if (typeof val !== 'function') return errormsg("Got a value of a type I was not expecting in show: " + (typeof val))
const func = val.bind(obj)
return func(params)
}
tp.text_processors.rndalt = function(arr, params) {
let name = arr.shift()
if (params[name]) {
if (typeof params[name] === 'string') return params[name]
if (typeof params[name] === 'number') return params[name].toString()
if (arr.length > 0) return params[name][arr[0]]
}
const obj = tp._findObject(name, params, arr)
if (!obj) return errormsg("Failed to find object '" + name + "' in text processor 'show' (" + params.tpOriginalString + ")")
if (obj.alt) return random.fromArray(obj.alt)
return obj.alias
}
tp.text_processors.number = function(arr, params) {
let name = arr.shift()
if (name.match(/^\d+$/)) return lang.toWords(parseInt(name))
if (typeof params[name] === 'number') return lang.toWords(params[name])
const obj = tp._findObject(name, params, arr)
if (!obj) return errormsg("Failed to find object '" + name + "' in text processor 'number' (" + params.tpOriginalString + ")")
if (typeof obj[arr[0]] === 'number') return lang.toWords(obj[arr[0]])
return errormsg("Failed to find a number for object '" + name + "' in text processor (" + params.tpOriginalString + ")")
};
tp.text_processors.ordinal = function(arr, params) {
let name = arr.shift()
if (name.match(/^\d+$/)) return lang.toOrdinal(parseInt(name))
if (typeof params[name] === 'number') return lang.toOrdinal(params[name])
const obj = tp._findObject(name, params, arr)
if (!obj) return errormsg("Failed to find object '" + name + "' in text processor 'number' (" + params.tpOriginalString + ")")
if (typeof obj[arr[0]] === 'number') return lang.toOrdinal(obj[arr[0]])
return errormsg("Failed to find a number for object '" + name + "' in text processor (" + params.tpOriginalString + ")")
};
tp.text_processors.money = function(arr, params) {
let name = arr.shift()
if (name.match(/^\d+$/)) return displayMoney(parseInt(name))
if (typeof params[name] === 'number') return displayMoney(params[name])
const obj = tp._findObject(name, params, arr)
if (!obj) return errormsg("Failed to find object '" + name + "' in text processor 'money' (" + params.tpOriginalString + ")")
if (obj.loc === player.name && obj.getSellingPrice) {
return displayMoney(obj.getSellingPrice(player))
}
if (obj.loc === player.name && obj.getBuyingPrice) {
return displayMoney(obj.getBuyingPrice(player))
}
if (obj.getPrice) {
return displayMoney(obj.getPrice())
}
if (obj.price) {
return displayMoney(obj.price)
}
if (obj.money) {
return displayMoney(obj.money)
}
return errormsg("Failed to find a price for object '" + name + "' in text processor (" + params.tpOriginalString + ")")
};
tp.text_processors['$'] = tp.text_processors.money
tp.text_processors.dateTime = function(arr, params) {
const options = {format:arr[0]}
if (!isNaN(arr[1])) options.is = parseInt(arr[1])
if (!isNaN(arr[2])) options.add = parseInt(arr[2])
return util.getDateTime(options)
};
tp.text_processors.transitDest = function(arr, params) {
const transit = arr[0] ? w[arr[0]] : w[player.loc]
if (!transit.transitDoorDir) return errormsg("Trying to use the 'transitDest' text process directive when the player is not in a transit location (" + params.tpOriginalString + ").")
if (transit.currentButtonName) {
const button = w[transit.currentButtonName]
if (button.title) return button.title
}
const destName = transit[transit.transitDoorDir].name
return lang.getName(w[destName], {capital:true})
};
tp.text_processors.img = function(arr, params) {
const src = arr[0].includes('/') ? arr[0] : settings.imagesFolder + arr[0]
return '';
}
tp.once = function(params, s1, s2) {
if (params.tpFirstTime && s1) return s1
if (!params.tpFirstTime && s2) return s2
return ''
}
tp.text_processors.once = function(arr, params) { return tp.once(params, arr[0], arr[1]) }
tp.text_processors.first = tp.text_processors.once
tp.text_processors.notOnce = function(arr, params) { return tp.once(params, arr[1], arr[0]) }
tp.text_processors.notfirst = tp.text_processors.notOnce
tp.text_processors.cmd = function(arr, params) {
if (arr.length === 1) {
return io.cmdlink(arr[0], arr[0])
}
else {
return io.cmdlink(arr[0], arr[1])
}
}
tp.text_processors.command = function(arr, params) {
if (arr.length === 1) {
return io.cmdlink(arr[0], arr[0]);
}
else {
return io.cmdlink(arr[0], arr[1]);
}
}
tp.text_processors.exit = tp.text_processors.command
tp.text_processors.page = tp.text_processors.command
tp.text_processors.hour = function(arr, params) {
const hour = util.getDateTimeDict().hour
if (hour < arr[0]) return ''
if (hour >= arr[1]) return ''
return arr[2]
}
tp.text_processors.link = function(arr, params) {
let s1 = arr.shift()
let s2 = arr.join(':')
return '' + s1 + ''
}
tp.text_processors.popup = function(arr, params) {
let s1 = arr.shift()
let s2 = arr.join(':')
let id = s1.replace(/[^a-zA-Z_]/, '') + random.int(0, 999999999)
const html = '
' + s2 + '