// **********************************************
// * Terra Incognita Random Character Generator *
// * By Scott Larson							*
// * Inspired by "D.I.Y Random Names on the Web"*
// * by L. Lockwood in Pyramid Magazine			*
// * PickSkill() function by Bill Hamilton		*
// * Advice from Ronald Pyatt and Darren Hill	*
// * Begun on January 1, 2003                   *
// **********************************************

// Gifts
var gifts = new Array("Absolute Direction", "Acute Memory", "Acute Sense", "Alertness", "Ambidexterity", "Animal Empathy", "Attractive", "Charisma", "Combat Reflexes", "Common Sense", "Contacts", "Cultural Adaptability", "Damage Resistance", "Danger Sense", "Favors Due", "Intuition", "Knack", "Lucky", "Pain Tolerance", "Perfect Timing", "Privileged Upbringing", "Rapid Healing");

// Faults
var faults = new Array("Absent Minded", "Addiction", "Blunt and Tactless", "Combat Paralysis", "Compulsion", "Cowardice", "Curious", "Damage Prone", "Dependent", "Deprived Upbringing", "Favors Owed", "Mental Challenge", "Nemesis", "Obsession", "Pain Intolerant", "Phobia", "Physical Challenge", "Quixotic", "Reputation", "Secret", "Show-off", "Temper", "Unattractive", "Unlucky");

// Fault checking arrays: Mutually exclusive gifts and faults
// These Arrays must parallel one another (match gift with exclusive fault)
faultCheck1 = new Array("Attractive", "Combat Reflexes", "Damage Resistance", "Privileged Upbringing", "Lucky", "Pain Tolerance"); // Gifts with opposites
faultCheck2 = new Array("Unattractive", "Combat Paralysis", "Damage Prone", "Deprived Upbringing", "Unlucky", "Pain Intolerant");

// skill group titles, which parallels the skillGroups array
var skillGroupTitles = new Array("Athletic", "Combat", "Investigation", "Knowledge", "Outre", "Social", "Technical", "Vocational"); // The opposites of above gifts, in parallel

// skill groups and skills
var skillGroups = new Array();

skillGroups[0] = new Array("Acrobatics","Boating","Camouflage","Climbing","Diving","Jumping","Riding","Running","Survival (specific)","Swimming","Throwing","Tracking");

skillGroups[1] = new Array("Acrobatics", "Archery", "Blowgun", "Dodge", "Firearm (specific)", "Heavy Weapons", "Melee Weapon (specific)", "Quick Draw", "Tactics", "Thrown Weapon", "Traps", "Unarmed Combat");

skillGroups[2] = new Array("Camouflage", "Discern", "Disguise", "Forgery", "Legerdemain", "Lock Picking", "Photography", "Stealth", "Surveillance", "Tracking", "Traps", "Ventriloquism");

skillGroups[3] = new Array("Academic (specific)", "Area Knowledge (specific)", "Cartography", "Computing", "Familiarity (specific)", "History (specific)", "Religion (specific)", "Language (specific)", "Medical (modern or traditional)", "Profession (specific)", "Research", "Science (specific)");

skillGroups[4] = new Array("Computing", "Cryptography", "Cryptohistory", "Cryptozoology", "Gadgeteer", "Hypnotism", "Lock Picking", "Meditation", "Occult", "Research", "Thanatology", "Toxicology");

skillGroups[5] = new Array("Bargain", "Diplomacy", "Discern", "Dissemble", "Etiquette", "Flirt", "Interrogate", "Oratory", "Persuade", "Savoir-Faire", "Surveillance", "Wit");

skillGroups[6] = new Array("Communications", "Computing", "Demolitions", "Driving (specific)", "Gadgeteer", "Mechanic", "Navigation", "Parachute/Paraglider", "Photography", "Pilot (specific)");

skillGroups[7] = new Array("Animal Handling", "Animal Training", "Art (specific)", "Craft (specific)", "Gambling", "Games (specific)", "Legerdemain", "Mechanic", "Photography", "Profession (specific)", "Stage Magic", "Trade (specific)");

// Roll a random number from 1 to num
function Random1(num) {
	return Math.floor(Math.random() * num) + 1;
	} // End Random1()

// Roll a random number from 0 to num
function Random0(num) {
	return Math.floor(Math.random() * num);
	} // End Random0()
	
// Roll a random element of an array
function Roll(arrayName) {
	return arrayName[Math.round(Math.random() * (arrayName.length - 1))];
	} // End Roll()

// Pick Attribute
function PickAttribute() {
	var x = Random1(6) + Random1(6) // Simulates 2d6
	switch (x) {
		case (x = 2):
			var attribute = "Terrible";
			return attribute;
			break;
		case (x = 3):
			var attribute = "Poor";
			return attribute;
			break;
		case (x = 4):
			var attribute = "Mediocre";
			return attribute;
			break;
		case (x = 5):
			var attribute = "Fair";
			return attribute;
			break;
		case (x = 6):
			var attribute = "Fair";
			return attribute;
			break;
		case (x = 7):
			var attribute = "Fair";
			return attribute;
			break;
		case (x = 8):
			var attribute = "Fair";
			return attribute;
			break;
		case (x = 9):
			var attribute = "Fair";
			return attribute;
			break;
		case (x = 10):
			var attribute = "Good";
			return attribute;
			break;
		case (x = 11):
			var attribute = "Great";
			return attribute;
			break;
		case (x = 12):
			var attribute = "Superb";
			return attribute;
			break;
		default:
			document.write("Error!");
		} // end switch
	} // end PickAttribute

// Initialize nonoFault array and counter
var nonoFault = new Array(4); // large enough to hold 4 faults (2 excluded by gifts and the 2 you picked)
var nf = 0; // a counter

// Pick 2 faults, with no repeats and no mutually exclusives
function PickFaults() {
	for (var i=0; i<faultCheck1.length; i++) { // stuff nonoFault with excluded faults,
		if (gift1 == faultCheck1[i]) { // if there are any
			nonoFault[nf] = faultCheck2[i];
			nf++;
			} // end if
		if (gift2 == faultCheck1[i]) {
			nonoFault[nf] = faultCheck2[i];
			nf++;
			} // end if
		} // end for
	var notMatched = 1; // entry condition for while() loop
	while (notMatched !=0) { // if it doesn't match, continue
		var fault1 = Roll(faults); // roll first fault
		notMatched = 0; // assume it's not on nono list
		for (var i=0; i<nonoFault.length; i++) {
			if (fault1 == nonoFault[i]) notMatched = 1; // if it's on nono list, set flag
			} // end for
		} // end while
	nonoFault[nf] = fault1; // add this new fault to the nono list
	nf++; // increment the counter in case anybody wants to do more faults
	var notMatched = 1; // do it all again for second fault
	while (notMatched !=0) {
		var fault2 = Roll(faults);
		notMatched = 0;
		for (var i=0; i<nonoFault.length; i++) {
			if (fault2 == nonoFault[i]) notMatched = 1;
			} // end for
		} // end while
	nonoFault[nf] = fault2; // add this new fault to the nono list
	nf++; // increment the counter in case anybody wants to do more faults
 	document.write("<h3> Faults </h3>");
	document.write(fault1 + "<br>");
	document.write(fault2 + "<br>");
	} // end PickFaults()

// Initialize "Already Picked" counters
var groupPicked = new Array(8);
var skillPicked = new Array(96);
var gp = 0; // Group already picked counter
var sp = 0; // Skill already picked counter

// Pick a random skill group
function PickGroup() {
	var notMatched = 1;         // entry condition for while() loop.
	while (notMatched !=0){     // if it doesn't get a match, it's ok to continue
		var randomGroup = Random0(7);  // generate a random group
		notMatched = 0;                     // assume the skill isn't matched yet
		for (i = 0; i<groupPicked.length; i++) {
			if (randomGroup == groupPicked[i]) notMatched = 1;// if it matches this group, set the flag                              
			}// end for
		}// end while
 // only get here if the group doesn't match any list entries.
	groupPicked[gp] = randomGroup;  // add the group
    gp++; // increment the counter.
          // (shouldn't this increment skillPicked.length instead?)
    return randomGroup;    // return the skill
}// end PickGroup

// Pick a random skill
function PickSkill(arrayName) {
	var notMatched = 1;         //entry condition for while() loop.
	while (notMatched !=0){     //if it doesn't get a match, it's ok to continue
		var randomSkill = Roll(arrayName);  //generate a random skill
		notMatched = 0;                     //assume the skill isn't matched yet
		for (i = 0; i<skillPicked.length; i++) {
			if (randomSkill == skillPicked[i]) notMatched = 1;//if it matches this skill, set the flag                              
		}//end for
	}//end while
 //only get here if the skill doesn't match any list entries.
	skillPicked[sp]=randomSkill;  //add the skill
    sp++; //increment the counter.
          //(shouldn't this increment skillPicked.length instead?)
    return randomSkill;    //return the skill.
}//end PickSkill

// Function: Four Skill Points
function FourSP() {
	var theGroupNumber = PickGroup();
	var theGroupName = skillGroupTitles[theGroupNumber];
	var theGroup = skillGroups[theGroupNumber];
	document.write("<h3>" + "<i>" + "-- " + theGroupName + " Skills: 4 pts. --" + "</h3>" + "</i>");
	document.write(PickSkill(theGroup) + " : Superb" + "<br>");
	document.write(PickSkill(theGroup) + " : Great" + "<br>");
	document.write(PickSkill(theGroup) + " : Great" + "<br>");
	document.write(PickSkill(theGroup) + " : Good" + "<br>");
	document.write(PickSkill(theGroup) + " : Good" + "<br>");
	document.write(PickSkill(theGroup) + " : Good" + "<br>");
	document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	} // End FourSP

// Function: Three Skill Points
function ThreeSP() {
	var theGroupNumber = PickGroup();
	var theGroupName = skillGroupTitles[theGroupNumber];
	var theGroup = skillGroups[theGroupNumber];
	document.write("<h3>" + "<i>" + "-- " + skillGroupTitles[theGroupNumber] + " Skills: 3 pts. --" + "</h3>" + "</i>");
	document.write(PickSkill(theGroup) + " : Great" + "<br>");
	document.write(PickSkill(theGroup) + " : Good" + "<br>");
	document.write(PickSkill(theGroup) + " : Good" + "<br>");
	document.write(PickSkill(theGroup) + " : Good" + "<br>");
	document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	} // End ThreeSP

// Function: Two Skill Points
function TwoSP() {
	// Determine focus
	switch(Random1(2)) {

	// Two skill points, broad focus
	case 1:
		var theGroupNumber = PickGroup();
		var theGroupName = skillGroupTitles[theGroupNumber];
		var theGroup = skillGroups[theGroupNumber];
		document.write("<h3>" + "<i>" + "-- " + skillGroupTitles[theGroupNumber] + " Skills: 2 pts. (broad focus) --" + "</h3>" + "</i>");
		document.write(PickSkill(theGroup) + " : Good" + "<br>");
		document.write(PickSkill(theGroup) + " : Good" + "<br>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	break;

	// Two skill points, narrow focus
	case 2:
		var theGroupNumber = PickGroup();
		var theGroupName = skillGroupTitles[theGroupNumber];
		var theGroup = skillGroups[theGroupNumber];
		document.write("<h3>" + "<i>" + "-- " + skillGroupTitles[theGroupNumber] + " Skills: 2 pts. (narrow focus) --" + "</h3>" + "</i>");
		document.write(PickSkill(theGroup) + " : Good" + "<br>");	
		document.write(PickSkill(theGroup) + " : Good" + "<br>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
	break;
	default:
		document.write("Error!");
		} // End switch
	} // End TwoSP

// Function: One Skill Point
function OneSP() { 
	// Determine focus
	switch(Random1(2)) {

	// One skill point, broad focus
	case 1:
		var theGroupNumber = PickGroup();
		var theGroupName = skillGroupTitles[theGroupNumber];
		var theGroup = skillGroups[theGroupNumber];
		document.write("<h3>" + "<i>" + "-- " + skillGroupTitles[theGroupNumber] + " Skills: 1 pt. (broad focus) --" + "</h3>" + "</i>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
		document.write(PickSkill(theGroup) + " : Fair" + "<br>");
		document.write(PickSkill(theGroup) + " : Mediocre" + "<br>");
	break;

	// One skill point, narrow focus
	case 2:
		var theGroupNumber = PickGroup();
		var theGroupName = skillGroupTitles[theGroupNumber];
		var theGroup = skillGroups[theGroupNumber];
		document.write("<h3>" + "<i>" + "-- " + skillGroupTitles[theGroupNumber] + " Skills: 1 pt. (narrow focus) --" + "</h3>" + "</i>");
		document.write(PickSkill(theGroup) + " : Good" + "<br>");
		document.write(PickSkill(theGroup) + " : Mediocre" + "<br>");
	break;
	default:
		document.write("Error!");
	} // End switch
} // End OneSP
	
// Begin body

// Attributes
document.write("<h3> Attributes </h3>");
document.write("Perception: " + PickAttribute() + "<br>");
document.write("Reasoning: " + PickAttribute() + "<br>");
document.write("Resolve: " + PickAttribute() + "<br>");
document.write("Strength: " + PickAttribute() + "<br>");
document.write("Dexterity: " + PickAttribute() + "<br>");
document.write("Vigor: " + PickAttribute() + "<br>");

// Gifts
document.write("<h3> Gifts </h3>");
 var gift1 = Roll(gifts);
var gift2 = Roll(gifts);
while (gift2 == gift1) {
	gift2 = Roll(gifts);
	} //end while
document.write(gift1 + "<br>");
document.write(gift2 + "<br>");

// Faults
PickFaults();

// Skills
document.write("<h3> Skills </h3>");
switch(Random1(6)) {

	case 1: // Skill points: 4, 1
		FourSP();
		OneSP();
	break;

	case 2: // Skill points: 3, 2
		ThreeSP();
		TwoSP();
		break;

	case 3: // Skill points 3, 1, 1
		ThreeSP();
		OneSP();
		OneSP();
	break;

	case 4: // Skill points: 2, 2, 1
		TwoSP();
		TwoSP();
		OneSP();
	break;

	case 5: // Skill points: 2, 1, 1, 1
		TwoSP();
		OneSP();
		OneSP();
		OneSP();
	break;

	case 6: // Skill points: 1, 1, 1, 1, 1
		OneSP();
		OneSP();
		OneSP();
		OneSP();
		OneSP();
	break;

	default:
		document.write("Error!");
	} // End switch