  //update overall summary of skill status
  function updateSummary() {
    calcTopSkill();
    allArmorRank = 0;
    allWeaponRank = 0;
    allSurvivalRank = 0;
    allMagicRank = 0;
    allLoreRank = 0;
    grandTotalRank = 0;
    tdpTotal = 0;
    for (sumstep=0; sumstep<totalArmorRank; sumstep++) {
      sumSkillTemp = getSkill(allArmor[sumstep]);
      tdpTotal = tdpTotal + tdpCalc(sumSkillTemp);
      allArmorRank = allArmorRank + sumSkillTemp;
    }
    for (sumstep=0; sumstep<totalWeaponRank; sumstep++) {
      sumSkillTemp = getSkill(allWeapon[sumstep]);
      tdpTotal = tdpTotal + tdpCalc(sumSkillTemp);
      allWeaponRank = allWeaponRank + sumSkillTemp;
    }
    for (sumstep=0; sumstep<totalSurvivalRank; sumstep++) {
      sumSkillTemp = getSkill(allSurvival[sumstep]);
      tdpTotal = tdpTotal + tdpCalc(sumSkillTemp);
      allSurvivalRank = allSurvivalRank + sumSkillTemp;
    }
    for (sumstep=0; sumstep<totalMagicRank; sumstep++) {
      sumSkillTemp = getSkill(allMagic[sumstep]);
      tdpTotal = tdpTotal + tdpCalc(sumSkillTemp);
      allMagicRank = allMagicRank + sumSkillTemp;
    }
    for (sumstep=0; sumstep<totalLoreRank; sumstep++) {
      sumSkillTemp = getSkill(allLore[sumstep]);
      tdpTotal = tdpTotal + tdpCalc(sumSkillTemp);
      allLoreRank = allLoreRank + sumSkillTemp;
    }
    tdpTotal = Math.floor(tdpTotal/200);
    grandTotalRank = allArmorRank + allWeaponRank + allSurvivalRank + allMagicRank + allLoreRank;
    finalSummary = "You have " + grandTotalRank + " total ranks.<br>";
    finalSummary = finalSummary + "You have gained " + tdpTotal + " TDP's from skills.<br>";
    finalSummary = finalSummary + "You have " + allArmorRank + " armor ranks.<br>";
    finalSummary = finalSummary + "You have " + allWeaponRank + " weapon ranks.<br>";
    finalSummary = finalSummary + "You have " + allSurvivalRank + " survival ranks.<br>";
    finalSummary = finalSummary + "You have " + allMagicRank + " magic ranks.<br>";
    finalSummary = finalSummary + "You have " + allLoreRank + " lore ranks.<br><br>";
    updateCircleVal = 5000;
    for (listStep=0; listStep<endMark; listStep++) {
      nextHighRank = skillGrid[listStep][9] + 1;
      if (skillGrid[listStep][9] == -1) {
        if (document.form1.legacy.checked == true)
          finalSummary = finalSummary + "You no longer specifically require " + skillGrid[listStep][8] + " to circle.<br>";
      }
      else {
        if (document.form1.legacy.checked == true)
          finalSummary = finalSummary + "+";
        finalSummary = finalSummary + "You have acquired enough " + skillGrid[listStep][8] + " for" + numAppend(skillGrid[listStep][9]) + " circle";
        if (document.form1.extrarank.checked == true)
          finalSummary = finalSummary + " and need " + skillGrid[listStep][11] + " ranks for " + numAppend(nextHighRank);
        finalSummary = finalSummary + ".<br>";
        if (skillGrid[listStep][9] < updateCircleVal)
          updateCircleVal = skillGrid[listStep][9];
      }
//    guildSummary();
    }
    summary.innerHTML = finalSummary;
    circleValOld = updateCircleVal + 1;
    document.form1.circle.value = updateCircleVal + 1;
  }

  //calc tdp's for a skill
  function tdpCalc(calcRank) {
    calcRankTotal = 0;
    calcRankTest1 = calcRank / 2;
    calcRankTest2 = Math.floor(calcRank / 2);
    if (calcRankTest1 != calcRankTest2) {
      calcRankTotal = calcRank;
      calcRank--;
    }
    calcRankTotal = calcRankTotal + ((calcRank + 1) * (calcRank / 2));
    return calcRankTotal;
  }

  //find highest circle achieved for each skill
  function calcTopSkill() {
    topStepCap = circleBreaks[1].length;
    for (topStep1=0; topStep1<endMark; topStep1++) {
      skillTopCalcTemp = skillGrid[topStep1][10];
      circleEnd = 0;
      for (topStep2=0; topStep2<topStepCap; topStep2++) {
        topStepTemp = topStep2 + 1;
        topStepTemp2 = topStep2 + 2;
        skillIncrementReq = skillGrid[topStep1][topStepTemp];
        skillIncrement = Math.floor(skillTopCalcTemp / skillIncrementReq);
        incrementTest1 = circleEnd + skillIncrement;
        incrementTest2 = circleBreaks[1][topStepTemp];
        if (topStepTemp == topStepCap) { // highest circle bracket, just calc it cold
          if (skillIncrementReq == 0)
            circleEnd = -1;
          else {
            skillTopCalcTemp = skillTopCalcTemp - (skillIncrement * skillIncrementReq);
            skillTopCalcTemp = skillIncrementReq - skillTopCalcTemp;
            circleEnd = incrementTest1;
          }
          break;
        }
        if (skillIncrementReq == 0) {
          circleEnd = incrementTest2;
          continue;
        }
        if (incrementTest1 > incrementTest2) {
          circleEnd = incrementTest2;
          skillTopCalcTemp = skillTopCalcTemp - ((incrementTest2 - circleBreaks[1][topStep2]) * skillIncrementReq);
          continue;
        }
        skillTopCalcTemp = skillTopCalcTemp - (skillIncrement * skillIncrementReq);
        circleEnd = incrementTest1;
        if (skillTopCalcTemp != 0) {
          skillTopCalcTemp = skillIncrementReq - skillTopCalcTemp;
          break;
        }
        if (incrementTest1 == incrementTest2) {
          skillTopCalcTemp = skillGrid[topStep1][topStepTemp2];
          break;
        }
        skillTopCalcTemp = skillIncrementReq;
        break;
      }
      skillGrid[topStep1][9] = circleEnd;
      skillGrid[topStep1][11] = skillTopCalcTemp;
    }
    if (document.form1.guild.selectedIndex == 3 && skillGrid[5][6] > 19)
      skillGrid[5][9] = -1;
  }

  //add appropriate suffixes to numbers
  function numAppend(numUsed) {
    numDone = " " + numUsed;
    numTest = Math.floor(numUsed/10);
    numTest = numUsed - (numTest * 10);
    if ((numTest > 3) || (numTest < 1)) {
      numDone = numDone + "th";
      return numDone;
    }
    if ((numUsed > 10) && (numUsed < 14)) {
      numDone = numDone + "th";
      return numDone;
    }
    if (numTest == 1)
      numDone = numDone + "st";
    if (numTest == 2)
      numDone = numDone + "nd";
    if (numTest == 3)
      numDone = numDone + "rd";
    return numDone;
  }

  //gather, sort and total skillsets, move specified number (topSkill) of highest skills to top of list
  function calcArmor() {
    genArmor = 0;
    setMark1 = armorSet[0].length;
    for (step=0; step<setMark1; step++) {
      fixTest = armorSet[0][step].indexOf("+");
      if (fixTest > -1)
        armorSet[0][step] = armorSet[0][step].slice(0,-1);
      armorSet[1][step] = getSkill(armorSet[0][step]);
      genArmor = genArmor + armorSet[1][step];
    }
    if (topArmor == 0) //if no top skills counted, cease calc
      return;
    for (step=0; step<topArmor; step++) { //find highest skill, swap with current top of list
      setMark2 = 0; // temp copy of # of ranks in high skill
      setMark3 = -1; // pointer to name of high skill
      for (step2=step; step2<setMark1; step2++) { //current top of list moves down one with each rep
        if (armorSet[1][step2] > setMark2) {
          setMark2 = armorSet[1][step2];
          setMark3 = step2;
        }
      }
      if (setMark3 > -1) {
        swapTemp1 = armorSet[0][step];
        swapTemp2 = armorSet[1][step];
        armorSet[0][step] = armorSet[0][setMark3];
        armorSet[1][step] = setMark2;
        armorSet[0][setMark3] = swapTemp1;
        armorSet[1][setMark3] = swapTemp2;
        continue;
      }
      if (armorSet[1][step] == 0)
        armorSet[0][step] = armorSet[0][step] + "+";
    }
  }
  function calcWeapon() {
    genWeapon = 0;
    setMark1 = weaponSet[0].length;
    for (step=0; step<setMark1; step++) {
      fixTest = weaponSet[0][step].indexOf("+");
      if (fixTest > -1)
        weaponSet[0][step] = weaponSet[0][step].slice(0,-1);
      weaponSet[1][step] = getSkill(weaponSet[0][step]);
      genWeapon = genWeapon + weaponSet[1][step];
    }
    if (topWeapon == 0)
      return;
    for (step=0; step<topWeapon; step++) {
      setMark2 = 0; // temp copy of # of ranks in high skill
      setMark3 = -1; // pointer to name of high skill
      for (step2=step; step2<setMark1; step2++) {
        if (weaponSet[1][step2] > setMark2) {
          setMark2 = weaponSet[1][step2];
          setMark3 = step2;
        }
      }
      if (setMark3 > -1) {
        swapTemp1 = weaponSet[0][step];
        swapTemp2 = weaponSet[1][step];
        weaponSet[0][step] = weaponSet[0][setMark3];
        weaponSet[1][step] = setMark2;
        weaponSet[0][setMark3] = swapTemp1;
        weaponSet[1][setMark3] = swapTemp2;
      }
      if (weaponSet[1][step] == 0)
        weaponSet[0][step] = weaponSet[0][step] + "+";
    }
  }
  function calcMagic() {
    genMagic = 0;
    setMark1 = magicSet[0].length;
    for (step=0; step<setMark1; step++) {
      fixTest = magicSet[0][step].indexOf("+");
      if (fixTest > -1)
        magicSet[0][step] = magicSet[0][step].slice(0,-1);
      magicSet[1][step] = getSkill(magicSet[0][step]);
      genMagic = genMagic + magicSet[1][step];
    }
    if (topMagic == 0)
      return;
    for (step=0; step<topMagic; step++) {
      setMark2 = 0; // temp copy of # of ranks in high skill
      setMark3 = -1; // pointer to name of high skill
      for (step2=step; step2<setMark1; step2++) {
        if (magicSet[1][step2] > setMark2) {
          setMark2 = magicSet[1][step2];
          setMark3 = step2;
        }
      }
      if (setMark3 > -1) {
        swapTemp1 = magicSet[0][step];
        swapTemp2 = magicSet[1][step];
        magicSet[0][step] = magicSet[0][setMark3];
        magicSet[1][step] = setMark2;
        magicSet[0][setMark3] = swapTemp1;
        magicSet[1][setMark3] = swapTemp2;
      }
      if (magicSet[1][step] == 0)
        magicSet[0][step] = magicSet[0][step] + "+";
    }
  }
  function calcSurvival() {
    genSurvival = 0;
    setMark1 = survivalSet[0].length;
    for (step=0; step<setMark1; step++) {
      fixTest = survivalSet[0][step].indexOf("+");
      if (fixTest > -1)
        survivalSet[0][step] = survivalSet[0][step].slice(0,-1);
      survivalSet[1][step] = getSkill(survivalSet[0][step]);
      genSurvival = genSurvival + survivalSet[1][step];
    }
    if (topSurvival == 0)
      return;
    for (step=0; step<topSurvival; step++) {
      setMark2 = 0; // temp copy of # of ranks in high skill
      setMark3 = -1; // pointer to name of high skill
      for (step2=step; step2<setMark1; step2++) {
        if (survivalSet[1][step2] > setMark2) {
          setMark2 = survivalSet[1][step2];
          setMark3 = step2;
        }
      }
      if (setMark3 > -1) {
        swapTemp1 = survivalSet[0][step];
        swapTemp2 = survivalSet[1][step];
        survivalSet[0][step] = survivalSet[0][setMark3];
        survivalSet[1][step] = setMark2;
        survivalSet[0][setMark3] = swapTemp1;
        survivalSet[1][setMark3] = swapTemp2;
      }
      if (survivalSet[1][step] == 0)
        survivalSet[0][step] = survivalSet[0][step] + "+";
    }
  }
  function calcLore() {
    genLore = 0;
    setMark1 = loreSet[0].length;
    for (step=0; step<setMark1; step++) {
      fixTest = loreSet[0][step].indexOf("+");
      if (fixTest > -1)
        loreSet[0][step] = loreSet[0][step].slice(0,-1);
      loreSet[1][step] = getSkill(loreSet[0][step]);
      genLore = genLore + loreSet[1][step];
    }
    if (topLore == 0)
      return;
    for (step=0; step<topLore; step++) {
      setMark2 = 0; // temp copy of # of ranks in high skill
      setMark3 = -1; // pointer to name of high skill
      for (step2=step; step2<setMark1; step2++) {
        if (loreSet[1][step2] > setMark2) {
          setMark2 = loreSet[1][step2];
          setMark3 = step2;
        }
      }
      if (setMark3 > -1) {
        swapTemp1 = loreSet[0][step];
        swapTemp2 = loreSet[1][step];
        loreSet[0][step] = loreSet[0][setMark3];
        loreSet[1][step] = setMark2;
        loreSet[0][setMark3] = swapTemp1;
        loreSet[1][setMark3] = swapTemp2;
      }
      if (loreSet[1][step] == 0)
        loreSet[0][step] = loreSet[0][step] + "+";
    }
  }
  function calcSets() {
    if (armorSet[0][0] != "n/a")
      calcArmor();
    if (weaponSet[0][0] != "n/a")
      calcWeapon();
    if (magicSet[0][0] != "n/a")
      calcMagic();
    if (survivalSet[0][0] != "n/a")
      calcSurvival();
    if (loreSet[0][0] != "n/a")
      calcLore();
  }

  //extract ranks in a specific skill
  function getSkill(skillMark) {
    searchTemp = document.form1.currskills.value; //save a copy of currskills
    searchLength = searchTemp.length;
    markLength = skillMark.length;
    searchIndex = searchTemp.search(skillMark); //find the target skill
    if (searchIndex == -1) //skill not found?
      return 0;
    searchIndex = searchIndex + markLength +1; //find ranks after skill
    searchIndexTemp = searchIndex + 5;
    if (searchLength <= searchIndexTemp)
      return 0; //invalid result, use failsafe
    searchTemp = searchTemp.substr(searchIndex, 5); //extract skill's ranks from result
    for (step4=4; step4>0; step4--) {
      searchTest = parseInt(searchTemp);
      if (isNaN(searchTest)) //extra non-numbers?
        searchTemp = searchTemp.substr(1, step4);
      if (searchTest >= 0) //good result?
       return searchTest;
    }
    return 0; //failsafe
  }
  //update skillGrid with new req's
  function calcReq() {
    stepMark = 1;
    circleBreaks[0][0] = 0;
    for (step=1; step<5; step++) { //set circle multipliers
      circleBreaks[0][step] = 0;
      if (circleValOld < circleBreaks[1][step])
        continue;
      circleBreaks[0][0] = circleBreaks[1][step];
      circleBreaks[0][step] = circleBreaks[1][step] - circleBreaks[1][step-1];
      stepMark++;
    }
    for (step=0; step<endMark; step++) { //each skill
      circleDiff = circleValOld - circleBreaks[0][0];
      skillGrid[step][7] = (circleBreaks[0][1] * skillGrid[step][1]) + (circleBreaks[0][2] * skillGrid[step][2]) + (circleBreaks[0][3] * skillGrid[step][3]) + (circleBreaks[0][4] * skillGrid[step][4]) + (circleDiff * skillGrid[step][stepMark]);
      skillGrid[step][7] = Math.floor(skillGrid[step][7] + 0.5);
    }
    calcGuildReq();
    printGrid();
  }

  //update skillGrid with new set of current skills (specific skills only)
  function calcCurrSkill() {
    for (step=0; step<reqMark; step++) {
      skillGrid[step][6] = getSkill(skillGrid[step][0]);
      skillGrid[step][10] = skillGrid[step][6];
    }
    calcSets();
    calcGuildCurr();
    nextCircle = 1;
    updateSummary();
    if (circleValOld > 0)
      calcReq();
    document.form1.currskills.blur();
  }

  //update value of circle input box
  function circleChange(changeType) {
    circleLengthTemp = document.form1.circle.value;
    circleLength = circleLengthTemp.length;
    circleTemp = parseInt(circleLengthTemp);
    if (isNaN(circleTemp))
      circleTemp = 0;
    if (changeType == 1) {
      circleTemp++;
      circleLength++;
    }
    if (changeType == 2) {
      circleTemp--;
      circleLength++;
    }
    if (circleLength == 0)
      return;
    if (isNaN(circleTemp))
      circleTemp = circleValOld;
    if (circleTemp < 1)
      circleTemp = 1;
    circleValOld = circleTemp;
    document.form1.circle.value = circleTemp;
    calcReq();
  }

  //update requirement area
  function printGrid() {
    document.form1.reqskills.value = "You require:\n";
    stepMarkTemp = stepMark - 1;
    for (step=0; step<endMark; step++) {
      if (document.form1.gridtype[1].checked == true) {
        circReqTemp = skillGrid[step][7] - skillGrid[step][6];
        skillPrintTemp = skillGrid[step][8];
      }
      else {
        circReqTemp = skillGrid[step][7];
        skillPrintTemp = skillGrid[step][0];
      }
      if (circReqTemp < 0)
        continue;
      if (document.form1.legacy.checked == true) {
        printLine(circReqTemp, skillPrintTemp);
        continue;
      }
      circleValTest1 = (circleValOld != 10) && (circleValOld != 30) && (circleValOld != 70) && (circleValOld != 100);
      circleValTest2 = skillGrid[step][stepMark] == 0 && skillGrid[step][stepMarkTemp] == 0;
      if (circleValTest2 || (skillGrid[step][stepMark] == 0 && circleValTest1))
        continue;
      if (circReqTemp == 0)
        continue;
      printLine(circReqTemp, skillPrintTemp);
    }
  }

  //print a single line for printGrid
  function printLine(printRank, printSkill) {
    lineTemp = "      " + printRank.toString();
    lineTempMark = lineTemp.length - 6;
    lineTemp = lineTemp.substr(lineTempMark, 6);
    printTest1 = printSkill.indexOf("+");
    printTest2 = printSkill.indexOf("(");
    printTest3 = " ";
    printTest4 = printSkill.length - 4;
    if (printTest2 > -1 && printTest1 > -1)
      printTest3 = printSkill.substr(printTest4, 4);
    if (printTest1 > -1)
      printSkill = "not yet trained";
    lineTemp = lineTemp + "  " + printSkill + printTest3 + "                       ";
    lineTemp = lineTemp.substr(0, 28);
    document.form1.reqskills.value = document.form1.reqskills.value + lineTemp + "\n";
  }

  //set standard variables
  allArmor = new Array("Shield Usage", "Leather Armor", "Light Chain", "Heavy Chain", "Light Plate", "Heavy Plate");
  totalArmorRank = allArmor.length;
  allWeapon = new Array("Parry Ability", "Multi Opponent", "Light Edged", "Medium Edged", "Heavy Edged", "Twohanded Edged", "Light Blunt", "Medium Blunt", "Large Blunt", "Twohanded Blunt", "Slings", "Staff Sling", "Short Bow", "Long Bow", "Composite Bow", "Light Crossbow", "Heavy Crossbow", "Short Staff", "Quarter Staff", "Pikes", "Halberds", "Light Thrown", "Heavy Thrown", "Brawling");
  totalWeaponRank = allWeapon.length;
  allSurvival = new Array("Evasion", "Climbing", "Perception", "Scouting", "Hiding", "Lockpicking", "Disarm Traps", "Stalking", "Stealing", "First Aid", "Foraging", "Escaping", "Backstab", "Skinning", "Swimming");
  totalSurvivalRank = allSurvival.length;
  allMagic = new Array("Primary Magic", "Harness Ability", "Power Perceive", "Magical Devices", "Targeted Magic");
  totalMagicRank = allMagic.length;
  allLore = new Array("Scholarship", "Mechanical Lore", "Musical Theory", "Appraisal", "Teaching", "Trading", "Animal Lore", "Percussions", "Strings", "Winds", "Vocals", "Empathy", "Astrology");
  totalLoreRank = allLore.length;
  circleBreaks = new Array(2);
  circleBreaks[0] = new Array(1, 0, 0, 0, 0);
  circleBreaks[1] = new Array(0, 10, 30, 70, 100);
  circleValUp = 1;
  circleValDown = 2;
  circleValNull = 0;
  circleValOld = 1;
  genArmor = 0;
  genWeapon = 0;
  genMagic = 0;
  genSurvival = 0;
  genLore = 0;
  stepMark = 0;
