(function(){
"use strict";
this.name = "Cabal_Common_PhraseGen";
this.author = "Disembodied, Svengali";
this.copyright = "(C)2010-2013, License:CC-by";
this.description = "Libraryscript";
this.version = "0.98";
this.OXPVersion = "0.98";

this.recGuard = false;
this.startUp = function()
{
	delete this.startUp;
	this.init = true;
	this.specials = {
		commanderBounty: player.bounty+" Cr.",
		commanderName: player.name,
		commanderRank: player.rank,
		commanderStatus: player.legalStatus,
		currentShipDisplayName: player.ship.displayName,
		currentShipName: player.ship.name,
		currentSystem: {},
		currentTarget: "",
		rndBrewName: [],
		rndFirstName: [],
		rndShipName: [],
		rndSurName: [],
		rndSystem: [],
		idsA: ["I","II","III","IV","V","VI","VII","IX","X"],
		idsB: ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"],
		idsC: ["0","1","2","3","4","5","6","7","8","9"]
	};
	this.pool = worldScripts.Cabal_Common_PhraseGenWords.pool;
	this.irregularNouns = worldScripts.Cabal_Common_PhraseGenWords.irregularNouns;
	this.irregularVerbs = worldScripts.Cabal_Common_PhraseGenWords.irregularVerbs;
	this.superlatives = worldScripts.Cabal_Common_PhraseGenWords.superlatives;
	this.fillTimer = new Timer(this,this.fillInBits,1);
};
// Entry point for OXPs.
this.makePhrase = function(set,pattern,store,seed,cst)
{
	if(!set) return(false);
	if(typeof(set)==='object') this.stdObj = set;
	else {
		if(typeof(this.pool[set])==='undefined') return(false);
		this.stdObj = this.pool[set];
	}
	var option = {
		patt: null,
		store: 0,
		seed: 0,
		cst: []
	};
	if(typeof(pattern)!=='undefined') option.patt = pattern;
	if(store) option.store = true;
	if(seed) option.seed = seed;
	if(cst) option.cst = cst;
	var t = this.buildPhrase(option.patt,option.store,option.seed,option.cst);
	return t;
};
// Entry point for OXPs.
this.addSample = function(samplename,obj,clone){
	if(typeof(obj) !== 'object' || typeof(samplename) !== 'string' || typeof(this.pool[samplename]) !== 'undefined') return(false);
	if(clone) this.pool[samplename] = this.cloneObj(obj);
	else this.pool[samplename] = obj;
	return(true);
};
this.fillInBits = function fillInBits()
{
	this.specials.commanderBounty = player.bounty+" Cr.";
	this.specials.commanderName = player.name;
	this.specials.commanderRank = player.rank;
	this.specials.commanderStatus = player.legalStatus;
	this.specials.currentShipDisplayName = player.ship.displayName;
	this.specials.currentShipName = player.ship.name;
	this.specials.currentSystem = (system.isInterstellarSpace?{description:"interstellar",economy:-1,government:-1,ID:-1,inhabitant:"none",inhabitants:"none",name:"interstellar",population:-1,productivity:-1,radius:-1,sun:false,techlevel:-1}:worldScripts.Cabal_Common_Functions.moreInfo.galaxyStats.contains(system.ID));
	this.specials.currentTarget = "";
	this.specials.rndBrewName = [];
	this.specials.rndFirstName = [];
	this.specials.rndShipName = [];
	this.specials.rndSurName = [];
	if(this.fillTimer){
		this.specials.rndSystem = [];
		for(var i=0;i<256;i++) this.specials.rndSystem.push(worldScripts.Cabal_Common_Functions.moreInfo.galaxyStats.contains(i));
	}
	for(var i=0;i<20;i++){
		this.specials.rndFirstName.push(this.makePhrase("CCL_Names","1"));
		this.specials.rndFirstName.push(this.makePhrase("CCL_Names","2"));
		this.specials.rndFirstName.push(this.makePhrase("CCL_Names","12"));
		this.specials.rndSurName.push(this.makePhrase("CCL_Names","{1"));
		this.specials.rndSurName.push(this.makePhrase("CCL_Names","{1"));
		this.specials.rndSurName.push(this.makePhrase("CCL_Names","{1"));
		this.specials.rndBrewName.push(this.makePhrase("CCL_NamesBrews"));
		this.specials.rndShipName.push(this.makePhrase("CCL_NamesShips"));
	}
	if(this.fillTimer) delete this.fillTimer;
	delete this.init;
	return;
};
this.shipWillDockWithStation = function()
{
	if(!system.isInterstellarSpace) this.fillInBits();
};
this.shipWillLaunchFromStation = function()
{
	var myInfo = worldScripts.Cabal_Common_Functions.moreInfo.galaxyStats;
	this.specials.commanderBounty = String(player.bounty)+" Cr.";
	this.specials.commanderName = player.name;
	this.specials.commanderRank = player.rank;
	this.specials.commanderStatus = player.legalStatus;
	this.specials.currentSystem = (system.isInterstellarSpace?{description:"interstellar",economy:-1,government:-1,ID:-1,inhabitant:"none",inhabitants:"none",name:"interstellar",population:-1,productivity:-1,radius:-1,sun:false,techlevel:-1}:myInfo.contains(system.ID));
system.addShips("phrasegen_test",1,player.ship.position,10000);
};
this.playerEnteredNewGalaxy = function()
{
	this.init = true;
	this.fillTimer = new Timer(this,this.fillInBits,1);
};
this.shipWillExitWitchspace = function()
{
	if(this.init) return;
	var myInfo = worldScripts.Cabal_Common_Functions.moreInfo.galaxyStats;
	this.specials.commanderRank = player.rank;
	this.specials.commanderStatus = player.legalStatus;
	this.specials.currentSystem = (system.isInterstellarSpace?{description:"interstellar",economy:-1,government:-1,ID:-1,inhabitant:"none",inhabitants:"none",name:"interstellar",population:-1,productivity:-1,radius:-1,sun:false,techlevel:-1}:myInfo.contains(system.ID));
system.addShips("phrasegen_test",1,player.ship.position,10000);
};
this.shipTargetLost = function()
{
	this.specials.commanderRank = player.rank;
	this.specials.commanderStatus = player.legalStatus;
};
this.playerBoughtNewShip = function()
{
	this.specials.currentShipDisplayName = player.ship.displayName;
	this.specials.currentShipName = player.ship.name;
};
this.shipTargetAcquired = function()
{
	this.specials.commanderRank = player.rank;
	this.specials.commanderStatus = player.legalStatus;
};
this.shipBountyChanged = function()
{
	this.specials.commanderBounty = String(player.bounty)+" Cr.";
	this.specials.commanderStatus = player.legalStatus;
};
this.stdObj = {
	fieldA:[],fieldB:[],fieldC:[],fieldD:[],fieldE:[],fieldF:[],fieldG:[],fieldH:[],fieldI:[],
	fieldJ:[],fieldK:[],fieldL:[],fieldM:[],fieldN:[],fieldO:[],fieldP:[],fieldQ:[],fieldR:[],
	sentences:[],custom:[],splitRules:[]
};
this.fields = [["fieldA","fieldJ"],["fieldB","fieldK"],["fieldC","fieldL"],["fieldD","fieldM"],
	["fieldE","fieldN"],["fieldF","fieldO"],["fieldG","fieldP"],["fieldH","fieldQ"],["fieldI","fieldR"]];
this.cloneObj = function(srcInstance){
	if(typeof(srcInstance)!=='object' || srcInstance===null) return srcInstance;
	var newInstance = srcInstance.constructor();
	for(var i in srcInstance) newInstance[i] = this.cloneObj(srcInstance[i]);
	return newInstance;
};
this.random = function(maxnum)
{
	return maxnum*(Math.random()%1) | 0;
};
// Random number in range a-b in steps of s
this.rnd_range = function(a,b,s){
	var x = Math.random();
	var y = (b*x)-(a*x)+1;
	if(!y) return a;
	var z = Math.floor(y/s);
	return a+z*s;
};
// First letter uppercase
this.initial_cap = function(str)
{
	if(!str) return "";
	return str[0].toUpperCase() + str.substr(1);
};
// Rules
this.make_plural = function(word)
{ // e,f,h,o,s,x,y
	if(/[^es]s$/.test(word)) return word;
	if(/fe$/.test(word)) return word.replace(/fe$/,"ves");
	if(/e$/.test(word)) return word + "s";
	if(/(?:[^ei]x|[^o]o|[es]s|[cs]h)$/.test(word)) return word + "es";
	if(/s$/.test(word)) return word;
	if(/[^aeou]y$/.test(word)) return word.replace(/y$/,"ies");
	if(/[^erf]f$/.test(word)) return word.replace(/f$/,"ves");
	if(/[ei]x$/.test(word)) return word.replace(/[ei]x$/,"ices");
	return word + "s";
};
// Rules
this.make_past = function(word)
{ // b,e,l,p,y
	if(/e$/.test(word)) return word + "d";
	if(/[^aeou]y$/.test(word)) return word.replace(/y$/,"ied");
	if(/[^adeliosy][aeioy][bcdfgjklmnpqrsvz]$/.test(word)) return word + word[word.length-1] + "ed";
	return word + "ed";
};
this.make_verbPhrase = function(word,markTense,markPlural)
{
	var wsp = word.split(" ");
	var wspl = wsp.length;
	for(var i=0;i<wspl;i++){
		var t = wsp[i].match(/[\$&]/g);
		if(t && t.length){
			var raw = wsp[i].replace(/[\$&]/g,""),flagP,flagS,flagH,flagI;
			var ex = raw.match(/[^A-Za-z=]/g);
			if(ex) raw = raw.replace(/[^A-Za-z=]/g,"");
			var tl = t.length;
			for(var o=0;o<tl;o++){
				switch(t[o]){
					case "&":
						flagI=1;
						raw = raw.replace(/=/," ");
						if(typeof(this.irregularVerbs[raw])!=='undefined') raw = this.irregularVerbs[raw][(markTense<4?markTense:3)];
						else flagI=0;
						break;
					case "$":
						switch(markTense){
							case 0: if(markPlural) flagS=1; break;
							case 1: if(!flagI) flagS=1; break;
							case 2: flagP=1; break;
							case 3: flagP=1; break;
							case 4: flagH=1; flagP=1; break;
						}
						break;
				}
			}
			if(flagS) raw = this.make_plural(raw);
			if(flagI) flagI = 0;
			else if(flagP) raw = this.make_past(raw);
			if(flagH) raw = (markPlural?"have ":"has ")+raw;
			if(ex) raw = raw + ex[0];
			wsp[i] = raw;
		}
	}
	return wsp.join(" ");
};
this.handleRules = function(wrd,markTense,nextPlural,markShift,donot){
	if(/[\$$^&]/.test(wrd)){
		var irregNoun = 0;
		// Verbs
		if(/\$/.test(wrd)) wrd = this.make_verbPhrase(wrd,markTense,nextPlural);
		else { // Nouns
			var ex = wrd.match(/[^A-Za-z=]/g);
			if(ex) wrd = wrd.replace(/[^A-Za-z=&]/g,"");
			if(/&/g.test(wrd)){
				irregNoun = 1;
				wrd = wrd.replace(/&/,"");
			}
			if(nextPlural){
				if(irregNoun && typeof(this.irregularNouns[wrd])!=='undefined') wrd = this.irregularNouns[wrd];
				else wrd = this.make_plural(wrd);
			}
			if(ex) wrd = wrd + ex[0];
		}
	} else {
		if(nextPlural && donot<2) wrd = this.make_plural(wrd);
	}
	return wrd;
};
this.handleFieldCombiners = function(wrd,markShift,rec)
{
	var last = 0;
	var z = wrd.indexOf("[");
	var y = wrd.charAt(z+1);
	var x = this.fields[y-1][markShift];
	var w = this.getField(x,last,rec);
	wrd = wrd.replace(/\[\d\]/,w[0]);
	last = w[1];
	if(rec<5){
		if(/\[\d\]/g.test(w[0])){
			rec++;
			wrd = this.handleFieldCombiners(wrd,markShift,rec);
		}
		rec--;
		if(/\[\d\]/g.test(wrd)){
			rec++;
			wrd = this.handleFieldCombiners(wrd,markShift,rec);
		}
		rec--;
	} else {
		if(this.recGuard){
			if(typeof(Script)==='undefined') alert("Warning!\n\nFieldCombiner recursion depth limit reached.\n\nwrd:"+wrd+" : "+x+" : "+y+" : "+z+" : "+rec);
			else log(this.name,"Warning! - FieldCombiner recursion depth limit reached.\n\nwrd:"+wrd+" : "+x+" : "+y+" : "+z+" : "+rec);
		}
	}
	return wrd;
};
this.handleNV = function(word,markTense,nextPlural,markShift){
	var wr = word.split(" ");
	var n = wr.length;
	for(var i=0;i<n;i++){
		var wrd = wr[i];
		// field combiner
		if(/\[\d\]/g.test(wrd)) wrd = this.handleFieldCombiners(wrd,markShift,0);
		// Verbs, nouns
		var c = wrd.split(" ");
		if(c.length>1){
			var cc = c.length;
			for(var o=0;o<cc;o++){
				c[o] = this.handleRules(c[o],markTense,nextPlural,markShift,cc);
			}
			wrd = c.join(" ");
		} else wrd = this.handleRules(wrd,markTense,nextPlural,markShift,n);
		wrd = wrd.replace(/&$/,"");
		wr[i] = wrd;
	}
	word = wr.join(" ");
	return word;
};
this.compareConditions = function(w,c,v,a)
{
	switch(c){
		case "<":
			if(a<2){
				if(this.specials.currentSystem[w]<v) return true;
			} else if(this.specials.rndSystem[this.lastSys][w]<v) return true;
			break;
		case ">":
			if(a<2){
				if(this.specials.currentSystem[w]>v) return true;
			} else if(this.specials.rndSystem[this.lastSys][w]>v) return true;
			break;
		case ":":
			if(a<2){
				if(this.specials.currentSystem[w]==v) return true;
			} else if(this.specials.rndSystem[this.lastSys][w]==v) return true;
			break;
		case "!":
			if(a<2){
				if(this.specials.currentSystem[w]!=v) return true;
			} else if(this.specials.rndSystem[this.lastSys][w]!=v) return true;
			break;
	}
	return false;
};
this.parseConditions = function(wrd,remB)
{
	var left = false, right = false, compare = 1, w = wrd.split(")");
	var wl = w.length;
	for(var q=0;q<wl;q++){
		var ex = w[q].match(/\(/g);
		if(ex){
			var exl = ex.length;
			for(var i=0;i<exl;i++){
				compare = 1;
				var con = w[q].match(/\(.*/);
				var act = con[0].split("="); // split conditions from actions (Sg:0,e<5 [4]|[7]
				switch(act[0].charAt(1)){ // A,B,D,P,S,Y
					case "A": compare = 5; break;
					case "B": compare = 3; break;
					case "D": compare = 4; break;
					case "S":
						compare = 2;
						// prepare @S
						if(this.lastSys<0) var sys = this.getRNDSystem();
						break;
					case "Y": compare = 6; break;
				}
				// conditions
				switch(compare){
					case 1:
					case 2:
						var c = act[0].substr(2).split(","); // multiple conditions
						var cl = c.length;
						for(var u=0;u<cl;u++){
							var cx = c[u][1], cy = c[u].substr(2), cz;
							switch(c[u][0]){
								case "c": cz = "productivity"; break;
								case "d":
									var reg = new RegExp(cy,"g");
									if(compare===1) left = reg.test(this.specials.currentSystem.description);
									else left = reg.test(this.specials.rndSystem[this.lastSys].description);
									if(cx==='!') left = !left;
									break;
								case "e": cz = "economy"; break;
								case "g": cz = "government"; break;
								case "i":
									var reg = new RegExp(cy,"gi");
									if(compare===1) left = reg.test(this.specials.currentSystem.inhabitant);
									else left = reg.test(this.specials.rndSystem[this.lastSys].inhabitant);
									if(cx==='!') left = !left;
									break;
								case "p": cz = "population"; break;
								case "r": cz = "radius"; break;
								case "s": cz = "sun"; break;
								case "t": cz = "techlevel"; break;
							}
							if(cz) left = this.compareConditions(cz,cx,cy,compare);
							if(!left) break;
						}
						break;
					case 3: //Bits
						var c = act[0].substr(2);
						var bitID = parseInt(c)%30;
						if(act.length<2){
							if(c[c.length-1]==="+"){
								this.bits |= (1<<bitID);
								left = true;
							} else if(c[c.length-1]==="-"){
								this.bits &= ~(1<<bitID);
								left = true;
							}
						}
						if((this.bits&(1<<bitID))!=0) left = true;
						break;
					case 4: //Dice
						var c = act[0].substr(2);
						if(act.length<2){
							var ns = c.split(",");
							right = this.rnd_range(+ns[0],+ns[1],+ns[2]);
							left = true;
						} else {
							if(c>Math.floor(Math.random()*100)) left = true;
						}
						break;
					case 5: //All
						var c = parseInt(act[0].substr(2));
						if((this.bits&c)===c) left = true;
						break;
					case 6: //Any
						var c = parseInt(act[0].substr(2));
						if(this.bits&c) left = true;
						break;
				}
				// actions
				if(act.length>1){
					var acc = act[1].split("|");
					if(!left){
						if(acc.length>1) right = acc[1];
					} else right = acc[0];
				}
				if(right) w[q] = w[q].replace(/\(.*/,right);
				else w[q] = w[q].replace(/\(.*/,"");
			}
		}
	}
	wrd = w.join("");
	if(remB) wrd = wrd.replace(/[\[\]]/g,"");
	return wrd;
};
this.getField = function(field,last,rec)
{
	var sp = this.stdObj[field].length;
	var r = this.random(sp);
	if(this.salt) r = ((0x357941*this.salt)>>16)%sp;
	else if(r===last) r = this.random(sp);
	if(rec){
		if(rec===5) r = sp-1;
		else r = (r+rec)%sp;
	}
	var wrd = this.stdObj[field][r];
	if(/\([ABDPSY]/g.test(wrd)) wrd = this.parseConditions(wrd);
	return([wrd,r]);
};
this.getRNDSystem = function()
{
	var sp = this.specials.rndSystem.length;
	if(this.salt) r = ((0x357941*this.salt)>>16)%sp;
	else {
		var r = this.random(sp);
		var reselect = 0;
		while(r===this.lastSys){
			r = this.random(sp);
			reselect++;
			if(reselect>10) break;
		}
	}
	this.lastSys = r;
	return r;
};
this.buildPhrase = function(OXPPattern,store,sd,cst,cpf,foo)
{
	var pattern, cp = -1;
	if(sd) sd = sd&0x1ff;
	if(OXPPattern){
		if(typeof(OXPPattern)==='object'){
			cp = this.random(OXPPattern.length);
			pattern = OXPPattern[cp];
		} else {
			cp = 0;
			pattern = OXPPattern;
		}
	} else {
		if(sd){
			var sp = this.stdObj.sentences.length;
			cp = ((0x357941*sd)>>16)%sp;
		} else cp = this.random(this.stdObj.sentences.length);
		pattern = this.stdObj.sentences[cp];
	}
	var aFlag = 0, markShift = 0, markTense = 0, nextPlural = 0, nextSpecial = 0, nextUpper = 1;
	var lastA = -1, lastB = -1, lastC = -1, lastD = -1, lastE = -1, lastF = -1, lastG = -1, lastH = -1, lastI = -1;
	var info = {num:""}, za = [], zb = 0, zc = [], zd = 0, wOffset = 0, sFlag = 0;
	if(!foo){
		this.lastSys = -1; this.salt = (sd?sd:0)&0x1ff; this.bits = 0; this.limitCross = 0;
		if(this.stdObj.custom && this.stdObj.custom.length){
			if(!cst) this.bits = this.stdObj.custom[0];
			else {
				this.bits = cst[0];
				this.stdObj.custom = cst;
			}
		}
		var lasts = {rndBrewName:[],rndFirstName:[],rndSurName:[],rndShipName:[],rndSystem:[],rndTitle:[],lastWords:[]};
	} else {
		var lasts = foo;
		wOffset = foo.lastWords.length;
	}
	if(/\([ABDPSY]/g.test(pattern)){
		za = pattern.match(/\([a-zA-Z0-9,:!><=\)\[\]\| @\+-_\{\}]+\)/g);
		pattern = pattern.replace(/\([a-zA-Z0-9,:!><=\)\[\]\| @\+-_\{\}]+\)/g,"@?");
	}
	if(/\[[a-zA-Z_]+\]/g.test(pattern)){
		zc = pattern.match(/\[[a-zA-Z_]+\]/g);
		pattern = pattern.replace(/\[[a-zA-Z_]+\]/g,"@[");
	}
	pattern = pattern.split(" ");
	var denpat = pattern.length, r = -1, tmp = null;
	for(var p=0;p<denpat;p++){
		var lenpat = pattern[p].length, txt = "", wrd = "", pushit = 0;
		for (var ichr = 0; ichr < lenpat; ichr++){
			var chr = pattern[p].charAt(ichr);
			if(!nextSpecial){
				switch(chr){
					case '@': nextSpecial = 1; continue;
					case '1':
						tmp = this.getField(this.fields[0][markShift],lastA);
						wrd = tmp[0]; lastA = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '2':
						tmp = this.getField(this.fields[1][markShift],lastB);
						wrd = tmp[0]; lastB = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '3':
						tmp = this.getField(this.fields[2][markShift],lastC);
						wrd = tmp[0]; lastC = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '4':
						tmp = this.getField(this.fields[3][markShift],lastD);
						wrd = tmp[0]; lastD = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '5':
						tmp = this.getField(this.fields[4][markShift],lastE);
						wrd = tmp[0]; lastE = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '6':
						tmp = this.getField(this.fields[5][markShift],lastF);
						wrd = tmp[0]; lastF = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '7':
						tmp = this.getField(this.fields[6][markShift],lastG);
						wrd = tmp[0]; lastG = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '8':
						tmp = this.getField(this.fields[7][markShift],lastH);
						wrd = tmp[0]; lastH = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '9':
						tmp = this.getField(this.fields[8][markShift],lastI);
						wrd = tmp[0]; lastI = tmp[1]; pushit = 1;
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						break;
					case '.': wrd = chr; nextUpper = 2; break;
					case '!': wrd = chr; nextUpper = 2; break;
					case '?': wrd = chr; nextUpper = 2; break;
					case '#': markTense = 1; continue;
					case '_': markTense = 2; continue;
					case '^': markTense = 3; continue;
					case '*': markTense = 4; continue;
					case '>': nextPlural = 1; continue;
					case '<': nextPlural = 0; continue;
					case '|': nextPlural = (Math.random()>0.5?1:0); continue;
					case '+': nextUpper = 1; continue;
					case '{': markShift = 1; continue;
					case '}': markShift = 0; continue;
					default: wrd = chr;
				}
				if(pushit && store){
					if(info[p]) info[p] += wrd;
					else info[p] = wrd;
				}
				markTense = 0; nextPlural = 0;
			} else { // @
				var where = "", sys = false, ovr = false, spc;
				switch(chr){
					case 'a':
						r = this.random(this.specials.idsA.length);
						wrd = this.specials.idsA[r];
						if(store) info.num += wrd;
						break;
					case 'B': wrd = this.specials.commanderBounty; break;
					case 'b':
						r = this.random(this.specials.idsB.length);
						wrd = this.specials.idsB[r];
						if(store) info.num += wrd;
						break;
					case 'C': wrd = this.specials.commanderName; break;
					case 'c':
						r = this.random(this.specials.idsC.length);
						wrd = this.specials.idsC[r];
						if(store) info.num += wrd;
						break;
					case 'D': wrd = this.specials.currentShipDisplayName; break;
					case 'd': wrd = String(clock.days-Math.floor(Math.random()*7)); break;
					case 'F':
						where = "rndFirstName";
						break;
					case 'f':
						if(lasts.rndFirstName.length){
							if(+pattern[p].charAt(ichr+1)+1){ // trickery
								wrd = lasts.rndFirstName[+pattern[p].charAt(ichr+1)];
								ichr++;
							} else wrd = lasts.rndFirstName[lasts.rndFirstName.length-1];
						} else where = "rndFirstName";
						break;
					case 'h':
						if(this.lastSys<0) r = this.getRNDSystem();
						wrd = this.specials.rndSystem[this.lastSys].inhabitant.toLowerCase();
						lasts.lastWords.push(wrd);
						if(store) info.lastInhabitant = wrd;
						break;
					case 'I': wrd = this.specials.currentShipName; break;
					case 'i':
						if(lasts.rndShipName.length){
							if(+pattern[p].charAt(ichr+1)+1){ // trickery
								wrd = lasts.rndShipName[+pattern[p].charAt(ichr+1)];
								ichr++;
							} else wrd = lasts.rndShipName[lasts.rndShipName.length-1];
						} else where = "rndShipName";
						break;
					case 'L': wrd = this.specials.commanderStatus; break;
					case 'N':
						where = "rndSurName";
						break;
					case 'n':
						if(lasts.rndSurName.length){
							if(+pattern[p].charAt(ichr+1)+1){ // trickery
								wrd = lasts.rndSurName[+pattern[p].charAt(ichr+1)];
								ichr++;
							} else wrd = lasts.rndSurName[lasts.rndSurName.length-1];
						} else where = "rndSurName";
						break;
					case 'P':
						wrd = this.specials.currentSystem.name;
						if(store) info.currentSystemName = wrd;
						break;
					case 'R': wrd = this.specials.commanderRank; break;
					case 'S':
						sys = true;
						ovr = true;
						where = "rndSystem";
						break;
					case 's':
						sys = true;
						where = "rndSystem";
						break;
					case 'T': wrd = this.specials.currentTarget; break;
					case 'W':
						wrd = this.parseConditions("(Si:human=[CCL_Names]|[CCL_NamesOther])");
						if(this.limitCross<3){
							this.limitCross++;
							var ww = stdObj;
							this.stdObj = this.pool[wrd.substr(1,wrd.length-2)];
							wrd = this.buildPhrase(null,0,sd,0,0,lasts);
							if(!this.stdObj.splitRules) lasts.lastWords.push(wrd);
							this.stdObj = ww;
							if(store) info[p] = wrd;
							this.limitCross--;
						}
						break;
					case 'X':
						if(this.lastSys<0) r = this.getRNDSystem();
						break;
					case 'Y':
						if(this.stdObj.custom){
							if(+pattern[p].charAt(ichr+1)+1){ // trickery
								wrd = this.stdObj.custom[+pattern[p].charAt(ichr+1)];
								ichr++;
							}
						}
						break;
					case 'Z':
						where = "rndBrewName";
						break;
					case 'z':
						if(lasts.rndBrewName.length){
							if(+pattern[p].charAt(ichr+1)+1){ // trickery
								wrd = lasts.rndBrewName[+pattern[p].charAt(ichr+1)];
								ichr++;
							} else wrd = lasts.rndBrewName[lasts.rndBrewName.length-1];
						} else where = "rndBrewName";
						break;
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						if(foo){
							if(lasts.lastWords.length>chr) wrd = lasts.lastWords[+chr+wOffset];
						} else {
							if(lasts.lastWords.length>chr) wrd = lasts.lastWords[+chr];
						}
						break;
					case '?':
						wrd = this.parseConditions(za[zb]);
						if(wrd.charAt(0)===" "){
							spc = 1;
							wrd = wrd.trim();
						}
						if(/\[\d\]/.test(wrd)) wrd = this.handleFieldCombiners(wrd,markShift,0);
						wrd = this.handleNV(wrd,markTense,nextPlural,markShift);
						if(this.limitCross<3 && /\[[a-zA-Z_]+\]/.test(wrd)){
							var zl = wrd.substr(1,wrd.length-2);
							if(this.pool[zl]){
								this.limitCross++;
								var ww = stdObj;
								this.stdObj = this.pool[zl];
								wrd = this.buildPhrase(null,0,sd,0,0,lasts);
								if(!this.stdObj.splitRules) lasts.lastWords.push(wrd);
								this.stdObj = ww;
								if(store) info[p] = wrd;
								wOffset = 0;
								this.limitCross--;
							}
						} else if(/[\{\}]/.test(wrd)){
							if(wrd==="{") markShift = 1;
							if(wrd==="}") markShift = 0;
							wrd = wrd.substr(1);
						} else {
							if(this.limitCross>2){
								if(this.recGuard){
									if(typeof(Script)==='undefined') alert("Warning!\n\nSample recursion depth limit reached.\n\n"+zl);
									else log(this.name,"Warning! - Sample recursion depth limit reached. "+zl);
								}
							}
							if(!this.stdObj.splitRules) if(wrd) lasts.lastWords.push(wrd);
						}
						if(spc) wrd = " "+wrd;
						zb++;
						break;
					case '[':
						var zl = zc[zd];
						var zk = zl.substr(1,zl.length-2);
						if(this.limitCross<3 && this.pool[zk]){
							this.limitCross++;
							var ww = stdObj;
							this.stdObj = this.pool[zk];
							wrd = this.buildPhrase(null,0,sd,0,0,lasts);
							if(!this.stdObj.splitRules) lasts.lastWords.push(wrd);
							this.stdObj = ww;
							if(store) info[p] = wrd;
							this.limitCross--;
						} else {
							if(this.limitCross>2){
								if(this.recGuard){
									if(typeof(Script)==='undefined') alert("Warning!\n\nSample recursion depth limit reached.\n\n"+zl);
									else log(this.name,"Warning! - Sample recursion depth limit reached. "+zl);
								}
								wrd = zl;
							}
						}
						zd++;
						break;
					default: wrd = chr;
				}
				if(where){
					if(sys){
						if(ovr || (sys && this.lastSys<0)) r = this.getRNDSystem();
						wrd = this.specials[where][this.lastSys].name;
						if(nextPlural){
							wrd = this.make_plural(wrd);
							nextPlural = 0;
						}
					} else {
						r = this.random(this.specials[where].length);
						wrd = this.specials[where][r];
					}
					lasts[where].push(wrd);
				}
				if(wrd && wrd[0]==="@"){
					pattern[p] = pattern[p].replace(/@\?/,wrd);
					p--;
					nextSpecial = 0;
					continue;
				}
				nextSpecial = 0;
			}
			if(nextUpper){
				if(nextUpper>1) nextUpper--;
				else {
					wrd = this.initial_cap(wrd);
					nextUpper = 0;
				}
			}
			txt += wrd;
		}
		pattern[p] = txt;
		if(txt.length===1){
			if(txt==="a") aFlag = 1;
			else if(txt==="A") aFlag = 2;
			else aFlag = 0;
		} else {
			if(aFlag){
				if(typeof(this.superlatives[txt])!=='undefined'){
					var rep = pattern[p-1].split(" ");
					if(aFlag>1) rep[rep.length-1] = "The";
					else rep[rep.length-1] = "the";
					pattern[p-1] = rep.join(" ");
				} else {
					if(/^[FHLMNRSX][A-Z]/.test(txt)) pattern[p-1] = pattern[p-1]+"n"; // a -> an
					else if(/^u/i.test(txt)){
						if(/^u[^aeiou\d\s][^aeiou\d\s]/i.test(txt)) pattern[p-1] = pattern[p-1]+"n"; // a -> an
						else if(/^un[aeou]/i.test(txt)) pattern[p-1] = pattern[p-1]+"n"; // a -> an
						else if(/^uni/i.test(txt) && /^unim|(?:ive|ble)$/i.test(txt)) pattern[p-1] = pattern[p-1]+"n"; // a -> an
					} else {
						if(/^(?:[aei]|o[^ne]|ho(?:ur|nest|no|mage|mbre|rs d')|he(?:ir|rb))/i.test(txt)) pattern[p-1] = pattern[p-1]+"n"; // a -> an
					}
				}
				aFlag = 0;
			} else if(/\ba\b$/.test(txt)) aFlag = 1;
		}
	}
	if(!foo || (foo && this.limitCross===1)){
		if(this.stdObj.splitRules){
			switch(this.stdObj.splitRules[cp]){
				case 1:
					lasts.rndFirstName.push(pattern[0]);
					lasts.rndSurName.push(pattern[1]);
					lasts.rndTitle.push("");
					break;
				case 2:
					lasts.rndSurName.push(pattern[0]);
					lasts.rndFirstName.push("");
					lasts.rndTitle.push("");
					break;
				case 3:
					lasts.rndFirstName.push(pattern[0]);
					lasts.rndTitle.push(pattern[1]);
					lasts.rndSurName.push(pattern[2]);
					break;
				case 4:
					lasts.rndTitle.push(pattern[0]);
					lasts.rndFirstName.push(pattern[1]);
					lasts.rndSurName.push(pattern[2]);
					break;
				case 21:
					lasts.rndShipName.push(pattern.join(" "));
					break;
				case 22:
					lasts.rndBrewName.push(pattern.join(" "));
					break;
			}
		}
	}
	var fin = pattern.join(" ");
	if(cpf){
		if(store){
			info.store = lasts;
			info.bits = parseInt(this.bits);
			return([fin,info,cp,lasts]);
		} else return([fin,cp,lasts]);
	}
	if(store){
		info.store = lasts;
		info.bits = parseInt(this.bits);
		return([fin,info]);
	}
	return fin;
};
}).call(this);
