diff --git a/armors.js b/armors.js deleted file mode 100644 index 112a360..0000000 --- a/armors.js +++ /dev/null @@ -1,188 +0,0 @@ -/*global _:false */ -/*global Grimoire:true */ -'use strict'; - -//TODO: Program the "Roll twice" logic - -var Armors = {}; -Armors.specificBaseUrl = 'http://paizo.com/pathfinderRPG/prd/magicItems/armor.html'; -Armors.getSpecifics = function() { - return [ - {'name': 'Mithral shirt', 'bonus': 0, 'cost': 1100, 'url': '#mithril-shirt'}, - {'name': 'Dragonhide plate', 'bonus': 0, 'cost': 3300, 'url':''}, - {'name': 'Elven chain', 'bonus': 0, 'cost': 5150, 'url':''}, - {'name': 'Rhino hide', 'bonus': 0, 'cost': 5165, 'url':''}, - {'name': 'Adamantine breastplate', 'bonus': 0, 'cost': 10200, 'url':''}, - {'name': 'Dwarven plate', 'bonus': 0, 'cost': 16500, 'url':''}, - {'name': 'Banded mail of luck', 'bonus': 0, 'cost': 18900, 'url':''}, - {'name': 'Celestial armor', 'bonus': 0, 'cost': 22400, 'url':''}, - {'name': 'Plate armor of the deep', 'bonus': 0, 'cost': 24650, 'url':''}, - {'name': 'Breastplate of command', 'bonus': 0, 'cost': 25400, 'url':''}, - {'name': 'Mithral full plate of speed', 'bonus': 0, 'cost': 26500, 'url':''}, - {'name': 'Demon armor', 'bonus': 0, 'cost': 52260, 'url':''}, - ]; -}; - -Armors.getSpecific = function(type) { - var roll = _.random(1,100); - var armor = {}; - if(type == 'minor') { - switch(true) { - case (roll <= 50): armor = Armors.getSpecifics()[0]; break; - case (roll <= 80): armor = Armors.getSpecifics()[1]; break; - case (roll <= 100): armor = Armors.getSpecifics()[2]; break; - } - } - else if(type == 'medium') { - switch(true) { - case (roll <= 25): armor = Armors.getSpecifics()[0]; break; - case (roll <= 45): armor = Armors.getSpecifics()[1]; break; - case (roll <= 57): armor = Armors.getSpecifics()[2]; break; - case (roll <= 67): armor = Armors.getSpecifics()[3]; break; - case (roll <= 82): armor = Armors.getSpecifics()[4]; break; - case (roll <= 97): armor = Armors.getSpecifics()[5]; break; - case (roll <= 100): armor = Armors.getSpecifics()[6]; break; - } - } - else if(type == 'major') { - switch(true) { - case (roll <= 10): armor = Armors.getSpecifics()[4]; break; - case (roll <= 20): armor = Armors.getSpecifics()[5]; break; - case (roll <= 32): armor = Armors.getSpecifics()[6]; break; - case (roll <= 50): armor = Armors.getSpecifics()[7]; break; - case (roll <= 60): armor = Armors.getSpecifics()[8]; break; - case (roll <= 75): armor = Armors.getSpecifics()[9]; break; - case (roll <= 90): armor = Armors.getSpecifics()[10]; break; - case (roll <= 100): armor = Armors.getSpecifics()[11]; break; - } - } - return armor; -}; - -Armors.getArmors = function() { - //5 possible roll'able armors. Specific type of armor is left up to DM - return [ - {'name': '+1 armor', 'bonus': 1, 'cost': 1000}, - {'name': '+2 armor', 'bonus': 2, 'cost': 4000}, - {'name': '+3 armor', 'bonus': 3, 'cost': 9000}, - {'name': '+4 armor', 'bonus': 4, 'cost': 16000}, - {'name': '+5 armor', 'bonus': 5, 'cost': 25000}, - {'name': '+6 armor', 'bonus': 6, 'cost': 36000}, - {'name': '+7 armor', 'bonus': 7, 'cost': 49000}, - {'name': '+8 armor', 'bonus': 8, 'cost': 64000}, - {'name': '+9 armor', 'bonus': 9, 'cost': 81000}, - {'name': '+10 armor', 'bonus': 10,'cost': 10000} - ]; -}; - -Armors.getSpecials = function() { - return [ - {'name': 'Glamered', 'bonus': 0, 'cost': 2700}, - {'name': 'Light Fortification', 'bonus': 1, 'cost': 0}, - {'name': 'Slick', 'bonus': 0, 'cost': 3750}, - {'name': 'Shadow', 'bonus': 0, 'cost': 3750}, - {'name': 'Spell resistance (13)', 'bonus': 2, 'cost': 0}, - {'name': 'Improved Slick', 'bonus': 0, 'cost': 15000}, - {'name': 'Improved Shadow', 'bonus': 0, 'cost': 15000}, - {'name': 'Energy resistance (' + Grimoire.getEnergyResistance() + ')', 'bonus': 0, 'cost': 18000}, - {'name': 'Ghost touch', 'bonus': 3, 'cost': 0}, - {'name': 'Invulnerability', 'bonus': 3, 'cost': 0}, - {'name': 'Moderate Fortification', 'bonus': 3, 'cost': 0}, - {'name': 'Spell resistance (15)', 'bonus': 3, 'cost': 0}, - {'name': 'Wild', 'bonus': 3, 'cost': 0}, - {'name': 'Slick, greater', 'bonus': 0, 'cost': 33750}, - {'name': 'Shadow, greater', 'bonus': 0, 'cost': 33750}, - {'name': 'Improved Energy resistance (' + Grimoire.getEnergyResistance() + ')', 'bonus': 0, 'cost': 42000}, - {'name': 'Spell resistance (17)', 'bonus': 4, 'cost': 0}, - {'name': 'Etherealness', 'bonus': 0, 'cost': 49000}, - {'name': 'Undead controlling', 'bonus': 0, 'cost': 49000}, - {'name': 'Fortification, heavy', 'bonus': 5, 'cost': 0}, - {'name': 'Spell resistance (19)', 'bonus': 5, 'cost': 0}, - {'name': 'Energy resistance, greater (' + Grimoire.getEnergyResistance() + ')', 'bonus': 0, 'cost': 66000} - //100 Roll again twice - ]; -}; - -Armors.getSpecial = function(type) { - var roll = _.random(1,100); - var s1, s2; - if(type == 'minor') { - switch(true) { - case (roll <= 25): return Armors.getSpecials()[0]; - case (roll <= 32): return Armors.getSpecials()[1]; - case (roll <= 52): return Armors.getSpecials()[2]; - case (roll <= 92): return Armors.getSpecials()[3]; - case (roll <= 96): return Armors.getSpecials()[4]; - case (roll <= 97): return Armors.getSpecials()[5]; - case (roll <= 99): return Armors.getSpecials()[6]; - case (roll <= 100): //roll twice - s1 = Armors.getSpecial('minor'); - s2 = Armors.getSpecial('minor'); - return {'name': s1.name + ' ' + s2.name, 'bonus': s1.bonus + s2.bonus}; - } - } - else if(type == 'medium') { - switch(true) { - case (roll <= 5): return Armors.getSpecials()[0]; - case (roll <= 8): return Armors.getSpecials()[1]; - case (roll <= 11): return Armors.getSpecials()[2]; - case (roll <= 17): return Armors.getSpecials()[3]; - case (roll <= 19): return Armors.getSpecials()[4]; - case (roll <= 29): return Armors.getSpecials()[5]; - case (roll <= 49): return Armors.getSpecials()[6]; - case (roll <= 74): return Armors.getSpecials()[7]; - case (roll <= 79): return Armors.getSpecials()[8]; - case (roll <= 84): return Armors.getSpecials()[9]; - case (roll <= 89): return Armors.getSpecials()[10]; - case (roll <= 94): return Armors.getSpecials()[11]; - case (roll <= 99): return Armors.getSpecials()[12]; - case (roll <= 100): //roll twice - s1 = Armors.getSpecial('medium'); - s2 = Armors.getSpecial('medium'); - return {'name': s1.name + ' ' + s2.name, 'bonus': s1.bonus + s2.bonus}; - } - } - else if(type == 'major') { - switch(true) { - case (roll <= 3): return Armors.getSpecials()[0]; - case (roll <= 4): return Armors.getSpecials()[1]; - case (roll <= 7): return Armors.getSpecials()[5]; - case (roll <= 13): return Armors.getSpecials()[6]; - case (roll <= 28): return Armors.getSpecials()[7]; - case (roll <= 33): return Armors.getSpecials()[8]; - case (roll <= 35): return Armors.getSpecials()[9]; - case (roll <= 40): return Armors.getSpecials()[10]; - case (roll <= 42): return Armors.getSpecials()[11]; - case (roll <= 43): return Armors.getSpecials()[12]; - case (roll <= 48): return Armors.getSpecials()[13]; - case (roll <= 58): return Armors.getSpecials()[14]; - case (roll <= 83): return Armors.getSpecials()[15]; - case (roll <= 88): return Armors.getSpecials()[16]; - case (roll <= 89): return Armors.getSpecials()[17]; - case (roll <= 90): return Armors.getSpecials()[18]; - case (roll <= 92): return Armors.getSpecials()[19]; - case (roll <= 94): return Armors.getSpecials()[20]; - case (roll <= 99): return Armors.getSpecials()[21]; - case (roll <= 100): //roll twice - s1 = Armors.getSpecial('major'); - s2 = Armors.getSpecial('major'); - return {'name': s1.name + ' ' + s2.name, 'bonus': s1.bonus + s2.bonus}; - } - } - if(['minor','medium','major'].indexOf(type) >= 0 && roll == 100) { - var special1 = Armors.getSpecial(type); - var special2 = Armors.getSpecial(type); - //there exists a possibility of getting the same bonus - //this is hilarious and has not been fixed - if(special1.bonus + special2.bonus <= 10) { - return {'name': special1.name + ' ' + special2.name, - 'bonus': special1.bonus + special2.bonus, - 'cost': special1.cost + special2.cost - }; - } - else { - //return the special with the better bonus. - return (special1.bonus > special2.bonus ? special1 : special2); - } - } -}; diff --git a/grimoire-core.js b/grimoire-core.js index 4bd3920..2fc7a90 100644 --- a/grimoire-core.js +++ b/grimoire-core.js @@ -324,9 +324,11 @@ var Grimoire = function(config) { // jshint ignore:line if(itemType == TYPES.SCROLLS) { item = self.getScroll(quality, options); } + //POTIONS else if(itemType == TYPES.POTIONS) { item = self.getPotion(quality, options); } + //WANDS else if(itemType == TYPES.WANDS) { item = self.getWand(quality, options); } @@ -334,6 +336,9 @@ var Grimoire = function(config) { // jshint ignore:line else if(itemType == TYPES.WONDROUS_ITEMS) { item = self.getWondrousItem(quality, options); } + else if(itemType == TYPES.WEAPONS) { + item = self.getWeapon(quality, options); + } //EVERYTHING ELSE else { //Select the item source based on the quality and item type @@ -341,7 +346,6 @@ var Grimoire = function(config) { // jshint ignore:line //EXCEPTIONS FOR ARMOR_AND_SHEILDS - //EXCEPTIONS FOR WEAPONS //CHANCE FOR INTELLIGENT WEAPONS, RINGS, RODS, STAVES, OR WONDROUS ITEMS item = self.getWeightedItem(source.data[itemType].data, quality); @@ -355,6 +359,8 @@ var Grimoire = function(config) { // jshint ignore:line return item; }; + //options.maxRoll - override the maximul value that can be rolled for these items + // default is the sum of the quality weights this.getWeightedItem = function(itemData, quality, options) { options = options ? options : {}; var chance = (self.chance ? self.chance : options.seed ? new Chance(options.seed) : new Chance()); @@ -374,7 +380,7 @@ var Grimoire = function(config) { // jshint ignore:line } } console.error('Could not find valid '+quality+'item in',itemData); - } + }; this.getSpells = function(level, count, options) { options = options ? options : {}; @@ -470,28 +476,13 @@ var Grimoire = function(config) { // jshint ignore:line var chance = (self.chance ? self.chance : options.seed ? new Chance(options.seed) : new Chance()); var cost = [25, 50, 300, 750]; - if(!level || level < 0 || level > 4) { - var roll = chance.d100(); - if(quality == QUALITIES.MINOR) { - switch(true) { - case (roll <= 20): level = 0; break; - case (roll <= 60): level = 1; break; - case (roll <= 100): level = 2; break; - } - } - else if(quality == QUALITIES.MEDIUM) { - switch(true) { - case (roll <= 20): level = 1; break; - case (roll <= 60): level = 2; break; - case (roll <= 100): level = 3; break; - } - } - else if(quality == QUALITIES.MAJOR) { - switch(true) { - case (roll <= 20): level = 2; break; - case (roll <= 100): level = 3; break; - } - } + if(!level || level < 0 || level > 3) { + var weights = {}; + weights[QUALITIES.MINOR] = [20, 40, 40, 0]; + weights[QUALITIES.MEDIUM] = [ 0, 20, 40, 40]; + weights[QUALITIES.MAJOR] = [ 0, 0, 20, 80]; + + level = chance.weighted([0,1,2,3], weights[quality]); } options.typeOverride = TYPES.POTIONS; options.potionLevel = level; @@ -514,26 +505,12 @@ var Grimoire = function(config) { // jshint ignore:line if(!level || level < 0 || level > 4) { - var roll = chance.d100(); - if(quality == QUALITIES.MINOR) { - switch(true) { - case (roll <= 5): level = 0; break; - case (roll <= 60): level = 1; break; - case (roll <= 100): level = 2; break; - } - } - else if(quality == QUALITIES.MEDIUM) { - switch(true) { - case (roll <= 60): level = 2; break; - case (roll <= 100): level = 3; break; - } - } - else if(quality == QUALITIES.MAJOR) { - switch(true) { - case (roll <= 60): level = 3; break; - case (roll <= 100): level = 4; break; - } - } + var weights = {}; + weights[QUALITIES.MINOR] = [ 5, 55, 40, 0, 0]; + weights[QUALITIES.MEDIUM] = [ 0, 0, 60, 40, 0]; + weights[QUALITIES.MAJOR] = [ 0, 0, 0, 60, 40]; + + level = chance.weighted([0,1,2,3,4], weights[quality]); } options.wandLevel = level; @@ -562,7 +539,8 @@ var Grimoire = function(config) { // jshint ignore:line //make an intelligent item if we either want ALL intelligent items //OR intelligent items are NOT disabled AND we roll under the chance threshold if(options.allIntelligent || (!options.disableIntelligent && chance.d100() <= (options.intelligenceChance || 1))) { - item.intelligence = 'WOOHOO I AM INTELLIGENT!'; + item.intelligence = self.getIntelligence(item.cost, options); //'WOOHOO I AM INTELLIGENT!'; + item.cost += item.intelligence.cost; } return item; }; @@ -592,6 +570,12 @@ var Grimoire = function(config) { // jshint ignore:line bane = bane.replace(/GET_OUTSIDER_TYPE/, self.getOutsider(options)); return bane; }; + this.getEnergyType = function(options) { + options = options ? options : {}; + var chance = (self.chance ? self.chance : options.seed ? new Chance(options.seed) : new Chance()); + + return chance.pick(_.values(ENERGY_TYPES)); + }; //type is 'armor', 'shield', 'melee', or 'ranged' //options.excludeSpecials can contain a list of specials you do NOT want to get @@ -633,8 +617,10 @@ var Grimoire = function(config) { // jshint ignore:line } while(options.excludeSpecials.indexOf(special) != -1); //if we have a duplicate, try again //EXCEPTION for Bane special - if(special.name.indexOf('GET_BANE_TYPE')) { + if(/GET_BANE_TYPE/.test(special.name)) { special.name = special.name.replace(/GET_BANE_TYPE/, self.getBane(options)); + } else if(/GET_ENERGY_RESISTANCE_TYPE/.test(special.name)) { + special.name = special.name.replace(/GET_ENERGY_RESISTANCE_TYPE/, self.getEnergyType(options)); } return [special]; //could contain one or more specials @@ -767,11 +753,24 @@ var Grimoire = function(config) { // jshint ignore:line //30% chance to be glowing if(options.allIntelligent || (!options.disableIntelligent && chance.d100() <= (options.intelligenceChance || 1))) { - weapon.intelligence = 'WOOHOO I AM INTELLIGENT!'; + var cost = weapon.baseCost + 2000 * Math.pow(weapon.bonus, 2); + weapon.intelligence = self.getIntelligence(cost, options); //'WOOHOO I AM INTELLIGENT!'; + weapon.cost += weapon.intelligence.cost; } if(!options.disableGlowing && chance.d100() <= (options.glowingChance || 30)) { weapon.glowing = true; } + weapon.print = function() { + var ret = 'Name: '; + ret += this.glowing ? 'Glowing ' : ''; + ret += this.bonus > 0 ? ('+' + this.bonus + ' ') : ''; + ret += this.specials.length > 0 ? _.map(this.specials, function(s) { return s.name;}).join(', ') + ' ' : ''; + ret += this.name ? this.name : (this.type + ' weapon'); + ret += ';'; + ret += this.intelligence.print ? 'Intelligence: [' + this.intelligence.print() + '];' : ''; + ret += 'Cost: ' + (this.baseCost + 2000 * Math.pow(weapon.bonus, 2) + this.intelligence.cost) + 'gp'; + return ret; + }; return weapon; }; @@ -804,6 +803,273 @@ var Grimoire = function(config) { // jshint ignore:line return alignment; }; + //options.cl can be Chaotic, Neutral, or Lawful + //options.ge can be Good, Neutral, or Evil + this.getDeity = function(options) { + options = options ? options : {}; + var chance = (self.chance ? self.chance : options.seed ? new Chance(options.seed) : new Chance()); + var cl = options.cl || chance.pick(['Chaotic', 'Neutral', 'Lawful']); + var ge = options.ge || chance.pick(['Good', 'Neutral', 'Evil']); + var deity = {}; + deity.name = chance.pick(self.Deities.data[cl][ge]); + deity.alignment = (cl == 'Neutral' && ge == 'Neutral') ? 'True Neutral' : (cl + ' ' + ge); + + return deity; + }; + + //baseCost is the base cost of the item the intelligence is being made for. + //This directly affects the intelligence's ego score! + //baseCost also directly affects the probability of the number of special abilities an intelligence will have + //options.numPowers + //options.purposeChance + //options.numDedicatedPowers + this.getIntelligence = function(baseCost, options) { + baseCost = baseCost || 0; + options = options || {}; + var chance = (self.chance ? self.chance : options.seed ? new Chance(options.seed) : new Chance()); + var i = {}; //intelligence object. we'll be referencing this a LOT + + + //***BASE VALUES*** + i.cost = 500; //base starting cost + i.ego = 0; + //Base cost ego modifier + switch(true) { + case (baseCost <= 1000): i.ego += 0; break; + case (baseCost <= 5000): i.ego += 1; break; + case (baseCost <= 10000): i.ego += 2; break; + case (baseCost <= 20000): i.ego += 3; break; + case (baseCost <= 50000): i.ego += 4; break; + case (baseCost <= 100000): i.ego += 6; break; + case (baseCost <= 200000): i.ego += 8; break; + case (baseCost > 200000): i.ego += 12; break; + } + + + //***ITEM ABILITY STATS*** + var statScores = [ + {'score': 10, 'costMod': 0, 'egoMod': 0}, + {'score': 11, 'costMod': 200, 'egoMod': 0}, + {'score': 12, 'costMod': 500, 'egoMod': 1}, + {'score': 13, 'costMod': 700, 'egoMod': 1}, + {'score': 14, 'costMod': 1000, 'egoMod': 2}, + {'score': 15, 'costMod': 1400, 'egoMod': 2}, + {'score': 16, 'costMod': 2000, 'egoMod': 3}, + {'score': 17, 'costMod': 2800, 'egoMod': 3}, + {'score': 18, 'costMod': 4000, 'egoMod': 4}, + {'score': 19, 'costMod': 5200, 'egoMod': 4}, + {'score': 20, 'costMod': 8000, 'egoMod': 5}, + ]; + var statWeights = [10, 10, 20, 10, 20, 5, 5, 5, 5, 5, 5]; + + i.stats = {}; + ['intelligence', 'wisdom', 'charisma'].forEach(function(stat) { + var score = chance.weighted(statScores, statWeights); + i.stats[stat] = score.score; + i.cost += score.costMod; + i.ego += score.egoMod; + }); + + i.alignment = self.getAlignment(options); + + + //***ITEM COMMUNICATION AND SENSES*** + //get communication ability for the item. + var communicationTypes = [ + {'description': 'Empathy', 'costMod': 0, 'egoMod': 0}, + {'description': 'Speech', 'costMod': 500, 'egoMod': 0}, + {'description': 'Telepathy', 'costMod': 1000, 'egoMod': 1}, + ]; + var communicationWeights = [3,4,3]; //There was no roll table so I made this up + var communication = chance.weighted(communicationTypes, communicationWeights); + + //get senses for the item. there was no roll table so I made this up + var basicSenses = [ + {'description': 'Senses (30 ft.)', 'costMod': 0, 'egoMod': 0}, + {'description': 'Senses (60 ft.)', 'costMod': 500, 'egoMod': 0}, + {'description': 'Senses (120 ft.)', 'costMod': 1000, 'egoMod': 0}, + ]; + var basicSensesWeights = [5,3,2]; //There was no roll table so I made this up + var basicSense = chance.weighted(basicSenses, basicSensesWeights); + + //get special senses for the item. + var specialSenses = [ + {'description': '', 'costMod': 0, 'egoMod': 0}, + {'description': 'Darkvision', 'costMod': 500, 'egoMod': 0}, + {'description': 'Blindsense', 'costMod': 5000, 'egoMod': 1}, + {'description': 'Read languages', 'costMod': 1000, 'egoMod': 1}, + {'description': 'Read magic', 'costMod': 2000, 'egoMod': 1}, + ]; + //There was no roll table so I made this up and limited it to only 1 special per item + var specialSensesWeights = [50, 20, 5, 15, 10]; + var specialSense = chance.weighted(specialSenses, specialSensesWeights); + + i.communication = communication.description; + i.senses = basicSense.description + (specialSense.description ? ', ' + specialSense.description : ''); + + i.cost += communication.costMod + basicSense.costMod + specialSense.costMod; + i.ego += communication.egoMod + basicSense.egoMod + specialSense.egoMod; + + + //***ITEM POWERS*** + //Get item powers! + var powerCountWeights = [1,1,1,1,1]; + //The probability for more powers is directly related to the base cost of the item + //I made up these roll weights. references the same basecost as the basic ego modifier + switch(true) { + case (baseCost <= 1000): powerWeights = [6,4,0,0,0]; break; + case (baseCost <= 5000): powerWeights = [3,4,3,0,0]; break; + case (baseCost <= 10000): powerWeights = [2,3,4,1,0]; break; + case (baseCost <= 20000): powerWeights = [1,3,4,2,0]; break; + case (baseCost <= 50000): powerWeights = [0,2,4,3,1]; break; + case (baseCost <= 100000): powerWeights = [0,1,3,4,2]; break; + case (baseCost <= 200000): powerWeights = [0,0,2,5,3]; break; + case (baseCost > 200000): powerWeights = [0,0,0,6,4]; break; + } + + + var powerWeights = _.map(self.ItemPowers, function(p) { return p.weight; }); + + i.powers = []; + var reSkill = /GET_ITEM_SKILL/; + var reSpell = /GET_SPELL_LEVEL_(.)/; //for spell levels 0-9 + + //Another option would be to do this with _.sample but it does not support weights + _.times((options.numPowers || chance.weighted(_.range(1,6), powerCountWeights)), function() { + var power = {}; + do { + power = _.clone(chance.weighted(_.clone(self.ItemPowers), powerWeights)); + if(reSkill.test(power.description)) { + power.description = power.description.replace(reSkill, chance.pick(self.ItemSkills).name); + } + else if (reSpell.test(power.description)) { + var spellLevel = reSpell.exec(power.description)[1]; + power.spell = self.getSpell(spellLevel, options); //add the spell onto the power for later reference + power.description = power.description.replace(reSpell, power.spell.name); + } + } while(_.findWhere(i.powers, {'description': power.description}) && !power.repeatable); //power exists in item powers and is not repeatable + if(_.findWhere(i.powers, {'description': power.description})) { //if we selected an existing but repeatable power + //add the new power values to the old power + var oldPower = _.findWhere(i.powers, {'description': power.description}); + oldPower.costMod += power.costMod; + oldPower.egoMod += power.egoMod; + oldPower.value += power.value; + } + else { + i.powers.push(power); + } + }); + + //Set for the next section + var bonusLanguages = 0; + + //Finalize powers + i.powers.forEach(function(p) { + p.description = p.description.replace(/#/, p.value); + i.ego += p.egoMod; + i.cost += p.costMod; + + if(/Linguistics/.test(p.description)) { //check if we got any ranks in linguistics + bonusLanguages += p.value; + } + + //clean up the power + delete p.value; + delete p.egoMod; + delete p.costMod; + delete p.weight; + delete p.repeatable; + //final power should only have description and spell + }); + + + //***ITEM BONUS LANGUAGES*** + i.languages = ['Common']; //ALL intelligent items know Common + //extra languages are based on intelligence and ranks in Linguistics + bonusLanguages += Math.floor((i.stats.intelligence-10)/2); + //pick is safe even if we have more bonusLanguages than exist + i.languages.concat(chance.pick(self.Languages.data, bonusLanguages)); + + + //***ITEM PURPOSE*** + //there was NO roll chart for determining if an item has a purpose so I made this up + //I figure 30% of the time sounds good + i.purpose = ''; + i.dedicatedPowers = []; + + if(chance.d100() <= (options.purposeChance || 30)) { + var reBane = /GET_BANE/; + var reHumOrOut = /GET_HUMANOID_OR_OUTSIDER_TYPE/; + var reDeity = /GET_DEITY/; + //get purpose + var purpose = chance.weighted(_.clone(self.ItemPurposes), + _.map(self.ItemPurposes, function(p) { return p.weight; })); + i.purpose = purpose.description; + i.ego += purpose.egoMod; + + if(reBane.test(i.purpose)) { + i.purpose = i.purpose.replace(reBane, self.getBane(options)); + } + else if(reHumOrOut.test(i.purpose)) { + i.purpose = i.purpose.replace(reHumOrOut, + chance.pick(['Humanoids (' + self.getHumanoid(options) + ')', + 'Outsiders (' + self.getOutsider(options) + ')'])); + } + else if(reDeity.test(i.purpose)) { + var deity = self.getDeity(options); + i.purpose = i.purpose.replace(reDeity, deity.name + ' (' + deity.alignment + ')'); + } + + //console.log(i.purpose.description); + i.dedicatedPowers = []; //chance.pick() + //I decided that purposed items get between 1-3 dedicated powers, heavily leaning on 1 + var numDedicatedPowers = options.numDedicatedPowers || chance.weighted([1,2,3], [7,2,1]); + _.times(numDedicatedPowers, function() { + var power = {}; + do { + power = _.clone(chance.weighted(self.ItemDedicatedPowers, + _.map(self.ItemDedicatedPowers, function(p) { return p.weight; }))); + + if (reSpell.test(power.description)) { //as in the normal powers + var spellLevel = reSpell.exec(power.description)[1]; + power.spell = self.getSpell(spellLevel, options); //add the spell onto the power for later reference + power.description = power.description.replace(reSpell, power.spell.name); + } + //don't allow for duplicate dedicated powers + } while(_.findWhere(i.dedicatedPowers, {'description': power.description})); + //finalize dedicated power + i.cost += power.costMod; + i.ego += power.egoMod; + delete power.costMod; + delete power.egoMod; + delete power.weight; + i.dedicatedPowers.push(power); + }); + } + + //***PRINT FUNCTION*** + i.print = function() { + var ret = ''; + ret += 'Alignment: ' + this.alignment + ';'; + ret += 'Stats: Ego ' + this.ego + ', Int ' + this.stats.intelligence + ', ' + + 'Wis ' + this.stats.wisdom + ', ' + + 'Cha ' + this.stats.charisma + ';'; + ret += 'Communication: ' + this.communication + ' (' + this.languages.join(',' ) + ');'; + ret += 'Senses: ' + this.senses + ';'; + ret += 'Powers: ' + _.map(this.powers, function(p) { return p.description; }).join(', ') + ';'; + if(this.purpose) { + ret += 'Purpose: ' + this.purpose + ';'; + ret += 'Dedicated Powers: ' + _.map(this.dedicatedPowers, function(p) {return p.description; }).join(', ') + ';'; + } + ret += 'Cost: ' + i.cost + 'gp'; + + return ret; + + }; + + return i; //object intelligence + }; + }; diff --git a/intelligence.js b/intelligence.js deleted file mode 100644 index 330ada3..0000000 --- a/intelligence.js +++ /dev/null @@ -1,390 +0,0 @@ -/*global _:false */ -/*global Grimoire:true, Spells:true, Weapons:true */ -'use strict'; - -Grimoire.alignments = ['Chaotic good', 'Chaotic neutral', 'Chaotic evil', 'Neutral evil', -'Lawful evil', 'Lawful good', 'Lawful neutral', 'Neutral good', 'True neutral']; //9 alignments - -Grimoire.getAlignment = function() { - var roll = _.random(1,100); - switch(true) { - case (roll <= 10): return 'Chaotic good'; - case (roll <= 20): return 'Chaotic neutral'; - case (roll <= 35): return 'Chaotic evil'; - case (roll <= 45): return 'Neutral evil'; - case (roll <= 55): return 'Lawful evil'; - case (roll <= 70): return 'Lawful good'; - case (roll <= 80): return 'Lawful neutral'; - case (roll <= 90): return 'Neutral good'; - case (roll <= 100): return 'True neutral'; - } -}; - -var Intelligence = {}; - -Intelligence.abilityScore = [ - //ability_score = [score, base price modifier, ego modifier] - {'score': 10, 'priceMod': 0, 'egoMod': 0}, - {'score': 11, 'priceMod': 200, 'egoMod': 0}, - {'score': 12, 'priceMod': 500, 'egoMod': 1}, - {'score': 13, 'priceMod': 700, 'egoMod': 1}, - {'score': 14, 'priceMod': 1000, 'egoMod': 2}, - {'score': 15, 'priceMod': 1400, 'egoMod': 2}, - {'score': 16, 'priceMod': 2000, 'egoMod': 3}, - {'score': 17, 'priceMod': 2800, 'egoMod': 3}, - {'score': 18, 'priceMod': 4000, 'egoMod': 4}, - {'score': 19, 'priceMod': 5200, 'egoMod': 4}, - {'score': 20, 'priceMod': 8000, 'egoMod': 5}, - ]; - -Intelligence.getAbilityScore = function() { - var roll = _.random(1,100); - switch(true) { - case (roll <= 10): return Intelligence.abilityScore[0]; - case (roll <= 20): return Intelligence.abilityScore[1]; - case (roll <= 40): return Intelligence.abilityScore[2]; - case (roll <= 50): return Intelligence.abilityScore[3]; - case (roll <= 70): return Intelligence.abilityScore[4]; - case (roll <= 75): return Intelligence.abilityScore[5]; - case (roll <= 80): return Intelligence.abilityScore[6]; - case (roll <= 85): return Intelligence.abilityScore[7]; - case (roll <= 90): return Intelligence.abilityScore[8]; - case (roll <= 95): return Intelligence.abilityScore[9]; - case (roll <= 100): return Intelligence.abilityScore[10]; - } -}; - -Intelligence.skills = { - //Craft has been left off the skills list since an object would have a hard time crafting anything - 'int': ['Appraise', 'Knowledge (arcana)', 'Knowledge (dungeoneering)', 'Knowledge (engineering)', - 'Knowledge (geography)', 'Knowledge (history)', 'Knowledge (local)', 'Knowledge (nature)', - 'Knowledge (nobility)', 'Knowledge (planes)', 'Knowledge (religion)', 'Linguistics', 'Spellcraft'], - 'cha': ['Bluff', 'Diplomacy', 'Intimidate', 'Perform'], - 'wis': ['Perception', 'Sense Motive', 'Survival'], -}; - -Intelligence.getSkill = function (type) { - if(['int','cha','wis'].indexOf(type) >= 0) { - return _.sample(Intelligence.skills[type]); - } - else { - return _(Intelligence.skills.int) - .concat(Intelligence.skills.cha) - .concat(Intelligence.skills.wis) - .sample(); - } -}; - -//I've tried to keep things orderly in public arrays but item powers are a bit messy -//item_power = [description, base price modifier, ego modifier] -Intelligence.getItemPower = function() { - var roll = _.random(1,100); - switch(true) { - case (roll <= 10): - return {'description': 'Item can cast ' + Spells.getLevelSpell(0).name + ' at will', - 'priceMod': 1000, 'egoMod': 1}; - case (roll <= 20): - return {'description': 'Item can cast ' + Spells.getLevelSpell(1).name + ' 3/day', - 'priceMod': 1200, 'egoMod': 1}; - case (roll <= 25): - return {'description': 'Item can use Magic Aura on itself at will', - 'priceMod': 2000, 'egoMod': 1}; - case (roll <= 35): - return {'description': 'Item can cast ' + Spells.getLevelSpell(2).name + ' 1/day', - 'priceMod': 2400, 'egoMod': 1}; - case (roll <= 45): - return {'description': 'Item has 5 ranks in ' + Intelligence.getSkill(), - 'priceMod': 2500, 'egoMod': 1}; - case (roll <= 50): - return {'description': 'Item can sprout limbs and move with a speed of 10 feet', - 'priceMod': 5000, 'egoMod': 1}; - case (roll <= 55): - return {'description': 'Item can cast ' + Spells.getLevelSpell(3).name + ' 1/day', - 'priceMod': 6000, 'egoMod': 1}; - case (roll <= 60): - return {'description': 'Item can cast ' + Spells.getLevelSpell(2).name + ' 3/day', - 'priceMod': 1000, 'egoMod': 1}; - case (roll <= 70): - return {'description': 'Item has 10 ranks in ' + Intelligence.getSkill(), - 'priceMod': 10000, 'egoMod': 2}; - case (roll <= 75): - return {'description': 'Item can change shape into one other form of the same size', - 'priceMod': 10000, 'egoMod': 2}; - case (roll <= 80): - return {'description': 'Item can fly, as per the spell, at a speed of 30 feet', - 'priceMod': 10000, 'egoMod': 2}; - case (roll <= 85): - return {'description': 'Item can cast ' + Spells.getLevelSpell(4).name + ' 1/day', - 'priceMod': 11200, 'egoMod': 2}; - case (roll <= 90): - return {'description': 'Item can cast teleport itself 1/day', - 'priceMod': 15000, 'egoMod': 2}; - case (roll <= 95): - return {'description': 'Item can cast ' + Spells.getLevelSpell(3).name + ' 3/day', - 'priceMod': 18000, 'egoMod': 2}; - case (roll <= 100): - return {'description': 'Item can cast ' + Spells.getLevelSpell(4).name + ' 3/day', - 'priceMod': 33600, 'egoMod': 2}; - } -}; - -//this one was also a bit messy -//item_purpose = [description, ego modifier] -Intelligence.getItemPurpose = function() { - var roll = _.random(1,100); - switch(true) { - case (roll <= 20): - return {'description': 'Defeat/slay diametrically opposed alignment', - 'egoMod': 2}; - case (roll <= 30): - return {'description': 'Defeat/slay arcane spellcasters (including spellcasting monsters and those that use spell-like abilities)', - 'egoMod': 2}; - case (roll <= 40): - return {'description': 'Defeat/slay divine spellcasters (including divine entities and servitors)', - 'egoMod': 2}; - case (roll <= 50): - return {'description': 'Defeat/slay non-spellcasters', - 'egoMod': 2}; - case (roll <= 55): - return {'description': 'Defeat/slay all ' + Weapons.getBane().slice(8), //this probably isn't quite right but we'll keep it for now', - 'egoMod': 2}; - case (roll <= 60): - return {'description': 'Defeat/slay all ' + _.sample(['Humanoids (' + Grimoire.getHumanoidType() + ')', 'Outsiders (' + Grimoire.getOutsiderType() + ')']), - 'egoMod': 2}; - case (roll <= 70): - return {'description': 'Defend all ' + _.sample(['Humanoids (' + Grimoire.getHumanoidType() + ')', 'Outsiders (' + Grimoire.getOutsiderType() + ')']), - 'egoMod': 2}; - case (roll <= 80): - return {'description': 'Defeat/slay the servants of ' + Grimoire.getDeity(), - 'egoMod': 2}; - case (roll <= 90): - return {'description': 'Defend the servants of ' + Grimoire.getDeity(), - 'egoMod': 2}; - case (roll <= 95): - return {'description': 'Defeat/slay all (other than the item and the wielder)', - 'egoMod': 2}; - case (roll <= 100): - return {'description': 'Make something up! (GM discression)', - 'egoMod': 2}; - } -}; - -//another messy one -//dedicated_power = [description, base price modifier, ego modifier] -Intelligence.getDedicatedPower = function() { - var roll = _.random(1,100); - switch(true) { - case (roll <= 20): - return {'description': 'Item can detect any special purpose foes within 60 feet', - 'priceMod': 10000, 'egoMod': 1}; - case (roll <= 35): - return {'description': 'Item can cast ' + Spells.getLevelSpell(4).name + ' at will', - 'priceMod': 56000, 'egoMod': 2}; - case (roll <= 50): - return {'description': 'Wielder gets +2 luck bonus on attacks, saves, and checks', - 'priceMod': 80000, 'egoMod': 2}; - case (roll <= 65): - return {'description': 'Item can cast ' + Spells.getLevelSpell(5).name + ' at will', - 'priceMod': 90000, 'egoMod': 2}; - case (roll <= 80): - return {'description': 'Item can cast ' + Spells.getLevelSpell(6).name + ' at will', - 'priceMod': 132000, 'egoMod': 2}; - case (roll <= 95): - return {'description': 'Item can cast ' + Spells.getLevelSpell(7).name + ' at will', - 'priceMod': 182000, 'egoMod': 2}; - case (roll <= 100): - return {'description': 'Item can cast true resurrection on weilder, once per month', - 'priceMod': 200000, 'egoMod': 2}; - } -}; - -Intelligence.communication = [ - {'description': 'Empathy', 'priceMod': 0, 'egoMod': 0}, - {'description': 'Speech', 'priceMod': 500, 'egoMod': 0}, - {'description': 'Telepathy', 'priceMod': 1000, 'egoMod': 1}, - ]; -Intelligence.basicSenses = [ - {'description': 'Senses (30 ft.)', 'priceMod': 0, 'egoMod': 0}, - {'description': 'Senses (60 ft.)', 'priceMod': 500, 'egoMod': 0}, - {'description': 'Senses (120 ft.)', 'priceMod': 1000, 'egoMod': 0}, - ]; -Intelligence.specialSenses = [ - {'description': '', 'priceMod': 0, 'egoMod': 0}, - {'description': 'Darkvision', 'priceMod': 500, 'egoMod': 0}, - {'description': 'Blindsense', 'priceMod': 5000, 'egoMod': 1}, - {'description': 'Read languages', 'priceMod': 1000, 'egoMod': 1}, - {'description': 'Read magic', 'priceMod': 2000, 'egoMod': 1}, - ]; - -//Common was left out since ALL intelligent items speak common -//Druidic was left out since only Druids know it -//I was thinking of separating languages into generally 'good' or 'evil' but realized that was more up to DM discression -Intelligence.languages = ['Abyssal', 'Aklo', 'Aquan', 'Auran', 'Celestial', 'Draconic', - 'Dwarven', 'Elven', 'Giant', 'Gnome', 'Goblin', 'Gnoll', 'Halfling', - 'Ignan', 'Infernal', 'Orc', 'Sylvan', 'Terran', 'Undercommon']; - -//returns ['all stats, powers, and abilities', cost] -Intelligence.getItemIntelligence = function(basePrice) { - var cost = 500 + (basePrice === undefined ? 0 : basePrice); - var ego = 0; - switch(true) { - case (basePrice <= 1000): ego += 0; break; - case (basePrice <= 5000): ego += 1; break; - case (basePrice <= 10000): ego += 2; break; - case (basePrice <= 20000): ego += 3; break; - case (basePrice <= 50000): ego += 4; break; - case (basePrice <= 100000): ego += 6; break; - case (basePrice <= 200000): ego += 8; break; - case (basePrice > 200000): ego += 12; break; - } - - var sInt = Intelligence.getAbilityScore(); - var sCha = Intelligence.getAbilityScore(); - var sWis = Intelligence.getAbilityScore(); - - cost += sInt.priceMod + sCha.priceMod + sWis.priceMod; - ego += sInt.egoMod + sCha.egoMod + sWis.egoMod; - - var languages = ['Common']; - var bonusLanguages = Math.floor((sInt.score-10)/2); - //extra languages will be calculated after we see if it picked up ranks in Linguistics - - var communication = {}; - var roll = _.random(1,100); - //get communication ability for the item. there was no roll table so I made this up - switch(true) { - case (roll <= 30): communication = Intelligence.communication[0]; break; - case (roll <= 70): communication = Intelligence.communication[1]; break; - case (roll <= 100): communication = Intelligence.communication[2]; break; - } - var basicSenses = {}; - //get senses for the item. there was no roll table so I made this up - roll = _.random(1,100); - switch(true) { - case (roll <= 50): basicSenses = Intelligence.basicSenses[0]; break; - case (roll <= 80): basicSenses = Intelligence.basicSenses[1]; break; - case (roll <= 100): basicSenses = Intelligence.basicSenses[2]; break; - } - var specialSenses = {}; - //get special senses for the item. there was no roll table so I made this up - //and limited it to only 1 special per item - roll = _.random(1,100); - switch(true) { - case (roll <= 50): specialSenses = Intelligence.specialSenses[0]; break; - case (roll <= 70): specialSenses = Intelligence.specialSenses[0]; break; - case (roll <= 75): specialSenses = Intelligence.specialSenses[0]; break; - case (roll <= 90): specialSenses = Intelligence.specialSenses[0]; break; - case (roll <= 100): specialSenses = Intelligence.specialSenses[0]; break; - } - cost += communication.priceMod + basicSenses.priceMod + specialSenses.priceMod; - ego += communication.egoMod + basicSenses.egoMod + specialSenses.egoMod; - - - //Get item powers! - //So I was thinking of making the number of powers an item had somewhat based on the base cost - //but decided to instead roll it pure random items randomly get between 1-5 powers - //There is the possibility to get repeats of the SAME power - //In that case, I guess you would just add the numerical parts - // eg if 'fly at 30 ft/round' is rolled twice, it becomes 'fly at 60 ft/round' - var powers = []; - _.times(_.random(1,5), function() { - var power = Intelligence.getItemPower(); - powers.push(power); - cost += power.priceMod; - ego += power.egoMod; - if(power.description.indexOf('linguistics') >= 0) { - bonusLanguages += parseInt(power.description.match(/\d+/)[0]); - } - }); - - //add any extra languages to the known languages list - languages = _(languages).concat(_.sample(Intelligence.languages, bonusLanguages)).value(); - - //determining purpose - //there was NO roll chart for determining if an item has a purpose so I made this up - //I figure 20% of the time sounds good - - var purpose = {'description':'', 'egoMod': 0}; - var dedicatedPowers = []; - if(_.random(1,100) > 80) { - purpose = Intelligence.getItemPurpose(); - ego += purpose.egoMod; - - var pPowersNum = 1; - //I decided that purposed items get between 1-3 dedicated powers, heavily leaning on 1 - roll = _.random(1,100); - switch(true) { - case (roll <= 70): pPowersNum = 1; break; - case (roll <= 90): pPowersNum = 2; break; - case (roll <= 100): pPowersNum = 3; break; - } - - _.times(pPowersNum, function() { - var pPower = Intelligence.getDedicatedPower(); - dedicatedPowers.push(pPower); - cost += pPower.priceMod; - ego += pPower.egoMod; - }); - } - - var item = {}; - item.alignment = Grimoire.getAlignment(); - item.ego = ego; - item.intScore = sInt.score; - item.chaScore = sCha.score; - item.wisScore = sWis.score; - - item.communication = communication; - item.languages = languages; - - item.basicSenses = basicSenses; - item.specialSenses = specialSenses; - - item.powers = powers; - item.purpose = purpose; - item.dedicatedPowers = dedicatedPowers; - item.cost = cost; - item.print = function() { - var retStr = 'Alignment: ' + this.alignment + - ';Stats: Ego ' + this.ego + ' Int ' + this.intScore + ' Cha ' + this.chaScore + ' Wis ' + this.wisScore + - ';Communication: ' + this.communication.description; - this.languages.forEach(function(l, index) { retStr += ((index === 0) ? ';Languages: ' : ', ') + l;}); - retStr += ';Senses: ' + basicSenses.description + (!specialSenses.description) ? '' : (', ' + specialSenses.description); - this.powers.forEach(function(p, index) { - retStr += ((index === 0) ? ';Powers: ' : ', ') + p.description; - }); - if(this.purpose.description) { - retStr += ';Purpose: ' + this.purpose.description; - this.dedicatedPowers.forEach(function(p, index) { - retStr += ((index === 0) ? ';Dedicated Powers: ' : ', ') + p.description; - }); - } - retStr += ';Cost: ' + this.cost; - return retStr; - }; - - return item; -}; -/* - - - purpose += ' Dedicated Powers: ' - first = true - purpose_powers_num.times{ - purpose_power, cost_bonus, ego_bonus = get_dedicated_power() - if first - purpose += purpose_power - first = false - else - purpose += ', ' + purpose_power - end - cost += cost_bonus - ego += ego_bonus - } - end - return ['Alignment: ' + alignment + ' Stats: Ego ' + ego.to_s + ' Int ' + stat_int.to_s + ' Cha ' + stat_cha.to_s + ' Wis ' + - stat_wis.to_s + senses_and_communication + item_languages + powers + purpose, cost] - end - -end -*/ \ No newline at end of file diff --git a/shields.js b/shields.js deleted file mode 100644 index f8df3fa..0000000 --- a/shields.js +++ /dev/null @@ -1,166 +0,0 @@ -/*global _:false */ -/*global Grimoire:true */ -'use strict'; - -//TODO: Program the "Roll twice" logic - -var Shields = {}; -Shields.specificBaseUrl = 'http://paizo.com/pathfinderRPG/prd/magicItems/armor.html'; -Shields.getSpecifics = function() { - return [ - {'name': 'Darkwood buckler', 'bonus': 0, 'cost': 203, 'url': '#darkwood-buckler'}, - {'name': 'Darkwood shield', 'bonus': 0, 'cost': 257, 'url': ''}, - {'name': 'Mithral heavy shield', 'bonus': 0, 'cost': 1020, 'url': ''}, - {'name': 'Caster\'s shield', 'bonus': 0, 'cost': 3153, 'url': ''}, - {'name': 'Spined shield', 'bonus': 0, 'cost': 5580, 'url': ''}, - {'name': 'Lion\'s shield', 'bonus': 0, 'cost': 9170, 'url': ''}, - {'name': 'Winged shield', 'bonus': 0, 'cost': 17257, 'url': ''}, - {'name': 'Absorbing shield', 'bonus': 0, 'cost': 5017, 'url': ''} - ]; -}; - -Shields.getSpecific = function(type) { - var roll = _.random(1,100); - var shield = {}; - if(type == 'minor') { - switch(true) { - case (roll <= 30): shield = Shields.getSpecifics()[0]; break; - case (roll <= 80): shield = Shields.getSpecifics()[1]; break; - case (roll <= 95): shield = Shields.getSpecifics()[2]; break; - case (roll <= 100): shield = Shields.getSpecifics()[3]; break; - } - } - else if(type == 'medium') { - switch(true) { - case (roll <= 20): shield = Shields.getSpecifics()[0]; break; - case (roll <= 45): shield = Shields.getSpecifics()[1]; break; - case (roll <= 70): shield = Shields.getSpecifics()[2]; break; - case (roll <= 85): shield = Shields.getSpecifics()[3]; break; - case (roll <= 90): shield = Shields.getSpecifics()[4]; break; - case (roll <= 95): shield = Shields.getSpecifics()[5]; break; - case (roll <= 100): shield = Shields.getSpecifics()[6]; break; - } - } - else if(type == 'major') { - switch(true) { - case (roll <= 20): shield = Shields.getSpecifics()[3]; break; - case (roll <= 40): shield = Shields.getSpecifics()[4]; break; - case (roll <= 62): shield = Shields.getSpecifics()[5]; break; - case (roll <= 90): shield = Shields.getSpecifics()[6]; break; - case (roll <= 100): shield = Shields.getSpecifics()[7]; break; - } - } - return shield; -}; - -Shields.getShields = function() { - //5 possible roll'able shields. Specific type of shield is left up to DM - return [ - {'name': '+1 shield', 'bonus': 1, 'cost': 1000}, - {'name': '+2 shield', 'bonus': 2, 'cost': 4000}, - {'name': '+3 shield', 'bonus': 3, 'cost': 9000}, - {'name': '+4 shield', 'bonus': 4, 'cost': 16000}, - {'name': '+5 shield', 'bonus': 5, 'cost': 25000}, - {'name': '+6 shield', 'bonus': 6, 'cost': 36000}, - {'name': '+7 shield', 'bonus': 7, 'cost': 49000}, - {'name': '+8 shield', 'bonus': 8, 'cost': 64000}, - {'name': '+9 shield', 'bonus': 9, 'cost': 81000}, - {'name': '+10 shield', 'bonus': 10,'cost': 10000} - ]; -}; - -Shields.getSpecials = function() { - return [ - {'name': 'Arrow catching', 'bonus': 1, 'cost': 0}, - {'name': 'Bashing', 'bonus': 1, 'cost': 0}, - {'name': 'Blinding', 'bonus': 1, 'cost': 0}, - {'name': 'Light Fortification', 'bonus': 1, 'cost': 0}, - {'name': 'Arrow deflection', 'bonus': 2, 'cost': 0}, - {'name': 'Animated', 'bonus': 2, 'cost': 0}, - {'name': 'Spell resistance (13)', 'bonus': 2, 'cost': 0}, - {'name': 'Energy resistance (' + Grimoire.getEnergyResistance() + ')', 'bonus': 0, 'cost': 18000}, - {'name': 'Ghost touch', 'bonus': 3, 'cost': 0}, - {'name': 'Moderate Fortification', 'bonus': 3, 'cost': 0}, - {'name': 'Spell resistance (15)', 'bonus': 3, 'cost': 0}, - {'name': 'Wild', 'bonus': 3, 'cost': 0}, - {'name': 'Improved Energy resistance (' + Grimoire.getEnergyResistance() + ')', 'bonus': 0, 'cost': 42000}, - {'name': 'Spell resistance (17)', 'bonus': 4, 'cost': 0}, - {'name': 'Undead controlling', 'bonus': 0, 'cost': 49000}, - {'name': 'Fortification, heavy', 'bonus': 5, 'cost': 0}, - {'name': 'Reflecting', 'bonus': 5, 'cost': 0}, - {'name': 'Spell resistance (19)', 'bonus': 5, 'cost': 0}, - {'name': 'Energy resistance, greater (' + Grimoire.getEnergyResistance() + ')', 'bonus': 0, 'cost': 6600} - ]; -}; - -Shields.getSpecial = function(type) { - var roll = _.random(1,100); - if(type == 'minor') { - switch(true) { - case (roll <= 20): return Shields.getSpecials()[0]; - case (roll <= 40): return Shields.getSpecials()[1]; - case (roll <= 50): return Shields.getSpecials()[2]; - case (roll <= 75): return Shields.getSpecials()[3]; - case (roll <= 92): return Shields.getSpecials()[4]; - case (roll <= 97): return Shields.getSpecials()[5]; - case (roll <= 99): return Shields.getSpecials()[6]; - case (roll <= 100): /*roll twice*/ break; - } - } - else if(type == 'medium') { - switch(true) { - case (roll <= 10): return Shields.getSpecials()[0]; - case (roll <= 20): return Shields.getSpecials()[1]; - case (roll <= 25): return Shields.getSpecials()[2]; - case (roll <= 40): return Shields.getSpecials()[3]; - case (roll <= 50): return Shields.getSpecials()[4]; - case (roll <= 57): return Shields.getSpecials()[5]; - case (roll <= 59): return Shields.getSpecials()[6]; - case (roll <= 79): return Shields.getSpecials()[7]; - case (roll <= 85): return Shields.getSpecials()[8]; - case (roll <= 95): return Shields.getSpecials()[9]; - case (roll <= 98): return Shields.getSpecials()[10]; - case (roll <= 99): return Shields.getSpecials()[11]; - case (roll <= 100): /*roll twice*/ break; - } - } - else if(type == 'major') { - switch(true) { - case (roll <= 5): return Shields.getSpecials()[0]; - case (roll <= 8): return Shields.getSpecials()[1]; - case (roll <= 10): return Shields.getSpecials()[2]; - case (roll <= 15): return Shields.getSpecials()[3]; - case (roll <= 20): return Shields.getSpecials()[4]; - case (roll <= 25): return Shields.getSpecials()[5]; - case (roll <= 41): return Shields.getSpecials()[7]; - case (roll <= 46): return Shields.getSpecials()[8]; - case (roll <= 56): return Shields.getSpecials()[9]; - case (roll <= 58): return Shields.getSpecials()[10]; - case (roll <= 59): return Shields.getSpecials()[11]; - case (roll <= 84): return Shields.getSpecials()[12]; - case (roll <= 86): return Shields.getSpecials()[13]; - case (roll <= 87): return Shields.getSpecials()[14]; - case (roll <= 91): return Shields.getSpecials()[15]; - case (roll <= 93): return Shields.getSpecials()[16]; - case (roll <= 94): return Shields.getSpecials()[17]; - case (roll <= 99): return Shields.getSpecials()[18]; - case (roll <= 100): /*roll twice*/ break; - } - } - if(['minor','medium','major'].indexOf(type) >= 0 && roll == 100) { - var special1 = Shields.getSpecial(type); - var special2 = Shields.getSpecial(type); - //there exists a possibility of getting the same bonus or a bonus over +10 - //this is hilarious and has not been fixed - if(special1.bonus + special2.bonus <= 10) { - return {'name': special1.name + ' ' + special2.name, - 'bonus': special1.bonus + special2.bonus, - 'cost': special1.cost + special2.cost - }; - } - else { - //return the special with the better bonus. - return (special1.bonus > special2.bonus ? special1 : special2); - } - } -}; \ No newline at end of file diff --git a/sources/Banes.json b/sources/Banes.json new file mode 100644 index 0000000..b73eb5b --- /dev/null +++ b/sources/Banes.json @@ -0,0 +1,15 @@ +[ + { "name": "Aberations", "weight": 5}, + { "name": "Animals", "weight": 4}, + { "name": "Constructs", "weight": 7}, + { "name": "Dragons", "weight": 6}, + { "name": "Fey", "weight": 5}, + { "name": "Humanoids (GET_HUMANOID_TYPE)", "weight": 30}, + { "name": "Magical Beasts", "weight": 8}, + { "name": "Monstrous Humanoids", "weight": 5}, + { "name": "Oozes", "weight": 22}, + { "name": "Outsiders (GET_OUTSIDER_TYPE)", "weight": 16}, + { "name": "Plants", "weight": 2}, + { "name": "Undead", "weight": 8}, + { "name": "Vermin", "weight": 2} +] \ No newline at end of file diff --git a/sources/CRB/Armor and Shields.json b/sources/CRB/Armor and Shields.json new file mode 100644 index 0000000..dbcb335 --- /dev/null +++ b/sources/CRB/Armor and Shields.json @@ -0,0 +1,71 @@ +{ + "uniqueArmors": [ + {"name": "Mithral shirt", "cost": 1100, "url": "#mithril-shirt", "weight": { "minor": 50, "medium": 25, "major": 0} }, + {"name": "Dragonhide plate", "cost": 3300, "url":"", "weight": { "minor": 30, "medium": 20, "major": 0} }, + {"name": "Elven chain", "cost": 5150, "url":"", "weight": { "minor": 20, "medium": 12, "major": 0} }, + {"name": "Rhino hide", "cost": 5165, "url":"", "weight": { "minor": 0, "medium": 10, "major": 0} }, + {"name": "Adamantine breastplate", "cost": 10200, "url":"", "weight": { "minor": 0, "medium": 15, "major": 10} }, + {"name": "Dwarven plate", "cost": 16500, "url":"", "weight": { "minor": 0, "medium": 15, "major": 10} }, + {"name": "Banded mail of luck", "cost": 18900, "url":"", "weight": { "minor": 0, "medium": 3, "major": 12} }, + {"name": "Celestial armor", "cost": 22400, "url":"", "weight": { "minor": 0, "medium": 0, "major": 18} }, + {"name": "Plate armor of the deep", "cost": 24650, "url":"", "weight": { "minor": 0, "medium": 0, "major": 10} }, + {"name": "Breastplate of command", "cost": 25400, "url":"", "weight": { "minor": 0, "medium": 0, "major": 15} }, + {"name": "Mithral full plate of speed", "cost": 26500, "url":"", "weight": { "minor": 0, "medium": 0, "major": 15} }, + {"name": "Demon armor", "cost": 52260, "url":"", "weight": { "minor": 0, "medium": 0, "major": 10} } + ], + "armorSpecials": [ + {"name": "Glamered", "bonus": 0, "cost": 2700, "weight": {"minor": 25, "medium": 5, "major": 3} }, + {"name": "Light Fortification", "bonus": 1, "cost": 0, "weight": {"minor": 7, "medium": 3, "major": 1} }, + {"name": "Slick", "bonus": 0, "cost": 3750, "weight": {"minor": 20, "medium": 3, "major": 0} }, + {"name": "Shadow", "bonus": 0, "cost": 3750, "weight": {"minor": 40, "medium": 6, "major": 0} }, + {"name": "Spell resistance (13)", "bonus": 2, "cost": 0, "weight": {"minor": 4, "medium": 2, "major": 0} }, + {"name": "Improved Slick", "bonus": 0, "cost": 15000, "weight": {"minor": 1, "medium": 10, "major": 3} }, + {"name": "Improved Shadow", "bonus": 0, "cost": 15000, "weight": {"minor": 2, "medium": 20, "major": 6} }, + {"name": "Energy resistance (GET_ENERGY_RESISTANCE_TYPE)", "bonus": 0, "cost": 18000, "weight": {"minor": 0, "medium": 25, "major": 15} }, + {"name": "Ghost touch", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 5, "major": 5} }, + {"name": "Invulnerability", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 5, "major": 2} }, + {"name": "Moderate Fortification", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 5, "major": 5} }, + {"name": "Spell resistance (15)", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 5, "major": 2} }, + {"name": "Wild", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 5, "major": 1} }, + {"name": "Slick, greater", "bonus": 0, "cost": 33750, "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Shadow, greater", "bonus": 0, "cost": 33750, "weight": {"minor": 0, "medium": 0, "major": 10} }, + {"name": "Improved Energy resistance (GET_ENERGY_RESISTANCE_TYPE)", "bonus": 0, "cost": 42000, "weight": {"minor": 0, "medium": 0, "major": 30} }, + {"name": "Spell resistance (17)", "bonus": 4, "cost": 0, "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Etherealness", "bonus": 0, "cost": 49000, "weight": {"minor": 0, "medium": 0, "major": 1} }, + {"name": "Undead controlling", "bonus": 0, "cost": 49000, "weight": {"minor": 0, "medium": 0, "major": 1} }, + {"name": "Fortification, heavy", "bonus": 5, "cost": 0, "weight": {"minor": 0, "medium": 0, "major": 2} }, + {"name": "Spell resistance (19)", "bonus": 5, "cost": 0, "weight": {"minor": 0, "medium": 0, "major": 2} }, + {"name": "Energy resistance, greater (GET_ENERGY_RESISTANCE_TYPE)", "bonus": 0, "cost": 66000, "weight": {"minor": 0, "medium": 0, "major": 5} } + ], + "uniqueShields": [ + {"name": "Darkwood buckler", "cost": 203, "url": "#darkwood-buckler", "weight": { "minor": 30, "medium": 20, "major": 0} }, + {"name": "Darkwood shield", "cost": 257, "url": "", "weight": { "minor": 50, "medium": 25, "major": 0} }, + {"name": "Mithral heavy shield", "cost": 1020, "url": "", "weight": { "minor": 15, "medium": 25, "major": 0} }, + {"name": "Caster's shield", "cost": 3153, "url": "", "weight": { "minor": 5, "medium": 15, "major": 20} }, + {"name": "Spined shield", "cost": 5580, "url": "", "weight": { "minor": 0, "medium": 5, "major": 20} }, + {"name": "Lion's shield", "cost": 9170, "url": "", "weight": { "minor": 0, "medium": 5, "major": 22} }, + {"name": "Winged shield", "cost": 17257, "url": "", "weight": { "minor": 0, "medium": 5, "major": 28} }, + {"name": "Absorbing shield", "cost": 5017, "url": "", "weight": { "minor": 0, "medium": 0, "major": 10} } + ], + "shieldSpecials": [ + {"name": "Arrow catching", "bonus": 1, "cost": 0, "weight": {"minor": 20, "medium": 10, "major": 5} }, + {"name": "Bashing", "bonus": 1, "cost": 0, "weight": {"minor": 20, "medium": 10, "major": 3} }, + {"name": "Blinding", "bonus": 1, "cost": 0, "weight": {"minor": 10, "medium": 5, "major": 2} }, + {"name": "Light Fortification", "bonus": 1, "cost": 0, "weight": {"minor": 25, "medium": 15, "major": 5} }, + {"name": "Arrow deflection", "bonus": 2, "cost": 0, "weight": {"minor": 17, "medium": 10, "major": 5} }, + {"name": "Animated", "bonus": 2, "cost": 0, "weight": {"minor": 5, "medium": 7, "major": 5} }, + {"name": "Spell resistance (13)", "bonus": 2, "cost": 0, "weight": {"minor": 2, "medium": 2, "major": 0} }, + {"name": "Energy resistance (GET_ENERGY_RESISTANCE_TYPE)", "bonus": 0, "cost": 18000, "weight": {"minor": 0, "medium": 20, "major": 16} }, + {"name": "Ghost touch", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 6, "major": 5} }, + {"name": "Moderate Fortification", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 10, "major": 10} }, + {"name": "Spell resistance (15)", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 3, "major": 2} }, + {"name": "Wild", "bonus": 3, "cost": 0, "weight": {"minor": 0, "medium": 1, "major": 1} }, + {"name": "Improved Energy resistance (GET_ENERGY_RESISTANCE_TYPE)", "bonus": 0, "cost": 42000, "weight": {"minor": 0, "medium": 0, "major": 25} }, + {"name": "Spell resistance (17)", "bonus": 4, "cost": 0, "weight": {"minor": 0, "medium": 0, "major": 2} }, + {"name": "Undead controlling", "bonus": 0, "cost": 49000, "weight": {"minor": 0, "medium": 0, "major": 1} }, + {"name": "Fortification, heavy", "bonus": 5, "cost": 0, "weight": {"minor": 0, "medium": 0, "major": 4} }, + {"name": "Reflecting", "bonus": 5, "cost": 0, "weight": {"minor": 0, "medium": 0, "major": 2} }, + {"name": "Spell resistance (19)", "bonus": 5, "cost": 0, "weight": {"minor": 0, "medium": 0, "major": 1} }, + {"name": "Energy resistance, greater (GET_ENERGY_RESISTANCE_TYPE)", "bonus": 0, "cost": 6600, "weight": {"minor": 0, "medium": 0, "major": 5} } + ] +} \ No newline at end of file diff --git a/sources/CRB/Weapons.json b/sources/CRB/Weapons.json new file mode 100644 index 0000000..859038f --- /dev/null +++ b/sources/CRB/Weapons.json @@ -0,0 +1,87 @@ +{ + "uniqueWeapons": [ + {"name": "Sleep arrow", "cost": 132, "url": "#sleep-arrow", "weight": {"minor": 15, "medium": 0, "major": 0} }, + {"name": "Screaming bolt", "cost": 267, "url":"", "weight": {"minor": 10, "medium": 0, "major": 0} }, + {"name": "Silver dagger (masterwork)", "cost": 322, "url":"", "weight": {"minor": 20, "medium": 0, "major": 0} }, + {"name": "Cold iron longsword (masterwork)", "cost": 330, "url":"", "weight": {"minor": 20, "medium": 0, "major": 0} }, + {"name": "Javelin of lightning", "cost": 1500, "url":"", "weight": {"minor": 20, "medium": 9, "major": 0} }, + {"name": "Slaying arrow", "cost": 2282, "url":"", "weight": {"minor": 10, "medium": 6, "major": 0} }, + {"name": "Adamantine dagger", "cost": 3002, "url":"", "weight": {"minor": 5, "medium": 9, "major": 0} }, + {"name": "Adamantine battleaxe", "cost": 3010, "url":"", "weight": {"minor": 10, "medium": 9, "major": 0} }, + {"name": "Slaying arrow (greater)", "cost": 4057, "url":"", "weight": {"minor": 10, "medium": 4, "major": 0} }, + {"name": "Shatterspike", "cost": 4315, "url":"", "weight": {"minor": 0, "medium": 3, "major": 0} }, + {"name": "Dagger of venom", "cost": 8302, "url":"", "weight": {"minor": 0, "medium": 6, "major": 0} }, + {"name": "Trident of warning", "cost": 10115, "url":"", "weight": {"minor": 0, "medium": 5, "major": 0} }, + {"name": "Assassin\"s dagger", "cost": 10302, "url":"", "weight": {"minor": 0, "medium": 6, "major": 4} }, + {"name": "Shifter\"s sorrow", "cost": 12780, "url":"", "weight": {"minor": 0, "medium": 5, "major": 3} }, + {"name": "Trident of fish command", "cost": 18650, "url":"", "weight": {"minor": 0, "medium": 4, "major": 2} }, + {"name": "Flame tongue", "cost": 20715, "url":"", "weight": {"minor": 0, "medium": 8, "major": 4} }, + {"name": "Luck blade (0 wishes)", "cost": 22060, "url":"", "weight": {"minor": 0, "medium": 5, "major": 4} }, + {"name": "Sword of subtlety", "cost": 22310, "url":"", "weight": {"minor": 0, "medium": 7, "major": 7} }, + {"name": "Sword of the planes", "cost": 22315, "url":"", "weight": {"minor": 0, "medium": 5, "major": 7} }, + {"name": "Nine lives stealer", "cost": 23057, "url":"", "weight": {"minor": 0, "medium": 4, "major": 6} }, + {"name": "Oathbow", "cost": 25600, "url":"", "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Sword of life stealing", "cost": 25715, "url":"", "weight": {"minor": 0, "medium": 2, "major": 4} }, + {"name": "Mace of terror", "cost": 38552, "url":"", "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Life-drinker", "cost": 40320, "url":"", "weight": {"minor": 0, "medium": 0, "major": 6} }, + {"name": "Sylvan scimitar", "cost": 47315, "url":"", "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Rapier of puncturing", "cost": 50320, "url":"", "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Sun blade", "cost": 50335, "url":"", "weight": {"minor": 0, "medium": 0, "major": 6} }, + {"name": "Frost brand", "cost": 54475, "url":"", "weight": {"minor": 0, "medium": 0, "major": 6} }, + {"name": "Dwarven thrower", "cost": 60312, "url":"", "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Luck blade (1 wish)", "cost": 62360, "url":"", "weight": {"minor": 0, "medium": 0, "major": 7} }, + {"name": "Mace of smiting", "cost": 75312, "url":"", "weight": {"minor": 0, "medium": 0, "major": 4} }, + {"name": "Luck blade (2 wishes)", "cost": 102660, "url":"", "weight": {"minor": 0, "medium": 0, "major": 2} }, + {"name": "Holy avenger", "cost": 120630, "url":"", "weight": {"minor": 0, "medium": 0, "major": 1} }, + {"name": "Luck blade (3 wishes)", "cost": 14296, "url":"", "weight": {"minor": 0, "medium": 0, "major": 1} } + ], + "meleeSpecials" : [ + {"name": "Bane of GET_BANE_TYPE", "bonus": 1, "weight": {"minor": 10, "medium": 6, "major": 3} }, + {"name": "Defending", "bonus": 1, "weight": {"minor": 7, "medium": 6, "major": 0} }, + {"name": "Flaming", "bonus": 1, "weight": {"minor": 10, "medium": 7, "major": 3} }, + {"name": "Frost", "bonus": 1, "weight": {"minor": 10, "medium": 7, "major": 3} }, + {"name": "Shock", "bonus": 1, "weight": {"minor": 10, "medium": 7, "major": 3} }, + {"name": "Ghost touch", "bonus": 1, "weight": {"minor": 9, "medium": 5, "major": 3} }, + {"name": "Keen", "bonus": 1, "weight": {"minor": 11, "medium": 6, "major": 0} }, + {"name": "Ki Focus", "bonus": 1, "weight": {"minor": 4, "medium": 4, "major": 4} }, + {"name": "Merciful", "bonus": 1, "weight": {"minor": 4, "medium": 2, "major": 0} }, + {"name": "Mighty cleaving", "bonus": 1, "weight": {"minor": 7, "medium": 4, "major": 2} }, + {"name": "Spell storing", "bonus": 1, "weight": {"minor": 5, "medium": 5, "major": 3} }, + {"name": "Throwing", "bonus": 1, "weight": {"minor": 4, "medium": 4, "major": 4} }, + {"name": "Thundering", "bonus": 1, "weight": {"minor": 4, "medium": 2, "major": 4} }, + {"name": "Vicious", "bonus": 1, "weight": {"minor": 4, "medium": 4, "major": 4} }, + {"name": "Anarchic", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Axiomatic", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Disruption", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 3} }, + {"name": "Flaming burst", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Icy burst", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Holy", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Shocking burst", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Unholy", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Wounding", "bonus": 2, "weight": {"minor": 0, "medium": 2, "major": 4} }, + {"name": "Speed", "bonus": 3, "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Brilliant energy", "bonus": 4, "weight": {"minor": 0, "medium": 0, "major": 3} }, + {"name": "Dancing", "bonus": 4, "weight": {"minor": 0, "medium": 0, "major": 2} }, + {"name": "Vorpal", "bonus": 5, "weight": {"minor": 0, "medium": 0, "major": 2} } + ], + "rangedSpecials" : [ + {"name": "Bane of GET_BANE_TYPE", "bonus": 1, "weight": {"minor": 12, "medium": 8, "major": 4} }, + {"name": "Distance", "bonus": 1, "weight": {"minor": 13, "medium": 8, "major": 4} }, + {"name": "Flaming", "bonus": 1, "weight": {"minor": 15, "medium": 12, "major": 4} }, + {"name": "Frost", "bonus": 1, "weight": {"minor": 15, "medium": 12, "major": 4} }, + {"name": "Merciful", "bonus": 1, "weight": {"minor": 5, "medium": 2, "major": 0} }, + {"name": "Returning", "bonus": 1, "weight": {"minor": 8, "medium": 5, "major": 5} }, + {"name": "Shock", "bonus": 1, "weight": {"minor": 5, "medium": 12, "major": 4} }, + {"name": "Seeking", "bonus": 1, "weight": {"minor": 10, "medium": 5, "major": 2} }, + {"name": "Thundering", "bonus": 1, "weight": {"minor": 6, "medium": 4, "major": 2} }, + {"name": "Anarchic", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Axiomatic", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Flaming burst", "bonus": 2, "weight": {"minor": 0, "medium": 5, "major": 10} }, + {"name": "Holy", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Icy burst", "bonus": 2, "weight": {"minor": 0, "medium": 5, "major": 10} }, + {"name": "Shocking burst", "bonus": 2, "weight": {"minor": 0, "medium": 5, "major": 10} }, + {"name": "Unholy", "bonus": 2, "weight": {"minor": 0, "medium": 3, "major": 5} }, + {"name": "Speed", "bonus": 3, "weight": {"minor": 0, "medium": 0, "major": 5} }, + {"name": "Brilliant energy", "bonus": 4, "weight": {"minor": 0, "medium": 0, "major": 6} } + ] +} \ No newline at end of file diff --git a/sources/Deities.json b/sources/Deities.json index 4224951..a91e7b1 100644 --- a/sources/Deities.json +++ b/sources/Deities.json @@ -1,19 +1,19 @@ { "data": { - "lawful": { - "good" : ["Erastil", "Iomedae", "Torag"], - "neutral" : ["Abadar", "Irori"], - "evil" : ["Asmodeus", "Zon-Kuthon"] + "Lawful": { + "Good" : ["Erastil", "Iomedae", "Torag"], + "Neutral" : ["Abadar", "Irori"], + "Evil" : ["Asmodeus", "Zon-Kuthon"] }, - "neutral": { - "good" : ["Sarenrae"], - "neutral" : ["Gozreh", "Pharasma", "Nethys"], - "evil" : ["Urgathoa", "Norgorber"] + "Neutral": { + "Good" : ["Sarenrae"], + "Neutral" : ["Gozreh", "Pharasma", "Nethys"], + "Evil" : ["Urgathoa", "Norgorber"] }, - "chaotic" : { - "good" : ["Desna", "Cayden Cailean"], - "neutral" : ["Gorum", "Calistria"], - "evil" : ["Lamashtu", "Rovagug"] + "Chaotic" : { + "Good" : ["Desna", "Cayden Cailean"], + "Neutral" : ["Gorum", "Calistria"], + "Evil" : ["Lamashtu", "Rovagug"] } } } \ No newline at end of file diff --git a/sources/Humanoids.json b/sources/Humanoids.json new file mode 100644 index 0000000..fd7fa47 --- /dev/null +++ b/sources/Humanoids.json @@ -0,0 +1,13 @@ +[ + { "name": "Aquatic", "weight": 6}, + { "name": "Dwarf", "weight": 13}, + { "name": "Elf", "weight": 13}, + { "name": "Giant", "weight": 7}, + { "name": "Goblinoid", "weight": 6}, + { "name": "Gnoll", "weight": 7}, + { "name": "Gnome", "weight": 7}, + { "name": "Halfling", "weight": 8}, + { "name": "Human", "weight": 12}, + { "name": "Orc", "weight": 13}, + { "name": "Reptilian", "weight": 8} +] \ No newline at end of file diff --git a/sources/ItemDedicatedPowers.json b/sources/ItemDedicatedPowers.json new file mode 100644 index 0000000..a2ad036 --- /dev/null +++ b/sources/ItemDedicatedPowers.json @@ -0,0 +1,16 @@ +[ + { "description": "Item can detect any special purpose foes within 60 feet", + "costMod": 10000, "egoMod": 1, "weight": 20 }, + { "description": "Item can cast GET_SPELL_LEVEL_4 at will", + "costMod": 56000, "egoMod": 2, "weight": 15 }, + {"description": "Wielder gets +2 luck bonus on attacks, saves, and checks", + "costMod": 80000, "egoMod": 2, "weight": 15 }, + {"description": "Item can cast GET_SPELL_LEVEL_5 at will", + "costMod": 90000, "egoMod": 2, "weight": 15 }, + {"description": "Item can cast GET_SPELL_LEVEL_6 at will", + "costMod": 132000, "egoMod": 2, "weight": 25 }, + {"description": "Item can cast GET_SPELL_LEVEL_7 at will", + "costMod": 182000, "egoMod": 2, "weight": 15 }, + {"description": "Item can cast true resurrection on weilder, once per month", + "costMod": 200000, "egoMod": 2, "weight": 5 } +] \ No newline at end of file diff --git a/sources/ItemPowers.json b/sources/ItemPowers.json new file mode 100644 index 0000000..6768c5d --- /dev/null +++ b/sources/ItemPowers.json @@ -0,0 +1,32 @@ +[ + {"description": "Item can cast GET_SPELL_LEVEL_0 at will", + "costMod": 1000, "egoMod": 1, "repeatable": false, "weight": 10}, + {"description": "Item can cast GET_SPELL_LEVEL_1 #/day", + "costMod": 1200, "egoMod": 1, "repeatable": true, "value": 3, "weight": 10}, + {"description": "Item can use Magic Aura on itself at will", + "costMod": 2000, "egoMod": 1, "repeatable": false, "weight": 5}, + {"description": "Item can cast GET_SPELL_LEVEL_2 #/day", + "costMod": 2400, "egoMod": 1, "repeatable": true, "value": 1, "weight": 10}, + {"description": "Item has # ranks in GET_ITEM_SKILL", + "costMod": 2500, "egoMod": 1, "repeatable": true, "value": 5, "weight": 10}, + {"description": "Item can sprout limbs and move with a speed of # feet", + "costMod": 5000, "egoMod": 1, "repeatable": true, "value": 10, "weight": 5}, + {"description": "Item can cast GET_SPELL_LEVEL_3 #/day", + "costMod": 6000, "egoMod": 1, "repeatable": true, "value": 1, "weight": 5}, + {"description": "Item can cast GET_SPELL_LEVEL_2 #/day", + "costMod": 1000, "egoMod": 1, "repeatable": true, "value": 3, "weight": 5}, + {"description": "Item has # ranks in GET_ITEM_SKILL", + "costMod": 10000, "egoMod": 2, "repeatable": true, "value": 10, "weight": 10}, + {"description": "Item can change shape into # other form(s) of the same size", + "costMod": 10000, "egoMod": 2, "repeatable": true, "value": 1, "weight": 5}, + {"description": "Item can fly, as per the spell, at a speed of # feet", + "costMod": 10000, "egoMod": 2, "repeatable": true, "value": 30, "weight": 5}, + {"description": "Item can cast GET_SPELL_LEVEL_4 #/day", + "costMod": 11200, "egoMod": 2, "repeatable": true, "value": 1, "weight": 5}, + {"description": "Item can cast teleport itself #/day", + "costMod": 15000, "egoMod": 2, "repeatable": true, "value": 1, "weight": 5}, + {"description": "Item can cast GET_SPELL_LEVEL_3 #/day", + "costMod": 18000, "egoMod": 2, "repeatable": true, "value": 3, "weight": 5}, + {"description": "Item can cast GET_SPELL_LEVEL_4 #/day", + "costMod": 33600, "egoMod": 2, "repeatable": true, "value": 3, "weight": 5} +] \ No newline at end of file diff --git a/sources/ItemPurposes.json b/sources/ItemPurposes.json new file mode 100644 index 0000000..c59893a --- /dev/null +++ b/sources/ItemPurposes.json @@ -0,0 +1,15 @@ +[ + {"description": "Defeat/slay diametrically opposed alignment", "egoMod": 2, "weight": 20 }, + {"description": "Defeat/slay arcane spellcasters (including spellcasting monsters and those that use spell-like abilities)", + "egoMod": 2, "weight": 10 }, + {"description": "Defeat/slay divine spellcasters (including divine entities and servitors)", + "egoMod": 2, "weight": 10 }, + {"description": "Defeat/slay non-spellcasters", "egoMod": 2, "weight": 10 }, + {"description": "Defeat/slay all GET_BANE", "egoMod": 2, "weight": 5 }, + {"description": "Defeat/slay all GET_HUMANOID_OR_OUTSIDER_TYPE", "egoMod": 2, "weight": 5 }, + {"description": "Defend all GET_HUMANOID_OR_OUTSIDER_TYPE","egoMod": 2, "weight": 10 }, + {"description": "Defeat/slay the servants of GET_DEITY", "egoMod": 2, "weight": 10 }, + {"description": "Defend the servants of GET_DEITY", "egoMod": 2, "weight": 10 }, + {"description": "Defeat/slay all (other than the item and the wielder)", "egoMod": 2, "weight": 5 }, + {"description": "Make something up! (GM discression)", "egoMod": 2, "weight": 5 } +] \ No newline at end of file diff --git a/sources/ItemSkills.json b/sources/ItemSkills.json new file mode 100644 index 0000000..343da7e --- /dev/null +++ b/sources/ItemSkills.json @@ -0,0 +1,22 @@ +[ + { "name": "Appraise", "type": "intelligence" }, + { "name": "Knowledge (arcana)", "type": "intelligence" }, + { "name": "Knowledge (dungeoneering)", "type": "intelligence" }, + { "name": "Knowledge (engineering)", "type": "intelligence" }, + { "name": "Knowledge (geography)", "type": "intelligence" }, + { "name": "Knowledge (history)", "type": "intelligence" }, + { "name": "Knowledge (local)", "type": "intelligence" }, + { "name": "Knowledge (nature)", "type": "intelligence" }, + { "name": "Knowledge (nobility)", "type": "intelligence" }, + { "name": "Knowledge (planes)", "type": "intelligence" }, + { "name": "Knowledge (religion)", "type": "intelligence" }, + { "name": "Linguistics", "type": "intelligence" }, + { "name": "Spellcraft", "type": "intelligence" }, + { "name": "Bluff", "type": "charisma" }, + { "name": "Diplomacy", "type": "charisma" }, + { "name": "Intimidate", "type": "charisma" }, + { "name": "Perform", "type": "charisma" }, + { "name": "Perception", "type": "wisdom" }, + { "name": "Sense Motive", "type": "wisdom" }, + { "name": "Survival", "type": "wisdom" } +] \ No newline at end of file diff --git a/sources/Languages.json b/sources/Languages.json new file mode 100644 index 0000000..ef79f07 --- /dev/null +++ b/sources/Languages.json @@ -0,0 +1,23 @@ +{ + "data": [ + "Abyssal", + "Aklo", + "Aquan", + "Auran", + "Celestial", + "Draconic", + "Dwarven", + "Elven", + "Giant", + "Gnome", + "Goblin", + "Gnoll", + "Halfling", + "Ignan", + "Infernal", + "Orc", + "Sylvan", + "Terran", + "Undercommon" + ] +} \ No newline at end of file diff --git a/sources/Outsiders.json b/sources/Outsiders.json new file mode 100644 index 0000000..ce5e258 --- /dev/null +++ b/sources/Outsiders.json @@ -0,0 +1,11 @@ +[ + { "name": "Air", "weight": 11}, + { "name": "Earth", "weight": 11}, + { "name": "Fire", "weight": 11}, + { "name": "Water", "weight": 11}, + { "name": "Chaotic", "weight": 11}, + { "name": "Evil", "weight": 11}, + { "name": "Good", "weight": 11}, + { "name": "Lawful", "weight": 11}, + { "name": "Native", "weight": 12} +] \ No newline at end of file diff --git a/sources/UC.json b/sources/UC.json new file mode 100644 index 0000000..dcb78e2 --- /dev/null +++ b/sources/UC.json @@ -0,0 +1,7 @@ +{ + "name": "Ultimate Combat", + "shortName": "UC", + "types": [ + {"name": "Spells", "source": "sources/UC/Spells.json"} + ] +} \ No newline at end of file diff --git a/sources/UC/Spells.json b/sources/UC/Spells.json new file mode 100644 index 0000000..3c3f2be --- /dev/null +++ b/sources/UC/Spells.json @@ -0,0 +1,26 @@ +{ + "Arcane": [ + ["Haunted Fey Aspect"], + ["Adjuring Step", "Abundant Ammunition", "Adoration", "Compel Hostility", "Deadeye's Lore", "Jury-Rig", "Liberating Command", "Lock Gaze", "Moment of Greatness", "Negative Reaction", "See Alignment", "Illusion of Calm", "Longshot", "Mirror Strike", "Reinforce Armaments", "Returning Weapon", "Shock Shield", "Unerring Weapon", "Warding Weapon", "Air Bubble", "Damp Powder", "Fabricate Bullets", "Peacebond", "Weaken Powder", "Life Conduit"], + ["Blistering Invective", "Discovery Torch", "Pilfering Hand", "Qualm", "Returning Weapon", "Share Language, Communal", "Tactical Acumen", "Thunder Fire", "Adoration", "Animal Aspect", "Ant Haul, Communal", "Bestow Weapon Proficiency", "Brow Gasher", "Bullet Shield", "Certain Grip", "Destabilize Powder", "Endure Elements, Communal", "Fiery Shuriken", "Frost Fall", "Kinetic Reverberation", "Magic Siege Engine", "Mount, Communal", "Reloading Hands", "Protection from Chaos, Communal", "Protection from Evil, Communal", "Protection from Good, Communal", "Protection from Law, Communal", "Recoil Fire", "Reinforce Armaments, Communal", "Ricochet Shot", "Spontaneous Immolation", "Stabilize Powder", "Telekinetic Assembly", "Twisted Space", "Warding Weapon", "Ablative Barrier", "Mask Dweomer, Communal"], + ["Delay Poison, Communal", "Phantom Driver", "Returning Weapon, Communal", "Tongues, Communal", "Ablative Barrier", "Animal Aspect", "Bestow Weapon Proficiency", "Brow Gasher", "Effortless Armor", "Mount, Communal", "Pilfering Hand", "Reloading Hands", "Reinforce Armaments, Communal", "Tactical Acumen", "Telekinetic Assembly", "Twisted Space", "Animal Aspect, Greater", "Burst of Speed", "Locate Weakness", "Chain of Perdition", "Darkvision, Communal", "Flash Fire", "Healing Thief", "Hostile Levitation", "Pellet Blast", "Protection from Arrows, Communal", "Pup Shape", "Resinous Skin", "Resist Energy, Communal", "Share Language, Communal", "Spider Climb, Communal", "Touch Injection", "Life Conduit, Improved", "Obsidian Flow", "Phantom Chariot", "Phantom Steed, Communal"], + ["Phantom Steed, Communal", "Shocking Image", "Pellet Blast", "Wreath of Blades", "Animal Aspect, Greater", "Magic Siege Engine, Greater", "Named Bullet", "Nondetection, Communal", "Obsidian Flow", "Phantom Chariot", "Protection from Energy, Communal", "Telekinetic Charge", "Tongues, Communal", "Hostile Juxtaposition", "Stoneskin, Communal", "Summoner Conduit", "Absorb Toxicity", "Debilitating Portent"], + ["Symbol of Striking", "Absorb Toxicity", "Energy Siege Shot", "Hostile Juxtaposition", "Stoneskin, Communal", "Summoner Conduit", "Wreath of Blades", "Life Conduit, Greater", "Tar Pool"], + ["Walk through Space", "Energy Siege Shot, Greater", "Named Bullet, Greater", "Tar Pool", "Hostile Juxtaposition, Greater", "Dust Form"], + ["Arcane Cannon", "Hostile Juxtaposition, Greater", "Walk through Space", "Walk through Space"], + ["Frightful Aspect"], + ["Heroic Invocation", "Mind Blank, Communal"] + ], + "Divine": [ + [], + ["Abundant Ammunition", "Air Bubble", "Compel Hostility", "Deadeye's Lore", "Liberating Command", "Moment of Greatness", "Reinforce Armaments", "Sun Metal", "Damp Powder", "Weaken Powder", "Bowstaff", "Litany of Sloth", "Litany of Weakness", "Lock Gaze", "Longshot", "Peacebond", "Returning Weapon", "Unerring Weapon", "Tactical Acumen"], + ["Ant Haul, Communal", "Bestow Weapon Proficiency", "Effortless Armor", "Endure Elements, Communal", "Instrument of Agony", "Magic Siege Engine", "Pilfering Hand", "Protection from Chaos, Communal", "Protection from Evil, Communal", "Protection from Good, Communal", "Protection from Law, Communal", "Reinforce Armaments, Communal", "Returning Weapon", "Animal Aspect", "Certain Grip", "Forest Friend", "Frost Fall", "Wilderness Soldiers", "Blistering Invective", "Brow Gasher", "Discovery Torch", "Litany of Defense", "Qualm", "Returning Weapon, Communal", "Tactical Acumen", "Divine Arrow", "Litany of Eloquence", "Litany of Entanglement", "Litany of Righteousness", "Litany of Warding", "Locate Weakness", "Reloading Hands", "Ricochet Shot"], + ["Chain of Perdition", "Daybreak Arrow", "Deadly Juggernaut", "Delay Poison, Communal", "Discovery Torch", "Resist Energy, Communal", "Returning Weapon, Communal", "Share Language, Communal", "Animal Aspect, Greater", "Companion Mind Link", "Pup Shape", "Resinous Skin", "Spider Climb, Communal", "Burst of Speed", "Litany of Eloquence", "Litany of Entanglement", "Litany of Righteousness", "Litany of Warding", "Locate Weakness", "Litany of Escape", "Litany of Sight", "Named Bullet", "Protection from Energy, Communal"], + ["Debilitating Portent", "Protection from Energy, Communal", "Summoner Conduit", "Water Walk, Communal", "Absorb Toxicity", "Obsidian Flow", "Find Quarry", "Judgment Light", "Litany of Escape", "Litany of Sight", "Magic Siege Engine, Greater", "Named Bullet", "Litany of Thunder", "Litany of Vengeance", "Darkvision, Communal", "Named Bullet, Greater", "Terrain Bond"], + ["Air Walk, Communal", "Magic Siege Engine, Greater", "Spell Immunity, Communal", "Symbol of Striking", "Tongues, Communal", "Litany of Thunder", "Litany of Vengeance", "Stoneskin, Communal"], + ["Dust Form", "Stoneskin, Communal", "Tar Pool", "Litany of Madness", "Named Bullet, Greater"], + ["Jolting Portent", "Siege of Trees"], + ["Frightful Aspect"], + ["Spell Immunity, Greater Communal", "Siege of Trees, Greater"] + ] +} \ No newline at end of file diff --git a/sources/sources.json b/sources/sources.json index 6f8de58..1350617 100644 --- a/sources/sources.json +++ b/sources/sources.json @@ -10,6 +10,10 @@ "sources/Deities.json", "sources/Humanoids.json", "sources/Outsiders.json", - "sources/ItemSkills.json" + "sources/ItemSkills.json", + "sources/Languages.json", + "sources/ItemPowers.json", + "sources/ItemPurposes.json", + "sources/ItemDedicatedPowers.json" ] } \ No newline at end of file diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..e108a0b --- /dev/null +++ b/todo.txt @@ -0,0 +1,16 @@ +Pathfinder magic item automatic roller +To do: + +* Refactor code into GrimoireCore and resouce JSON objects + +* Reformat all the .js data files into JSON resources + +* Add roll weights for + = CRB + - Rings + = APG + - Rings + +* I'm getting a problem where the random number generator is reliably getting the SAME item from a weighted list and I'm not sure why. + = This is occuring for getHumanoid, getOutsider, getDeity, and several other lowest level methods + when called from higher order functions like getIntelligence or getWeapon \ No newline at end of file