mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-13 04:22:40 +00:00
Remove redundant helper files for DMG snippets
This commit is contained in:
@@ -1,42 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
const dedent = require('dedent-tabs').default;
|
|
||||||
|
|
||||||
module.exports = function(classname){
|
|
||||||
|
|
||||||
classname = _.sample(['archivist', 'fancyman', 'linguist', 'fletcher',
|
|
||||||
'notary', 'berserker-typist', 'fishmongerer', 'manicurist', 'haberdasher', 'concierge']);
|
|
||||||
|
|
||||||
classname = classname.toLowerCase();
|
|
||||||
|
|
||||||
const hitDie = _.sample([4, 6, 8, 10, 12]);
|
|
||||||
|
|
||||||
const abilityList = ['Strength', 'Dexerity', 'Constitution', 'Wisdom', 'Charisma', 'Intelligence'];
|
|
||||||
const skillList = ['Acrobatics', 'Animal Handling', 'Arcana', 'Athletics', 'Deception', 'History', 'Insight', 'Intimidation', 'Investigation', 'Medicine', 'Nature', 'Perception', 'Performance', 'Persuasion', 'Religion', 'Sleight of Hand', 'Stealth', 'Survival'];
|
|
||||||
|
|
||||||
|
|
||||||
return dedent`
|
|
||||||
## Class Features
|
|
||||||
As a ${classname}, you gain the following class features
|
|
||||||
#### Hit Points
|
|
||||||
|
|
||||||
**Hit Dice:** :: 1d${hitDie} per ${classname} level
|
|
||||||
**Hit Points at 1st Level:** :: ${hitDie} + your Constitution modifier
|
|
||||||
**Hit Points at Higher Levels:** :: 1d${hitDie} (or ${hitDie/2 + 1}) + your Constitution modifier per ${classname} level after 1st
|
|
||||||
|
|
||||||
#### Proficiencies
|
|
||||||
|
|
||||||
**Armor:** :: ${_.sampleSize(['Light armor', 'Medium armor', 'Heavy armor', 'Shields'], _.random(0, 3)).join(', ') || 'None'}
|
|
||||||
**Weapons:** :: ${_.sampleSize(['Squeegee', 'Rubber Chicken', 'Simple weapons', 'Martial weapons'], _.random(0, 2)).join(', ') || 'None'}
|
|
||||||
**Tools:** :: ${_.sampleSize(['Artian\'s tools', 'one musical instrument', 'Thieve\'s tools'], _.random(0, 2)).join(', ') || 'None'}
|
|
||||||
|
|
||||||
**Saving Throws:** :: ${_.sampleSize(abilityList, 2).join(', ')}
|
|
||||||
**Skills:** :: Choose two from ${_.sampleSize(skillList, _.random(4, 6)).join(', ')}
|
|
||||||
|
|
||||||
#### Equipment
|
|
||||||
You start with the following equipment, in addition to the equipment granted by your background:
|
|
||||||
- *(a)* a martial weapon and a shield or *(b)* two martial weapons
|
|
||||||
- *(a)* five javelins or *(b)* any simple melee weapon
|
|
||||||
- ${_.sample(['10 lint fluffs', '1 button', 'a cherished lost sock'])}
|
|
||||||
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
const features = [
|
|
||||||
'Astrological Botany',
|
|
||||||
'Biochemical Sorcery',
|
|
||||||
'Civil Divination',
|
|
||||||
'Consecrated Augury',
|
|
||||||
'Demonic Anthropology',
|
|
||||||
'Divinatory Mineralogy',
|
|
||||||
'Exo Interfacer',
|
|
||||||
'Genetic Banishing',
|
|
||||||
'Gunpowder Torturer',
|
|
||||||
'Gunslinger Corruptor',
|
|
||||||
'Hermetic Geography',
|
|
||||||
'Immunological Cultist',
|
|
||||||
'Malefic Chemist',
|
|
||||||
'Mathematical Pharmacy',
|
|
||||||
'Nuclear Biochemistry',
|
|
||||||
'Orbital Gravedigger',
|
|
||||||
'Pharmaceutical Outlaw',
|
|
||||||
'Phased Linguist',
|
|
||||||
'Plasma Gunslinger',
|
|
||||||
'Police Necromancer',
|
|
||||||
'Ritual Astronomy',
|
|
||||||
'Sixgun Poisoner',
|
|
||||||
'Seismological Alchemy',
|
|
||||||
'Spiritual Illusionism',
|
|
||||||
'Statistical Occultism',
|
|
||||||
'Spell Analyst',
|
|
||||||
'Torque Interfacer'
|
|
||||||
];
|
|
||||||
|
|
||||||
const classnames = ['Ackerman', 'Berserker-Typist', 'Concierge', 'Fishmonger',
|
|
||||||
'Haberdasher', 'Manicurist', 'Netrunner', 'Weirkeeper'];
|
|
||||||
|
|
||||||
const levels = ['1st', '2nd', '3rd', '4th', '5th',
|
|
||||||
'6th', '7th', '8th', '9th', '10th',
|
|
||||||
'11th', '12th', '13th', '14th', '15th',
|
|
||||||
'16th', '17th', '18th', '19th', '20th'];
|
|
||||||
|
|
||||||
const profBonus = [2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6];
|
|
||||||
|
|
||||||
const maxes = [4, 3, 3, 3, 3, 2, 2, 1, 1];
|
|
||||||
|
|
||||||
const drawSlots = function(Slots, rows, padding){
|
|
||||||
let slots = Number(Slots);
|
|
||||||
return _.times(rows, function(i){
|
|
||||||
const max = maxes[i];
|
|
||||||
if(slots < 1) return _.pad('—', padding);
|
|
||||||
const res = _.min([max, slots]);
|
|
||||||
slots -= res;
|
|
||||||
return _.pad(res.toString(), padding);
|
|
||||||
}).join(' | ');
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
full : function(classes){
|
|
||||||
const classname = _.sample(classnames);
|
|
||||||
|
|
||||||
|
|
||||||
let cantrips = 3;
|
|
||||||
let spells = 1;
|
|
||||||
let slots = 2;
|
|
||||||
return `{{${classes}\n##### The ${classname}\n` +
|
|
||||||
`| Level | Proficiency | Features | Cantrips | Spells | --- Spell Slots Per Spell Level ---|||||||||\n`+
|
|
||||||
`| ^| Bonus ^| ^| Known ^| Known ^|1st |2nd |3rd |4th |5th |6th |7th |8th |9th |\n`+
|
|
||||||
`|:-----:|:-----------:|:-------------|:--------:|:------:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|\n${
|
|
||||||
_.map(levels, function(levelName, level){
|
|
||||||
const res = [
|
|
||||||
_.pad(levelName, 5),
|
|
||||||
_.pad(`+${profBonus[level]}`, 2),
|
|
||||||
_.padEnd(_.sample(features), 21),
|
|
||||||
_.pad(cantrips.toString(), 8),
|
|
||||||
_.pad(spells.toString(), 6),
|
|
||||||
drawSlots(slots, 9, 2),
|
|
||||||
].join(' | ');
|
|
||||||
|
|
||||||
cantrips += _.random(0, 1);
|
|
||||||
spells += _.random(0, 1);
|
|
||||||
slots += _.random(0, 2);
|
|
||||||
|
|
||||||
return `| ${res} |`;
|
|
||||||
}).join('\n')}\n}}\n\n`;
|
|
||||||
},
|
|
||||||
|
|
||||||
half : function(classes){
|
|
||||||
const classname = _.sample(classnames);
|
|
||||||
|
|
||||||
let featureScore = 1;
|
|
||||||
return `{{${classes}\n##### The ${classname}\n` +
|
|
||||||
`| Level | Proficiency Bonus | Features | ${_.pad(_.sample(features), 21)} |\n` +
|
|
||||||
`|:-----:|:-----------------:|:---------|:---------------------:|\n${
|
|
||||||
_.map(levels, function(levelName, level){
|
|
||||||
const res = [
|
|
||||||
_.pad(levelName, 5),
|
|
||||||
_.pad(`+${profBonus[level]}`, 2),
|
|
||||||
_.padEnd(_.sample(features), 23),
|
|
||||||
_.pad(`+${featureScore}`, 21),
|
|
||||||
].join(' | ');
|
|
||||||
|
|
||||||
featureScore += _.random(0, 1);
|
|
||||||
|
|
||||||
return `| ${res} |`;
|
|
||||||
}).join('\n')}\n}}\n\n`;
|
|
||||||
},
|
|
||||||
|
|
||||||
third : function(classes){
|
|
||||||
const classname = _.sample(classnames);
|
|
||||||
|
|
||||||
let cantrips = 3;
|
|
||||||
let spells = 1;
|
|
||||||
let slots = 2;
|
|
||||||
return `{{${classes}\n##### ${classname} Spellcasting\n` +
|
|
||||||
`| Class | Cantrips | Spells |--- Spells Slots per Spell Level ---||||\n` +
|
|
||||||
`| Level ^| Known ^| Known ^| 1st | 2nd | 3rd | 4th |\n` +
|
|
||||||
`|:------:|:--------:|:-------:|:-------:|:-------:|:-------:|:-------:|\n${
|
|
||||||
_.map(levels, function(levelName, level){
|
|
||||||
const res = [
|
|
||||||
_.pad(levelName, 6),
|
|
||||||
_.pad(cantrips.toString(), 8),
|
|
||||||
_.pad(spells.toString(), 7),
|
|
||||||
drawSlots(slots, 4, 7),
|
|
||||||
].join(' | ');
|
|
||||||
|
|
||||||
cantrips += _.random(0, 1);
|
|
||||||
spells += _.random(0, 1);
|
|
||||||
slots += _.random(0, 1);
|
|
||||||
|
|
||||||
return `| ${res} |`;
|
|
||||||
}).join('\n')}\n}}\n\n`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
const titles = [
|
|
||||||
'The Burning Gallows',
|
|
||||||
'The Ring of Nenlast',
|
|
||||||
'Below the Blind Tavern',
|
|
||||||
'Below the Hungering River',
|
|
||||||
'Before Bahamut\'s Land',
|
|
||||||
'The Cruel Grave from Within',
|
|
||||||
'The Strength of Trade Road',
|
|
||||||
'Through The Raven Queen\'s Worlds',
|
|
||||||
'Within the Settlement',
|
|
||||||
'The Crown from Within',
|
|
||||||
'The Merchant Within the Battlefield',
|
|
||||||
'Ioun\'s Fading Traveler',
|
|
||||||
'The Legion Ingredient',
|
|
||||||
'The Explorer Lure',
|
|
||||||
'Before the Charming Badlands',
|
|
||||||
'The Living Dead Above the Fearful Cage',
|
|
||||||
'Vecna\'s Hidden Sage',
|
|
||||||
'Bahamut\'s Demonspawn',
|
|
||||||
'Across Gruumsh\'s Elemental Chaos',
|
|
||||||
'The Blade of Orcus',
|
|
||||||
'Beyond Revenge',
|
|
||||||
'Brain of Insanity',
|
|
||||||
'Breed Battle!, A New Beginning',
|
|
||||||
'Evil Lake, A New Beginning',
|
|
||||||
'Invasion of the Gigantic Cat, Part II',
|
|
||||||
'Kraken War 2020',
|
|
||||||
'The Body Whisperers',
|
|
||||||
'The Diabolical Tales of the Ape-Women',
|
|
||||||
'The Doctor Immortal',
|
|
||||||
'The Doctor from Heaven',
|
|
||||||
'The Graveyard',
|
|
||||||
'Azure Core',
|
|
||||||
'Core Battle',
|
|
||||||
'Core of Heaven: The Guardian of Amazement',
|
|
||||||
'Deadly Amazement III',
|
|
||||||
'Dry Chaos IX',
|
|
||||||
'Gate Thunder',
|
|
||||||
'Guardian: Skies of the Dark Wizard',
|
|
||||||
'Lute of Eternity',
|
|
||||||
'Mercury\'s Planet: Brave Evolution',
|
|
||||||
'Ruby of Atlantis: The Quake of Peace',
|
|
||||||
'Sky of Zelda: The Thunder of Force',
|
|
||||||
'Vyse\'s Skies',
|
|
||||||
'White Greatness III',
|
|
||||||
'Yellow Divinity',
|
|
||||||
'Zidane\'s Ghost'
|
|
||||||
];
|
|
||||||
|
|
||||||
const subtitles = [
|
|
||||||
'In an ominous universe, a botanist opposes terrorism.',
|
|
||||||
'In a demon-haunted city, in an age of lies and hate, a physicist tries to find an ancient treasure and battles a mob of aliens.',
|
|
||||||
'In a land of corruption, two cyberneticists and a dungeon delver search for freedom.',
|
|
||||||
'In an evil empire of horror, two rangers battle the forces of hell.',
|
|
||||||
'In a lost city, in an age of sorcery, a librarian quests for revenge.',
|
|
||||||
'In a universe of illusions and danger, three time travellers and an adventurer search for justice.',
|
|
||||||
'In a forgotten universe of barbarism, in an era of terror and mysticism, a virtual reality programmer and a spy try to find vengance and battle crime.',
|
|
||||||
'In a universe of demons, in an era of insanity and ghosts, three bodyguards and a bodyguard try to find vengance.',
|
|
||||||
'In a kingdom of corruption and battle, seven artificial intelligences try to save the last living fertile woman.',
|
|
||||||
'In a universe of virutal reality and agony, in an age of ghosts and ghosts, a fortune-teller and a wanderer try to avert the apocalypse.',
|
|
||||||
'In a crime-infested kingdom, three martial artists quest for the truth and oppose evil.',
|
|
||||||
'In a terrifying universe of lost souls, in an era of lost souls, eight dancers fight evil.',
|
|
||||||
'In a galaxy of confusion and insanity, three martial artists and a duke battle a mob of psychics.',
|
|
||||||
'In an amazing kingdom, a wizard and a secretary hope to prevent the destruction of mankind.',
|
|
||||||
'In a kingdom of deception, a reporter searches for fame.',
|
|
||||||
'In a hellish empire, a swordswoman and a duke try to find the ultimate weapon and battle a conspiracy.',
|
|
||||||
'In an evil galaxy of illusion, in a time of technology and misery, seven psychiatrists battle crime.',
|
|
||||||
'In a dark city of confusion, three swordswomen and a singer battle lawlessness.',
|
|
||||||
'In an ominous empire, in an age of hate, two philosophers and a student try to find justice and battle a mob of mages intent on stealing the souls of the innocent.',
|
|
||||||
'In a kingdom of panic, six adventurers oppose lawlessness.',
|
|
||||||
'In a land of dreams and hopelessness, three hackers and a cyborg search for justice.',
|
|
||||||
'On a planet of mysticism, three travelers and a fire fighter quest for the ultimate weapon and oppose evil.',
|
|
||||||
'In a wicked universe, five seers fight lawlessness.',
|
|
||||||
'In a kingdom of death, in an era of illusion and blood, four colonists search for fame.',
|
|
||||||
'In an amazing kingdom, in an age of sorcery and lost souls, eight space pirates quest for freedom.',
|
|
||||||
'In a cursed empire, five inventors oppose terrorism.',
|
|
||||||
'On a crime-ridden planet of conspiracy, a watchman and an artificial intelligence try to find love and oppose lawlessness.',
|
|
||||||
'In a forgotten land, a reporter and a spy try to stop the apocalypse.',
|
|
||||||
'In a forbidden land of prophecy, a scientist and an archivist oppose a cabal of barbarians intent on stealing the souls of the innocent.',
|
|
||||||
'On an infernal world of illusion, a grave robber and a watchman try to find revenge and combat a syndicate of mages intent on stealing the source of all magic.',
|
|
||||||
'In a galaxy of dark magic, four fighters seek freedom.',
|
|
||||||
'In an empire of deception, six tomb-robbers quest for the ultimate weapon and combat an army of raiders.',
|
|
||||||
'In a kingdom of corruption and lost souls, in an age of panic, eight planetologists oppose evil.',
|
|
||||||
'In a galaxy of misery and hopelessness, in a time of agony and pain, five planetologists search for vengance.',
|
|
||||||
'In a universe of technology and insanity, in a time of sorcery, a computer techician quests for hope.',
|
|
||||||
'On a planet of dark magic and barbarism, in an age of horror and blasphemy, seven librarians search for fame.',
|
|
||||||
'In an empire of dark magic, in a time of blood and illusions, four monks try to find the ultimate weapon and combat terrorism.',
|
|
||||||
'In a forgotten empire of dark magic, six kings try to prevent the destruction of mankind.',
|
|
||||||
'In a galaxy of dark magic and horror, in an age of hopelessness, four marines and an outlaw combat evil.',
|
|
||||||
'In a mysterious city of illusion, in an age of computerization, a witch-hunter tries to find the ultimate weapon and opposes an evil corporation.',
|
|
||||||
'In a damned kingdom of technology, a virtual reality programmer and a fighter seek fame.',
|
|
||||||
'In a hellish kingdom, in an age of blasphemy and blasphemy, an astrologer searches for fame.',
|
|
||||||
'In a damned world of devils, an alien and a ranger quest for love and oppose a syndicate of demons.',
|
|
||||||
'In a cursed galaxy, in a time of pain, seven librarians hope to avert the apocalypse.',
|
|
||||||
'In a crime-infested galaxy, in an era of hopelessness and panic, three champions and a grave robber try to solve the ultimate crime.'
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = ()=>{
|
|
||||||
return `<style>
|
|
||||||
.page#p1{ text-align:center; counter-increment: none; }
|
|
||||||
.page#p1:after{ display:none; }
|
|
||||||
.page:nth-child(2n) .pageNumber { left: inherit !important; right: 2px !important; }
|
|
||||||
.page:nth-child(2n+1) .pageNumber { right: inherit !important; left: 2px !important; }
|
|
||||||
.page:nth-child(2n)::after { transform: scaleX(1); }
|
|
||||||
.page:nth-child(2n+1)::after { transform: scaleX(-1); }
|
|
||||||
.page:nth-child(2n) .footnote { left: inherit; text-align: right; }
|
|
||||||
.page:nth-child(2n+1) .footnote { left: 80px; text-align: left; }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{{margin-top:225px}}
|
|
||||||
|
|
||||||
# ${_.sample(titles)}
|
|
||||||
|
|
||||||
{{margin-top:25px}}
|
|
||||||
|
|
||||||
{{wide
|
|
||||||
##### ${_.sample(subtitles)}
|
|
||||||
}}
|
|
||||||
|
|
||||||
\\page`;
|
|
||||||
};
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
const ClassFeatureGen = require('./classfeature.gen.js');
|
|
||||||
|
|
||||||
const ClassTableGen = require('./classtable.gen.js');
|
|
||||||
|
|
||||||
module.exports = function(){
|
|
||||||
|
|
||||||
const classname = _.sample(['Archivist', 'Fancyman', 'Linguist', 'Fletcher',
|
|
||||||
'Notary', 'Berserker-Typist', 'Fishmongerer', 'Manicurist', 'Haberdasher', 'Concierge']);
|
|
||||||
|
|
||||||
|
|
||||||
const image = _.sample(_.map([
|
|
||||||
'http://orig01.deviantart.net/4682/f/2007/099/f/c/bard_stick_figure_by_wrpigeek.png',
|
|
||||||
'http://img07.deviantart.net/a3c9/i/2007/099/3/a/archer_stick_figure_by_wrpigeek.png',
|
|
||||||
'http://pre04.deviantart.net/d596/th/pre/f/2007/099/5/2/adventurer_stick_figure_by_wrpigeek.png',
|
|
||||||
'http://img13.deviantart.net/d501/i/2007/099/d/4/black_mage_stick_figure_by_wrpigeek.png',
|
|
||||||
'http://img09.deviantart.net/5cf3/i/2007/099/d/d/dark_knight_stick_figure_by_wrpigeek.png',
|
|
||||||
'http://pre01.deviantart.net/7a34/th/pre/f/2007/099/6/3/monk_stick_figure_by_wrpigeek.png',
|
|
||||||
'http://img11.deviantart.net/5dcc/i/2007/099/d/1/mystic_knight_stick_figure_by_wrpigeek.png',
|
|
||||||
'http://pre08.deviantart.net/ad45/th/pre/f/2007/099/a/0/thief_stick_figure_by_wrpigeek.png',
|
|
||||||
], function(url){
|
|
||||||
return `<img src = '${url}' style='max-width:8cm;max-height:25cm' />`;
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
return `${[
|
|
||||||
image,
|
|
||||||
'',
|
|
||||||
'```',
|
|
||||||
'```',
|
|
||||||
'<div style=\'margin-top:240px\'></div>\n\n',
|
|
||||||
`## ${classname}`,
|
|
||||||
'Cool intro stuff will go here',
|
|
||||||
|
|
||||||
'\\page',
|
|
||||||
ClassTableGen(classname),
|
|
||||||
ClassFeatureGen(classname),
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
].join('\n')}\n\n\n`;
|
|
||||||
};
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
const spellNames = [
|
|
||||||
'Astral Rite of Acne',
|
|
||||||
'Create Acne',
|
|
||||||
'Cursed Ramen Erruption',
|
|
||||||
'Dark Chant of the Dentists',
|
|
||||||
'Erruption of Immaturity',
|
|
||||||
'Flaming Disc of Inconvenience',
|
|
||||||
'Heal Bad Hygene',
|
|
||||||
'Heavenly Transfiguration of the Cream Devil',
|
|
||||||
'Hellish Cage of Mucus',
|
|
||||||
'Irritate Peanut Butter Fairy',
|
|
||||||
'Luminous Erruption of Tea',
|
|
||||||
'Mystic Spell of the Poser',
|
|
||||||
'Sorcerous Enchantment of the Chimneysweep',
|
|
||||||
'Steak Sauce Ray',
|
|
||||||
'Talk to Groupie',
|
|
||||||
'Astonishing Chant of Chocolate',
|
|
||||||
'Astounding Pasta Puddle',
|
|
||||||
'Ball of Annoyance',
|
|
||||||
'Cage of Yarn',
|
|
||||||
'Control Noodles Elemental',
|
|
||||||
'Create Nervousness',
|
|
||||||
'Cure Baldness',
|
|
||||||
'Cursed Ritual of Bad Hair',
|
|
||||||
'Dispell Piles in Dentist',
|
|
||||||
'Eliminate Florists',
|
|
||||||
'Illusionary Transfiguration of the Babysitter',
|
|
||||||
'Necromantic Armor of Salad Dressing',
|
|
||||||
'Occult Transfiguration of Foot Fetish',
|
|
||||||
'Protection from Mucus Giant',
|
|
||||||
'Tinsel Blast',
|
|
||||||
'Alchemical Evocation of the Goths',
|
|
||||||
'Call Fangirl',
|
|
||||||
'Divine Spell of Crossdressing',
|
|
||||||
'Dominate Ramen Giant',
|
|
||||||
'Eliminate Vindictiveness in Gym Teacher',
|
|
||||||
'Extra-Planar Spell of Irritation',
|
|
||||||
'Induce Whining in Babysitter',
|
|
||||||
'Invoke Complaining',
|
|
||||||
'Magical Enchantment of Arrogance',
|
|
||||||
'Occult Globe of Salad Dressing',
|
|
||||||
'Overwhelming Enchantment of the Chocolate Fairy',
|
|
||||||
'Sorcerous Dandruff Globe',
|
|
||||||
'Spiritual Invocation of the Costumers',
|
|
||||||
'Ultimate Rite of the Confetti Angel',
|
|
||||||
'Ultimate Ritual of Mouthwash',
|
|
||||||
];
|
|
||||||
const itemNames = [
|
|
||||||
'Doorknob of Niceness',
|
|
||||||
'Paper Armor of Folding',
|
|
||||||
'Mixtape of Sadness',
|
|
||||||
'Staff of Endless Confetti',
|
|
||||||
];
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
|
|
||||||
spellList : function(){
|
|
||||||
const levels = ['Cantrips (0 Level)', '1st Level', '2nd Level', '3rd Level', '4th Level', '5th Level', '6th Level', '7th Level', '8th Level', '9th Level'];
|
|
||||||
|
|
||||||
const content = _.map(levels, (level)=>{
|
|
||||||
const spells = _.map(_.sampleSize(spellNames, _.random(4, 10)), (spell)=>{
|
|
||||||
return `- ${spell}`;
|
|
||||||
}).join('\n');
|
|
||||||
return `##### ${level} \n${spells} \n`;
|
|
||||||
}).join('\n');
|
|
||||||
|
|
||||||
return `{{spellList,wide\n${content}\n}}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
spell : function(){
|
|
||||||
const level = ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th'];
|
|
||||||
const spellSchools = ['abjuration', 'conjuration', 'divination', 'enchantment', 'evocation', 'illusion', 'necromancy', 'transmutation'];
|
|
||||||
|
|
||||||
|
|
||||||
let components = _.sampleSize(['V', 'S', 'M'], _.random(1, 3)).join(', ');
|
|
||||||
if(components.indexOf('M') !== -1){
|
|
||||||
components += ` (${_.sampleSize(['a small doll', 'a crushed button worth at least 1cp', 'discarded gum wrapper'], _.random(1, 3)).join(', ')})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
`#### ${_.sample(spellNames)}`,
|
|
||||||
`*${_.sample(level)}-level ${_.sample(spellSchools)}*`,
|
|
||||||
'',
|
|
||||||
'**Casting Time:** :: 1 action',
|
|
||||||
`**Range:** :: ${_.sample(['Self', 'Touch', '30 feet', '60 feet'])}`,
|
|
||||||
`**Components:** :: ${components}`,
|
|
||||||
`**Duration:** :: ${_.sample(['Until dispelled', '1 round', 'Instantaneous', 'Concentration, up to 10 minutes', '1 hour'])}`,
|
|
||||||
'',
|
|
||||||
'A flame, equivalent in brightness to a torch, springs from an object that you touch. ',
|
|
||||||
'The effect look like a regular flame, but it creates no heat and doesn\'t use oxygen. ',
|
|
||||||
'A *continual flame* can be covered or hidden but not smothered or quenched.',
|
|
||||||
'\n\n\n'
|
|
||||||
].join('\n');
|
|
||||||
},
|
|
||||||
|
|
||||||
item : function() {
|
|
||||||
return [
|
|
||||||
`#### ${_.sample(itemNames)}`,
|
|
||||||
`*${_.sample(['Wondrous item', 'Armor', 'Weapon'])}, ${_.sample(['Common', 'Uncommon', 'Rare', 'Very Rare', 'Legendary', 'Artifact'])} (requires attunement)*`,
|
|
||||||
`:`,
|
|
||||||
`This knob is pretty nice. When attached to a door, it allows a user to`,
|
|
||||||
`open that door with the strength of the nearest animal. For example, if`,
|
|
||||||
`there is a cow nearby, the user will have the "strength of a cow" while`,
|
|
||||||
`opening this door.`
|
|
||||||
].join('\n');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
const dedent = require('dedent-tabs').default;
|
|
||||||
|
|
||||||
const genList = function(list, max){
|
|
||||||
return _.sampleSize(list, _.random(0, max)).join(', ') || 'None';
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMonsterName = function(){
|
|
||||||
return _.sample([
|
|
||||||
'All-devouring Baseball Imp',
|
|
||||||
'All-devouring Gumdrop Wraith',
|
|
||||||
'Chocolate Hydra',
|
|
||||||
'Devouring Peacock',
|
|
||||||
'Economy-sized Colossus of the Lemonade Stand',
|
|
||||||
'Ghost Pigeon',
|
|
||||||
'Gibbering Duck',
|
|
||||||
'Sparklemuffin Peacock Spider',
|
|
||||||
'Gum Elemental',
|
|
||||||
'Illiterate Construct of the Candy Store',
|
|
||||||
'Ineffable Chihuahua',
|
|
||||||
'Irritating Death Hamster',
|
|
||||||
'Irritating Gold Mouse',
|
|
||||||
'Juggernaut Snail',
|
|
||||||
'Juggernaut of the Sock Drawer',
|
|
||||||
'Koala of the Cosmos',
|
|
||||||
'Mad Koala of the West',
|
|
||||||
'Milk Djinni of the Lemonade Stand',
|
|
||||||
'Mind Ferret',
|
|
||||||
'Mystic Salt Spider',
|
|
||||||
'Necrotic Halitosis Angel',
|
|
||||||
'Pinstriped Famine Sheep',
|
|
||||||
'Ritalin Leech',
|
|
||||||
'Shocker Kangaroo',
|
|
||||||
'Stellar Tennis Juggernaut',
|
|
||||||
'Wailing Quail of the Sun',
|
|
||||||
'Angel Pigeon',
|
|
||||||
'Anime Sphinx',
|
|
||||||
'Bored Avalanche Sheep of the Wasteland',
|
|
||||||
'Devouring Nougat Sphinx of the Sock Drawer',
|
|
||||||
'Djinni of the Footlocker',
|
|
||||||
'Ectoplasmic Jazz Devil',
|
|
||||||
'Flatuent Angel',
|
|
||||||
'Gelatinous Duck of the Dream-Lands',
|
|
||||||
'Gelatinous Mouse',
|
|
||||||
'Golem of the Footlocker',
|
|
||||||
'Lich Wombat',
|
|
||||||
'Mechanical Sloth of the Past',
|
|
||||||
'Milkshake Succubus',
|
|
||||||
'Puffy Bone Peacock of the East',
|
|
||||||
'Rainbow Manatee',
|
|
||||||
'Rune Parrot',
|
|
||||||
'Sand Cow',
|
|
||||||
'Sinister Vanilla Dragon',
|
|
||||||
'Snail of the North',
|
|
||||||
'Spider of the Sewer',
|
|
||||||
'Stellar Sawdust Leech',
|
|
||||||
'Storm Anteater of Hell',
|
|
||||||
'Stupid Spirit of the Brewery',
|
|
||||||
'Time Kangaroo',
|
|
||||||
'Tomb Poodle',
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getType = function(){
|
|
||||||
return `${_.sample(['Tiny', 'Small', 'Medium', 'Large', 'Gargantuan', 'Stupidly vast'])} ${_.sample(['beast', 'fiend', 'annoyance', 'guy', 'cutie'])}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAlignment = function(){
|
|
||||||
return _.sample([
|
|
||||||
'annoying evil',
|
|
||||||
'chaotic gossipy',
|
|
||||||
'chaotic sloppy',
|
|
||||||
'depressed neutral',
|
|
||||||
'lawful bogus',
|
|
||||||
'lawful coy',
|
|
||||||
'manic-depressive evil',
|
|
||||||
'narrow-minded neutral',
|
|
||||||
'neutral annoying',
|
|
||||||
'neutral ignorant',
|
|
||||||
'oedpipal neutral',
|
|
||||||
'silly neutral',
|
|
||||||
'unoriginal neutral',
|
|
||||||
'weird neutral',
|
|
||||||
'wordy evil',
|
|
||||||
'unaligned'
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStats = function(){
|
|
||||||
return `|${_.times(6, function(){
|
|
||||||
const num = _.random(1, 20);
|
|
||||||
const mod = Math.ceil(num/2 - 5);
|
|
||||||
return `${num} (${mod >= 0 ? `+${mod}` : mod})`;
|
|
||||||
}).join('|')}|`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const genAbilities = function(){
|
|
||||||
return _.sample([
|
|
||||||
'***Pack Tactics.*** These guys work together like peanut butter and jelly.',
|
|
||||||
'***Fowl Appearance.*** While the creature remains motionless, it is indistinguishable from a normal chicken.',
|
|
||||||
'***Onion Stench.*** Any creatures within 5 feet of this thing develops an irrational craving for onion rings.',
|
|
||||||
'***Enormous Nose.*** This creature gains advantage on any check involving putting things in its nose.',
|
|
||||||
'***Sassiness.*** When questioned, this creature will talk back instead of answering.',
|
|
||||||
'***Big Jerk.*** Whenever this creature makes an attack, it starts telling you how much cooler it is than you.',
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const genLongAbilities = function(){
|
|
||||||
return _.sample([
|
|
||||||
dedent`***Pack Tactics.*** These guys work together like peanut butter and jelly. Jelly and peanut butter.
|
|
||||||
|
|
||||||
When one of these guys attacks, the target is covered with, well, peanut butter and jelly.`,
|
|
||||||
dedent`***Hangriness.*** This creature is angry, and hungry. It will refuse to do anything with you until its hunger is satisfied.
|
|
||||||
|
|
||||||
When in visual contact with this creature, you must purchase an extra order of fries, even if they say they aren't hungry.`,
|
|
||||||
dedent`***Full of Detergent.*** This creature has swallowed an entire bottle of dish detergent and is actually having a pretty good time.
|
|
||||||
|
|
||||||
While walking near this creature, you must make a dexterity check or become "a soapy mess" for three hours, after which your skin will get all dry and itchy.`
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const genAction = function(){
|
|
||||||
const name = _.sample([
|
|
||||||
'Abdominal Drop',
|
|
||||||
'Airplane Hammer',
|
|
||||||
'Atomic Death Throw',
|
|
||||||
'Bulldog Rake',
|
|
||||||
'Corkscrew Strike',
|
|
||||||
'Crossed Splash',
|
|
||||||
'Crossface Suplex',
|
|
||||||
'DDT Powerbomb',
|
|
||||||
'Dual Cobra Wristlock',
|
|
||||||
'Dual Throw',
|
|
||||||
'Elbow Hold',
|
|
||||||
'Gory Body Sweep',
|
|
||||||
'Heel Jawbreaker',
|
|
||||||
'Jumping Driver',
|
|
||||||
'Open Chin Choke',
|
|
||||||
'Scorpion Flurry',
|
|
||||||
'Somersault Stump Fists',
|
|
||||||
'Suffering Wringer',
|
|
||||||
'Super Hip Submission',
|
|
||||||
'Super Spin',
|
|
||||||
'Team Elbow',
|
|
||||||
'Team Foot',
|
|
||||||
'Tilt-a-whirl Chin Sleeper',
|
|
||||||
'Tilt-a-whirl Eye Takedown',
|
|
||||||
'Turnbuckle Roll'
|
|
||||||
]);
|
|
||||||
|
|
||||||
return `***${name}.*** *Melee Weapon Attack:* +4 to hit, reach 5ft., one target. *Hit* 5 (1d6 + 2) `;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
|
|
||||||
monster : function(classes, genLines){
|
|
||||||
return dedent`
|
|
||||||
{{${classes}
|
|
||||||
## ${getMonsterName()}
|
|
||||||
*${getType()}, ${getAlignment()}*
|
|
||||||
___
|
|
||||||
**Armor Class** :: ${_.random(10, 20)} (chain mail, shield)
|
|
||||||
**Hit Points** :: ${_.random(1, 150)}(1d4 + 5)
|
|
||||||
**Speed** :: ${_.random(0, 50)}ft.
|
|
||||||
___
|
|
||||||
| STR | DEX | CON | INT | WIS | CHA |
|
|
||||||
|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|
|
|
||||||
${getStats()}
|
|
||||||
___
|
|
||||||
**Condition Immunities** :: ${genList(['groggy', 'swagged', 'weak-kneed', 'buzzed', 'groovy', 'melancholy', 'drunk'], 3)}
|
|
||||||
**Senses** :: darkvision 60 ft., passive Perception ${_.random(3, 20)}
|
|
||||||
**Languages** :: ${genList(['Common', 'Pottymouth', 'Gibberish', 'Latin', 'Jive'], 2)}
|
|
||||||
**Challenge** :: ${_.random(0, 15)} (${_.random(10, 10000)} XP)
|
|
||||||
___
|
|
||||||
${_.times(_.random(genLines, genLines + 2), function(){return genAbilities();}).join('\n:\n')}
|
|
||||||
:
|
|
||||||
${genLongAbilities()}
|
|
||||||
### Actions
|
|
||||||
${_.times(_.random(genLines, genLines + 2), function(){return genAction();}).join('\n:\n')}
|
|
||||||
}}
|
|
||||||
\n`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
const dedent = require('dedent-tabs').default;
|
|
||||||
|
|
||||||
const getTOC = (pages)=>{
|
|
||||||
const add1 = (title, page)=>{
|
|
||||||
res.push({
|
|
||||||
title : title,
|
|
||||||
page : page + 1,
|
|
||||||
children : []
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const add2 = (title, page)=>{
|
|
||||||
if(!_.last(res)) add1(null, page);
|
|
||||||
_.last(res).children.push({
|
|
||||||
title : title,
|
|
||||||
page : page + 1,
|
|
||||||
children : []
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const add3 = (title, page)=>{
|
|
||||||
if(!_.last(res)) add1(null, page);
|
|
||||||
if(!_.last(_.last(res).children)) add2(null, page);
|
|
||||||
_.last(_.last(res).children).children.push({
|
|
||||||
title : title,
|
|
||||||
page : page + 1,
|
|
||||||
children : []
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const res = [];
|
|
||||||
_.each(pages, (page, pageNum)=>{
|
|
||||||
const lines = page.split('\n');
|
|
||||||
_.each(lines, (line)=>{
|
|
||||||
if(_.startsWith(line, '# ')){
|
|
||||||
const title = line.replace('# ', '');
|
|
||||||
add1(title, pageNum);
|
|
||||||
}
|
|
||||||
if(_.startsWith(line, '## ')){
|
|
||||||
const title = line.replace('## ', '');
|
|
||||||
add2(title, pageNum);
|
|
||||||
}
|
|
||||||
if(_.startsWith(line, '### ')){
|
|
||||||
const title = line.replace('### ', '');
|
|
||||||
add3(title, pageNum);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = function(brew){
|
|
||||||
const pages = brew.text.split('\\page');
|
|
||||||
const TOC = getTOC(pages);
|
|
||||||
const markdown = _.reduce(TOC, (r, g1, idx1)=>{
|
|
||||||
if(g1.title !== null) {
|
|
||||||
r.push(`- ### [{{ ${g1.title}}}{{ ${g1.page}}}](#p${g1.page})`);
|
|
||||||
}
|
|
||||||
if(g1.children.length){
|
|
||||||
_.each(g1.children, (g2, idx2)=>{
|
|
||||||
if(g2.title !== null) {
|
|
||||||
r.push(` - #### [{{ ${g2.title}}}{{ ${g2.page}}}](#p${g2.page})`);
|
|
||||||
}
|
|
||||||
if(g2.children.length){
|
|
||||||
_.each(g2.children, (g3, idx3)=>{
|
|
||||||
if(g2.title !== null) {
|
|
||||||
r.push(` - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
|
|
||||||
} else { // Don't over-indent if no level-2 parent entry
|
|
||||||
r.push(` - [{{ ${g3.title}}}{{ ${g3.page}}}](#p${g3.page})`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}, []).join('\n');
|
|
||||||
|
|
||||||
return dedent`
|
|
||||||
{{toc,wide
|
|
||||||
# Table Of Contents
|
|
||||||
|
|
||||||
${markdown}
|
|
||||||
}}
|
|
||||||
\n`;
|
|
||||||
};
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
|
|
||||||
module.exports = ()=>{
|
|
||||||
return `{{watercolor${_.random(1, 12)},top:20px,left:30px,width:300px,background-color:#BBAD82,opacity:80%}}\n\n`;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user