Files
GrimoireJS/intelligence.js
T

390 lines
17 KiB
JavaScript

/*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
*/