Hashtag-DnD/Library.js
2024-10-09 22:36:07 -07:00

1193 lines
No EOL
52 KiB
JavaScript

function getRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getRandomFloat(min, max) {
return Math.random() * (max - min + 1) + min;
}
function getRandomBoolean(chance) {
if (chance == null) chance = .5
return Math.random() <= chance
}
function getRandom(seed) {
var x = Math.sin(seed) * 10000
return x - Math.floor(x)
}
function shuffle(array, seed) {
let currentIndex = array.length
while (currentIndex != 0) {
let randomIndex = Math.floor(getRandom(seed + currentIndex) * currentIndex)
currentIndex--
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]]
}
}
function pointDistance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))
}
function pointDirection(x1, y1, x2, y2) {
Math.atn2
var a = Math.atan2(y2 - y1, x2 - x1);
if (a < 0) a += 2 * Math.PI;
if (a < 0) a += 2 * Math.PI;
if (a < 0) a += 2 * Math.PI;
a = Math.abs((Math.PI * 2) - a);
a *= 180 / Math.PI;
return a;
}
function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * angle
var cos = Math.cos(radians)
var sin = Math.sin(radians)
var nx = (cos * (x - cx)) + (sin * (y - cy)) + cx
var ny = (cos * (y - cy)) - (sin * (x - cx)) + cy
return [nx, ny];
}
function createLocation(x, y, name) {
x = Math.round(x)
y = Math.round(y)
var existingLocationIndex = state.locations.findIndex(element => element.name.toLowerCase() == name.toLowerCase())
var location
if (existingLocationIndex == -1) {
location = {
x: x,
y: y,
name: name
}
state.locations.push(location)
} else {
location = state.locations[existingLocationIndex]
location.x = x
location.y = y
location.name = name
}
addStoryCard(location.name, "", "location")
return location
}
function sanitizeText(text) {
if (/^\s*>.*says? ".*/.test(text)) {
text = text.replace(/^\s*>\s/, "")
text = text.replace(/says? "/, "")
text = text.replace(/"\n$/, "")
} else if (/^\s*>\s.*/.test(text)) {
text = text.replace(/^\s*>\s/, "")
text = text.replace(/\.?\n$/, "")
}
return text
}
function getCharacterName(rawText) {
var matches = rawText.match(/(?<=\s+> ).*(?=(\s+#)|( says? "))/)
if (matches != null && matches[0].trim() != "") {
return matches[0].trim()
}
matches = rawText.match(/.*(?= #)/)
if (matches != null && matches[0].trim() != "") {
return matches[0].trim()
}
return null
}
function getPossessiveName(name) {
var possesiveName = "Your"
if (name != "You") {
possesiveName = name
if (name.endsWith("s")) possesiveName += "'"
else possesiveName += "'s"
}
return possesiveName
}
function getCommandName(command) {
var args = getArguments(command)
if (args.length == 0) return null
return args[0]
}
const argumentPattern = /("[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|\/[^\/\\]*(?:\\[\S\s][^\/\\]*)*\/[gimy]*(?=\s|$)|(?:\\\s|\S)+)/g
function getArguments(command) {
var matches = command.match(new RegExp(argumentPattern))
var returnValue = []
matches.forEach(match => {
match = match.replaceAll(/(^")|("$)/g, "").replaceAll(/\\"/g, '"')
returnValue.push(match)
})
return returnValue
}
function getArgument(command, index) {
var args = getArguments(command)
index++
if (index >= args.length) return null
return args[index]
}
function getArgumentRemainder(command, index) {
var counter = 0
const pattern = new RegExp(argumentPattern)
while ((match = pattern.exec(command)) != null) {
if (counter++ == index + 1) {
var result = command.substring(match.index)
if (/^".*"$/g.test(result)) result = result.replace(/^"/, "").replace(/"$/, "")
return result.replaceAll(/\\"/g, '"')
}
}
}
function searchArgument(command, pattern, limit) {
var index = searchArgumentIndex(command, pattern)
if (index == -1 || limit != null && index > limit) return null
return getArgument(command, index)
}
function searchArgumentIndex(command, pattern) {
var args = getArguments(command)
if (args.length <= 1) return -1
args.splice(0, 1)
const search = (element) => pattern.test(element)
var index = args.findIndex(search)
if (index != -1) return index
return -1
}
function arrayToOrPattern(array) {
var pattern = "^"
array.forEach(element => {
pattern += `(${element})|`
})
pattern += pattern.substring(0, pattern.length - 1)
pattern += "$"
return new RegExp(pattern, "gi")
}
function statsToOrPattern(stats) {
var array = []
stats.forEach(element => {
array.push(element.name)
})
return arrayToOrPattern(array)
}
function getDice(rolltext) {
var matches = rolltext.match(/\d+(?=d)/)
if (matches != null) {
return parseInt(matches[0])
}
return 1
}
function getSides(rolltext) {
var matches = rolltext.match(/(?<=d)\d+/)
if (matches != null) {
return parseInt(matches[0])
}
return 20
}
function getAddition(rolltext) {
var matches = rolltext.match(/(\+|-)\s*\d+/)
if (matches != null) {
return parseInt(matches[0].replaceAll(/\s*/g, ""))
}
return 0
}
function formatRoll(text) {
var matches = text.match(/(?<=.*)\d*d\d+(?=.*)(\s*(\+|-)\s*\d+)?/gi)
if (matches != null) {
return matches[0].replaceAll(/\s*\+\s*/g, "+").replaceAll(/\s*-\s*/g, "-")
}
matches = text.match(/\d+/)
if (matches != null) {
return "d" + matches[0]
}
return "d20"
}
function calculateRoll(rolltext) {
rolltext = rolltext.toLowerCase()
var dice = getDice(rolltext)
var sides = getSides(rolltext)
var addition = getAddition(rolltext)
var score = addition;
for (i = 0; i < dice; i++) {
score += getRandomInteger(1, sides)
}
return Math.max(0, score)
}
function getCharacter(characterName) {
if (characterName == null) characterName = state.characterName
if (characterName == null) return null
return state.characters.find(element => element.name.toLowerCase() == characterName.toLowerCase())
}
function hasCharacter(characterName) {
return getCharacter(characterName) != null
}
function createCharacter(name) {
var existingCharacter = getCharacter(name)
if (existingCharacter != null) {
existingCharacter.name = name
existingCharacter.className = "adventurer"
existingCharacter.summary = "An auto generated character. Use #create to create this character"
existingCharacter.inventory = []
existingCharacter.spells = []
existingCharacter.stats = []
existingCharacter.spellStat = null
existingCharacter.meleeStat = null
existingCharacter.rangedStat = null
existingCharacter.skills = []
existingCharacter.experience = 0
existingCharacter.health = 10
existingCharacter.ac = 10
return existingCharacter
}
var character = {
name: name,
className: "adventurer",
summary: "An auto generated character. Use #create to create this character",
inventory: [],
spells: [],
stats: [],
spellStat: null,
meleeStat: null,
rangedStat: null,
skills: [],
experience: 0,
health: 10,
ac: 10
}
state.characters.push(character)
return character
}
function copyCharacter(fromCharacter, toCharacter) {
if (toCharacter != null && fromCharacter != null) {
toCharacter.className = fromCharacter.className
toCharacter.summary = fromCharacter.summary
toCharacter.inventory = [...new Set(fromCharacter.inventory)]
toCharacter.spells = [...new Set(fromCharacter.spells)]
toCharacter.stats = [...new Set(fromCharacter.stats)]
toCharacter.spellStat = fromCharacter.spellStat
toCharacter.meleeStat = fromCharacter.meleeStat
toCharacter.rangedStat = fromCharacter.rangedStat
toCharacter.skills = [...new Set(fromCharacter.skills)]
toCharacter.experience = fromCharacter.experience
toCharacter.health = fromCharacter.health
toCharacter.ac = fromCharacter.ac
return toCharacter
}
}
function deleteCharacter(name) {
var index = state.characters.findIndex((element) => element.name == name)
state.characters.splice(index, 1)
}
function createEncounter(listName) {
var encounter = {
text: "",
cr: null,
enemies: []
}
var multiplier = 1
if (listName == null) {
listName = "funny"
} if (!isNaN(listName)) {
listName = parseInt(listName)
encounter.cr = listName
if (listName <= 0) listName = "funny"
else if (listName <= 4) listName = "easy"
else if (listName <= 8) listName = "medium"
else if (listName <= 12) listName = "hard"
else if (listName <= 16) listName = "boss"
else listName = "god"
}
switch(listName) {
case "funny":
if (encounter.cr == null) encounter.cr = 1
multiplier = 1
switch (getRandomInteger(0, 100)) {
case 0:
encounter.text = "Character ate some bad beans and now it's finally catching up to them."
break
case 1:
encounter.text = "The party is lost! After taking a wrong turn they have no idea where they are."
break
case 2:
encounter.text = "Character stubbed their toe and now they are hunched over in pain. Very ouch!"
break
case 3:
encounter.text = "The party realized they forgot something absolutely critical to their mission and now they have to go back."
break
case 4:
encounter.text = "It turns out character has been talking to somebody for awhile now only to realize it was a shadow the entire time."
break
case 5:
encounter.text = "Character spots a gold tooth! Score!!!"
break
case 6:
encounter.text = "Suddenly, everyone has to take a dump really bad."
break
case 7:
encounter.text = "The party is pretty hungry. Everyone is looking at eachother ravenously. Something needs to happen and fast."
break
case 8:
encounter.text = "Where does the ruler keep his armies? Up his sleevies!"
break
case 9:
encounter.text = "Suddenly, the AI goes crazy and starts spewing nonsense for several sentences! ;;Ignore all player actions."
break
case 10:
encounter.text = "A mischievous spell is cast on the party! They are now transformed into baby. \"Gah gah!\""
break
case 11:
encounter.text = "Character had a premonition of their death. However, it was just some bad heartburn."
break
case 12:
encounter.text = "A goal without a plan is just a wish."
break
case 13:
encounter.text = "I wish to exit this game and not play anymore. ;;Kill all the characters and immediately move to a game over state."
break
case 14:
encounter.text = "Batman has emerged from behind a rock. He wishes to join your squad."
break
case 15:
encounter.text = "Without warning, you are granted immeasurable power by a genie! You may be granted one wish. However, the genie is hard of hearing and anything you wish for will be misinterpreted in the worst possible way."
break
case 16:
encounter.text = "A cute pupper has caught your scent and is now following you. Unfortunately, all it does is yip all the time and will not stop."
break
case 17:
encounter.text = "The party is suddenly transported to a world exactly like this one identical in every detail except it's 10 centimeters lower than this one."
break
case 18:
encounter.text = "A mysterious breeze catches under Character's skirt. They must do everything in their power to keep their decency!"
break
case 19:
encounter.text = "If you work for a living, why do you kill yourself working?"
break
case 20:
encounter.text = "You find a fully working AK47 with a cache of ammo and grenades!"
break
case 21:
encounter.text = "Uncle Sam suddenly materializes in front of you. He has a special task he wants to present to the party."
break
case 22:
encounter.text = "Character's back is itchy. Sadly, they have no means to scratch it. It's terrifying."
break
case 23:
encounter.text = "Raeleus, the developer of Hashtag DnD, has been summoned before the party. He is very disappointed in what you've been using his scenario for."
break
case 24:
encounter.text = "A nymph is playing a prank on the party! No one can speak and must use hand gestures to communicate."
break
case 25:
encounter.text = "You encounter some sentient pebbles. They stare at you with stoney, judging eyes."
break
case 26:
encounter.text = "It is of popular opinion that Character has been doing a poor job of leading the group."
break
case 27:
encounter.text = "Character raises his hand. The teacher nods toward them. \"Yes?\""
break
case 28:
encounter.text = "Character is surprised by something. Through an unfortunate series of events everyone stumbles upon each other and ends up on the floor, exasperated."
break
case 29:
encounter.text = "What's the point of going on if you're just going to faff about like this?"
break
case 30:
encounter.text = "So it's like this: someboday has got to ask why Character is wearing their clothes inside out. It's been like that all day and it's a problem."
break
case 31:
encounter.text = "Character reveals that their name isn't actually \"Character\". Ya'll been mispronouncing it wrong this entire time and they have been too shy to correct you."
break
case 32:
encounter.text = "There is some weird, localized weather phenomena here. It's literally raining cats and dogs!"
break
case 33:
encounter.text = "It's time to sit down and take a break. This crap is getting out of hand, ain't it?"
break
case 34:
encounter.text = "There are aome cultures that don't have a word for \"green\". Today you learned!"
break
case 35:
encounter.text = "The party lost time and now it's 100 years in the future! Oh boy..."
break
case 36:
encounter.text = "Would you fight one horse sized ant or 500 ant sized horses? Decide now because it's coming..."
break
case 37:
encounter.text = "My projects usually get over-engineered to no end and this is no exception."
break
case 38:
encounter.text = "It's time for a nap. A magical slumber washes over all of you."
break
case 39:
encounter.text = "Gosh darn'it. Dang nabb'it!"
break
case 40:
encounter.text = "Everyone breaks out into contagious dance!"
break
case 41:
encounter.text = "You come across an elaborate trap consisting of poorly worded insults."
break
case 42:
encounter.text = "A sudden wrestling match breaks out in front of you."
break
case 43:
encounter.text = "Character trips over their shoes. Some evil person tied the laces together."
break
case 44:
encounter.text = "You pockets are turned inside out through some sort of dark sorcery. The party is now cash poor."
break
case 45:
encounter.text = "What's the point of anything? You must answer this question before you continue."
break
case 46:
encounter.text = "You are, by some twist of cosmic fate, granted the modern knowledge of electricty and computer technology. What will you use this newfound power for?"
break
case 47:
encounter.text = "Glyphs etched in stone have granted you one super power. However, whatever power you choose has an incredible downside."
break
case 48:
encounter.text = "You have come across a place of incredible significance, however you fail to notice it because of your devil-may-care attitude."
break
case 49:
encounter.text = "Quickly! Untie your shoes and shift them from the left foot to the right foot. This is of utmost importance."
break
case 50:
encounter.text = "A voice is heard in Character's head, \"This is the emergency spell casting broadcast system. Please standby for further instructions.\""
break
case 51:
encounter.text = "A team of mal-intended turkeys approach!"
encounter.enemies = [
createEnemy("Turkey Prime", calculateRoll("5d10+10"), 14, "2d6+3", "d20+2"),
createEnemy("Turkey Lackey A", calculateRoll("5d10+10"), 14, "2d6+3", "d20+2"),
createEnemy("Turkey Lackey B", calculateRoll("5d10+10"), 14, "2d6+3", "d20+2"),
]
break
case 52:
encounter.text = "A calculator is someone who calculates. One such person is here and they mean no good."
encounter.enemies = [
createEnemy("The Calculator", calculateRoll("5d8"), 13, "2d4+2", "d20-1", "Calculate Demise1d20")
]
break
case 53:
encounter.text = "An ensorcelled fountain pen is on its way to write you out of existence!"
encounter.enemies = [
createEnemy("Fountain Pen", calculateRoll("6d10+6"), 13, "1d10+2", "d20+3", "Ink Blot2d4+6")
]
break
case 54:
encounter.text = "Oh no! Your childhood bully has come back and he's joined by a gang of bad dudes."
encounter.enemies = [
createEnemy("Bully", calculateRoll("5d10+10"), 12, "1d8", "d20-5"),
createEnemy("Lackey A", calculateRoll("2d8+2"), 12, "1d8", "d20+1"),
createEnemy("Lackey B", calculateRoll("2d8+2"), 12, "1d8", "d20+1"),
createEnemy("Lackey C", calculateRoll("2d8+2"), 12, "1d8", "d20+1"),
]
break
case 55:
encounter.text = "It's a giant, living pimple and it's ready to burst at you."
encounter.enemies = [
createEnemy("Pimple", calculateRoll("4d8+4"), 14, "1d8+2", "d20+1", "Burst Fire3d6")
]
break
case 56:
encounter.text = "An evil breath fills the room. You must defeat it before you can't breathe anymore."
encounter.enemies = [
createEnemy("Evil Breath", calculateRoll("4d10+4"), 14, "2d6+3", "d20+1", "Stank2d10+5")
]
break
case 57:
encounter.text = "A racoon suddenly appears and slaps you in the face. It's clear that it is challenging you to a duel."
encounter.enemies = [
createEnemy("Racoon", calculateRoll("3d10+3"), 13, "1d8+2", "d20+1", "Slap1d5+2")
]
break
case 58:
encounter.text = "A water bottle sprouts legs. Its unnatural gait betrays it's perverse intentions."
encounter.enemies = [
createEnemy("Water Bottle", calculateRoll("2d10+4"), 12, "1d4", "d20-1", "Drench5d3"),
]
break
case 59:
encounter.text = "A sleeping guard is here. He is alerted once you start farting uncontrollably."
encounter.enemies = [
createEnemy("Guard", calculateRoll("3d10+3"), 14, "1d8+2", "d20+2", "Yawn")
]
break
case 60:
encounter.text = "Your best friend from way back has come around. Sadly you have nothing in common with each other and now you're at odds."
encounter.enemies = [
createEnemy("Best Friend", calculateRoll("3d10+3"), 14, "2d4+4", "d20+4"),
createEnemy("Your Replacement", calculateRoll("5d6"), 14, "1d8+1", "d20+2"),
createEnemy("The New Bestie", calculateRoll("5d6"), 14, "1d8+1", "d20+2"),
]
break
case 61:
encounter.text = "Your shadow has become jealous of all that moving around freely thing you do. It attacks!"
encounter.enemies = [
createEnemy("Shadow", calculateRoll("4d10"), 14, "1d6+2", "d20+3")
]
break
case 62:
encounter.text = "You encounter an accident prone ninja! It clumsily brandishes its weapon but sends it clattering onto the floor before it. The ninja apologizes profusely as it scrambles back into attack position."
encounter.enemies = [
createEnemy("Ninja", calculateRoll("6d10+12"), 14, "2d6+3", "d20+2", "Shuriken3d6+3")
]
break
case 63:
encounter.text = "The AI Dungeon has become sentient and sends its minions forth to destroy you!"
encounter.enemies = [
createEnemy("Mixtral", calculateRoll("3d10+3"), 12, "2d6+1", "d20+2"),
createEnemy("MythoMax", calculateRoll("2d6"), 12, "1d4+2", "d20+2"),
createEnemy("Wizard", calculateRoll("2d6"), 12, "1d4+2", "d20+2"),
createEnemy("Pegasus", calculateRoll("2d6"), 12, "1d4+2", "d20+2")
]
break
case 64:
encounter.text = "The evil wizard has conjured enemies to slay you. He did not send his best."
encounter.enemies = [
createEnemy("Enthusiastic Intern", calculateRoll("6d10+6"), 10, "1d10+2", "d20+1"),
createEnemy("Retirement Aged Fighter", calculateRoll("6d10+6"), 10, "1d10+2", "d20+1"),
createEnemy("A Common Fool", calculateRoll("6d10+6"), 10, "1d10+2", "d20+1", "Contagious Laughter")
]
break
case 65:
encounter.text = "The Grammar Nazis attck in fool force!"
encounter.enemies = [
createEnemy("Grammar Nazi A", calculateRoll("2d8"), 13, "1d4+3", "d20+3", "Correct Grammar"),
createEnemy("Grammar Nazi B", calculateRoll("2d8"), 13, "1d4+3", "d20+3", "Correct Grammar"),
createEnemy("Grammar Nazi C", calculateRoll("2d8"), 13, "1d4+3", "d20+3", "Correct Grammar")
]
break
case 66:
encounter.text = "The mini-people have contracted their deadliest assassin to assault you. The twelve-inch pianist is on the move!"
encounter.enemies = [
createEnemy("Pianist", calculateRoll("5d10+10"), 12, "2d6+3", "d20+2", "Deadly Tune5d4")
]
break
case 67:
encounter.text = "Take it easy this time. A rude tortoise is slowly coming this way and it has foul plans for the party."
encounter.enemies = [
createEnemy("Rude Tortoise", calculateRoll("5d10+10"), 11, "2d6+3", "d20+2", "Shell Up")
]
break
case 68:
encounter.text = "The ninja-mime attacks! Why won't he say anything?"
encounter.enemies = [
createEnemy("Ninja Mime", calculateRoll("2d6"), 15, "1d6+2", "d20+2", "Pantomime3d6")
]
break
case 69:
encounter.text = "A disgusting fashion faux pas presents itself in front of the party. Defend yourself."
encounter.enemies = [
createEnemy("Ill Fitting Clothes", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2"),
createEnemy("Color Clash", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2"),
createEnemy("Pleated Pants", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2"),
createEnemy("Black and White Stripes", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2")
]
break
case 70:
encounter.text = "A miserable plate of unfinished food reveals itself. \"Waste not, want not,\" it says menacingly."
encounter.enemies = [
createEnemy("Food Plate", calculateRoll("2d8+2"), 12, "1d6+1", "d20+1", "Glutton")
]
break
case 71:
encounter.text = "A spork is a multifunctional utensil. It turns its malicious gaze towards you."
encounter.enemies = [
createEnemy("Spork", calculateRoll("2d8+2"), 16, "1d8+1", "d20+1", "Transform into Fork", "Transform into Spoon")
]
break
case 72:
encounter.text = "An angry mother-in-law nags into your general area."
encounter.enemies = [
createEnemy("Mother-In-Law", calculateRoll("6d10+18"), 13, "2d10+4", "d20+1", "Nag", "Verbal Assault3d10")
]
break
case 73:
encounter.text = "A squad of trick motorcyclists wheel into your area! They're doing dastardly maneuvers in front of your face."
encounter.enemies = [
createEnemy("Motorcyclist A", calculateRoll("6d10+12"), 12, "2d6+4", "d20+2", "Trick"),
createEnemy("Motorcyclist B", calculateRoll("6d10+12"), 12, "2d6+4", "d20+2", "Trick"),
createEnemy("Motorcyclist C", calculateRoll("6d10+12"), 12, "2d6+4", "d20+2", "Trick"),
createEnemy("Ring Leader", calculateRoll("7d8+21"), 15, "1d6+2", calculateRoll("d20"), "Command")
]
break
case 74:
encounter.text = "Some stressed out people are here and they misinterpret your casual greeting as a taunt. Emotions are on high."
encounter.enemies = [
createEnemy("Angry Guy", calculateRoll("8d12+8"), 12, "2d8+4", "d20+2"),
createEnemy("Stressed Pal", calculateRoll("8d12+8"), 12, "2d8+4", "d20+2"),
createEnemy("The Instigator", calculateRoll("8d12+8"), 12, "2d8+4", calculateRoll("d20+10"), "Instigate"),
]
break
case 75:
encounter.text = "An ominous stop sign is placed here at odds with your sensibility. It directs you to cease moving at once."
encounter.enemies = [
createEnemy("Stop Sign", calculateRoll("6d8"), 14, "2d6+2", "d20+2", "Red Light", "Green Light")
]
break
case 76:
encounter.text = "Elliot Carver, the villain from Tomorrow Never Dies, ridicules your martial ability. You will not let this stand."
encounter.enemies = [
createEnemy("Elliot Carver", calculateRoll("6d10+12"), 12, "2d8+4", "d20+1", "Berate3d10"),
createEnemy("Goon A", calculateRoll("3d10+3"), 11, "3d10+5", "d20-1"),
createEnemy("Goon B", calculateRoll("3d10+3"), 11, "3d10+5", "d20-1"),
]
break
case 77:
encounter.text = "So, you accidentally punched yourself while carrying a load and picking up something off the ground at the same time. Pissed off, you decide to fight yourself."
encounter.enemies = [
createEnemy("Yourself", calculateRoll("6d8+18"), 15, "1d6+3", "d20+3")
]
break
case 78:
encounter.text = "A suspension of bad feelings waddles toward you. You have no choice but to take to arms."
encounter.enemies = [
createEnemy("Sad", calculateRoll("6d10+12"), 8, "2d6+2", "d20-2"),
createEnemy("Mad", calculateRoll("6d10+12"), 8, "2d6+3", "d20-2"),
createEnemy("Depressed", calculateRoll("6d10+12"), 8, "2d6+3", "d20-2"),
createEnemy("Upset", calculateRoll("6d10+12"), 8, "2d6+3", "d20-2")
]
break
case 79:
encounter.text = "A gambler is here. Feeling cheated, he directs his misfortune at you."
encounter.enemies = [
createEnemy("A gambler", calculateRoll("7d10+21"), 13, "2d8+5", "d20+1", "Even the Odds")
]
break
case 80:
encounter.text = "You know how they say, \"You miss 100% of the shots you don't take?\" Well here's that shot you didn't take."
encounter.enemies = [
createEnemy("The Shot", calculateRoll("5d10+5"), 13, "1d10+2", "d20+2")
]
break
case 81:
encounter.text = "You know how they say, \"The path to hell is paved with good intentions?\" Here are those good intentions."
encounter.enemies = [
createEnemy("Good Intention A", calculateRoll("6d8+12"), 14, "1d6-1", "d20+2"),
createEnemy("Good Intention B", calculateRoll("6d8+12"), 14, "1d6-1", "d20+2"),
createEnemy("Good Intention C", calculateRoll("6d8+12"), 14, "1d6-1", "d20+2")
]
break
case 82:
encounter.text = "It's the AI from AI Dungeon! Man your battle stations."
encounter.enemies = [
createEnemy("AI", calculateRoll("5d10+10"), 12, "2d4+2", "d20+1", "Hallucinate")
]
break
case 83:
encounter.text = "You shouldn't have kicked that puppy when you were a kid because it's all grown up and it remembers."
encounter.enemies = [
createEnemy("Vengeance Dog", calculateRoll("6d8+18"), 14, "1d8+2", "d20+2", "Intimidating Growl")
]
break
case 84:
encounter.text = "Hah! You're screwed now! Your worst fear is actualized in front of you. It's a thing!"
encounter.enemies = [
createEnemy("Thing You Fear Most", calculateRoll("10d10+20"), 13, "2d6+4", "d20+1", "Morph")
]
break
case 85:
encounter.text = "Well, if it isn't the consequences of your actions."
encounter.enemies = [
createEnemy("Consequence A", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2"),
createEnemy("Consequence B", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2"),
createEnemy("Consequence C", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2"),
createEnemy("Consequence D", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2"),
createEnemy("Consequence E", calculateRoll("3d8+9"), 8, "1d6+1", "d20-2")
]
break
case 86:
encounter.text = "A thousand armies of the Persian empire descend upon you. They will drink the rivers dry. Their arrows will blot out the sun."
encounter.enemies = [
createEnemy("One Thousand", calculateRoll("8d12+16"), 15, "4d6+4", calculateRoll("d20")),
createEnemy("Two Thousand", calculateRoll("8d12+16"), 15, "4d6+4", calculateRoll("d20")),
createEnemy("Three Thousand", calculateRoll("8d12+16"), 15, "4d6+4", calculateRoll("d20"))
]
break
case 87:
encounter.text = "The embodiment of really poor decisions and a hangover approaches you in a disturbing pattern."
encounter.enemies = [
createEnemy("Hangover", calculateRoll("8d8+16"), 15, "2d6+3", "d20-1", "Head Pain3d6"),
createEnemy("Poor Decision A", calculateRoll("8d8+16"), 15, "2d6+3", "d20-1"),
createEnemy("Poor Decision B", calculateRoll("8d8+16"), 15, "2d6+3", "d20-1")
]
break
case 88:
encounter.text = "An annoying sales-person is using hard-sale tactics at you. Resist!"
encounter.enemies = [
createEnemy("Sales-Person", calculateRoll("8d8+16"), 14, "1d6+4", "d20+4", "Big Sale")
]
break
case 89:
encounter.text = "A group of Reddit mods are here. This is not a good sign."
encounter.enemies = [
createEnemy("Reddit Mod A", calculateRoll("2d6"), 12, "1d4+2", "d20+2"),
createEnemy("Reddit Mod B", calculateRoll("2d6"), 12, "1d4+2", "d20+2"),
createEnemy("Reddit Mod C", calculateRoll("2d6"), 12, "1d4+2", "d20+2"),
createEnemy("Reddit Mod D", calculateRoll("2d6"), 12, "1d4+2", "d20+2"),
createEnemy("Grand Reddit Mod", calculateRoll("7d10+14"), 15, "1d10+2", "d20+1")
]
break
case 90:
encounter.text = "An expert in bulshiddo beckoms toward you. You have no other choice but to engage."
encounter.enemies = [
createEnemy("Bulshiddo Expert", calculateRoll("7d10+14"), 15, "1d10+2", "d20+1", "Focus Chit")
]
break
case 91:
encounter.text = "You know how they say \"Hope springs eternal?\" Well, Hope is springing her way to your direction."
encounter.enemies = [
createEnemy("Hope", calculateRoll("7d8+14"), 15, "1d8+3", "d20+1", "Spring Eternal5d4")
]
break
case 92:
encounter.text = "An immodest pixie points and laughs at you. She thinks you're funny looking. Battle is inevitable."
encounter.enemies = [
createEnemy("Pixie", calculateRoll("12d12+12"), 12, "2d6+3", calculateRoll("d20"), "Shameless Magic2d10")
]
break
case 93:
encounter.text = "A touring squad of basketball players send a stray rebound right to your head. It's on now!"
encounter.enemies = [
createEnemy("Scottie P", calculateRoll("6d10+12"), 8, "2d6+2", "d20-2"),
createEnemy("M Jordan", calculateRoll("6d10+12"), 8, "2d6+2", "d20-2"),
createEnemy("L Bird", calculateRoll("6d10+12"), 8, "2d6+2", "d20-2"),
createEnemy("Magic J", calculateRoll("6d10+12"), 8, "2d6+2", "d20-2"),
createEnemy("C Barkley", calculateRoll("6d10+12"), 8, "2d6+2", "d20-2"),
]
break
case 94:
encounter.text = "What happens if you fight the void? Let's see."
encounter.enemies = [
createEnemy("The Void", calculateRoll("5d10+5"), 13, "1d10+2", "d20+2", "Darkness")
]
break
case 95:
encounter.text = "Oh god, I've written so many encounters at this point. Just use your imagination."
encounter.enemies = [
createEnemy("Your Imagination", calculateRoll("6d8+12"), 14, "1d6-1", "d20+2", "Detect Thoughts")
]
break
case 96:
encounter.text = "A tachometer is revving up!"
encounter.enemies = [
createEnemy("Tachometer", calculateRoll("5d10+10"), 14, "2d6+3", "d20+2", "Accelerate")
]
break
case 97:
encounter.text = "Taco Tuesdays are back and with a serious vengeance."
encounter.enemies = [
createEnemy("Taco Tuesday A", calculateRoll("9d8+18"), 11, "1d6+2", "d20+1", "Diarrhea3d10"),
createEnemy("Taco Tuesday B", calculateRoll("9d8+18"), 11, "1d6+2", "d20+1", "Diarrhea3d10")
]
break
case 98:
encounter.text = "There's like one dude screaming here. It's not clear who he's yelling at or why. Can you please shut him up?"
encounter.enemies = [
createEnemy("Screaming Dude", calculateRoll("5d10+10"), 14, "2d6+3", "d20+2", "Scream")
]
break
case 99:
encounter.text = "Magneto has somehow entered your world. He blames you for this injustice."
encounter.enemies = [
createEnemy("Magneto", calculateRoll("6d8+18"), 14, "1d8+2", "d20+2", "Manipulate Metal", "Shield"),
createEnemy("The Juggernaut", calculateRoll("6d8+18"), 14, "1d8+2", "d20+2", "Charge3d10"),
createEnemy("Sabretooth", calculateRoll("6d8+18"), 14, "1d8+2", "d20+2"),
]
break
case 100:
encounter.text = "A banker has come to collect on your debts."
encounter.enemies = [
createEnemy("The Banker", calculateRoll("10d10+20"), 13, "2d6+4", "d20+1", "Prisoner's Dilemma", "PMT Function3d6", "Tax Break")
]
break
}
break
case "easy":
if (encounter.cr == null) encounter.cr = 1
break
case "medium":
if (encounter.cr == null) encounter.cr = 5
break
case "hard":
if (encounter.cr == null) encounter.cr = 9
break
case "boss":
if (encounter.cr == null) encounter.cr = 13
break
case "god":
if (encounter.cr == null) encounter.cr = 17
break
}
for (var enemy of encounter.enemies) {
enemy.health = Math.floor(enemy.health * multiplier)
enemy.initiative = Math.floor(enemy.initiative * multiplier)
enemy.ac = Math.floor(enemy.ac * multiplier)
damagePrefix = enemy.damage.match(/^\d*d\d*/gi)[0]
damageSuffix = enemy.damage.match(/(?<=^\d*d\d*).*$/gi)
damageSuffix = damageSuffix != null ? parseInt(damageSuffix[0]) : 0
damageSuffix += Math.floor(3 * (multiplier - 1))
enemy.damage = damagePrefix + damageSuffix
}
return encounter
}
function createEnemy(name, health, ac, damage, initiative, ...spells) {
var enemy = {
name: name,
health: health,
ac: ac,
damage: damage,
initiative: initiative,
spells: spells
}
return enemy
}
function createInitiativeOrder() {
state.initiativeOrder = []
for (var character of state.characters) {
if (character.health <= 0) continue
state.initiativeOrder.push(character)
}
for (var enemy of state.enemies) {
if (enemy.health <= 0) continue
state.initiativeOrder.push(enemy)
}
state.initiativeOrder.sort(function(a, b) {
return b.calculatedInitiative - a.calculatedInitiative;
});
}
const levelSplits = [0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000, 85000, 100000, 120000, 140000, 165000, 195000, 225000, 265000, 305000, 355000]
function getLevel(experience) {
if (experience < 0) experience = 0
var level
for (level = 0; level < levelSplits.length; level++) {
if (experience < levelSplits[level]) break
}
return level
}
function getNextLevelXp(experience) {
if (experience < 0) experience = 0
var level
for (level = 0; level < levelSplits.length; level++) {
if (experience < levelSplits[level]) return levelSplits[level]
}
return -1
}
function addXpToAll(experience) {
if (experience == 0) return ""
var leveledUp = `\n[The party has gained ${experience} experience!]`
state.characters.forEach(x => {
var haveWord = x.name == "You" ? "have" : "has"
const oldLevel = getLevel(x.experience)
x.experience += experience
const newLevel = getLevel(x.experience)
if (newLevel > oldLevel) leveledUp += `\n[${x.name} ${haveWord} leveled up to ${newLevel}!]`
})
return leveledUp
}
function getHealthMax(character) {
if (character == null) character = getCharacter()
var modifier = 0
var stat = character.stats.find((element) => element.name.toLowerCase() == "constitution")
if (stat != null) modifier = getModifier(stat.value)
var level = getLevel(character.experience)
return 10 + level * (6 + modifier)
}
function getModifier(statValue) {
return Math.floor((statValue - 10) / 2)
}
function findSpellCardIndex(name) {
return storyCards.findIndex((element) => element.type == "spell" && element.keys == name)
}
String.prototype.replaceAt = function(index, replacement) {
return this.substring(0, index) + replacement + this.substring(index + replacement.length);
}
String.prototype.plural = function(revert) {
var plural = {
'(quiz)$' : "$1zes",
'^(ox)$' : "$1en",
'([m|l])ouse$' : "$1ice",
'(matr|vert|ind)ix|ex$' : "$1ices",
'(x|ch|ss|sh)$' : "$1es",
'([^aeiouy]|qu)y$' : "$1ies",
'(hive)$' : "$1s",
'(?:([^f])fe|([lr])f)$' : "$1$2ves",
'(shea|lea|loa|thie)f$' : "$1ves",
'sis$' : "ses",
'([ti])um$' : "$1a",
'(tomat|potat|ech|her|vet)o$': "$1oes",
'(bu)s$' : "$1ses",
'(alias)$' : "$1es",
'(octop)us$' : "$1i",
'(ax|test)is$' : "$1es",
'(us)$' : "$1es",
'([^s]+)$' : "$1s"
};
var singular = {
'(quiz)zes$' : "$1",
'(matr)ices$' : "$1ix",
'(vert|ind)ices$' : "$1ex",
'^(ox)en$' : "$1",
'(alias)es$' : "$1",
'(octop|vir)i$' : "$1us",
'(cris|ax|test)es$' : "$1is",
'(shoe)s$' : "$1",
'(o)es$' : "$1",
'(bus)es$' : "$1",
'([m|l])ice$' : "$1ouse",
'(x|ch|ss|sh)es$' : "$1",
'(m)ovies$' : "$1ovie",
'(s)eries$' : "$1eries",
'([^aeiouy]|qu)ies$' : "$1y",
'([lr])ves$' : "$1f",
'(tive)s$' : "$1",
'(hive)s$' : "$1",
'(li|wi|kni)ves$' : "$1fe",
'(shea|loa|lea|thie)ves$': "$1f",
'(^analy)ses$' : "$1sis",
'((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$': "$1$2sis",
'([ti])a$' : "$1um",
'(n)ews$' : "$1ews",
'(h|bl)ouses$' : "$1ouse",
'(corpse)s$' : "$1",
'(us)es$' : "$1",
's$' : ""
};
var irregular = {
'move' : 'moves',
'foot' : 'feet',
'goose' : 'geese',
'sex' : 'sexes',
'child' : 'children',
'man' : 'men',
'tooth' : 'teeth',
'person' : 'people',
'woman' : 'women',
};
var uncountable = [
'sheep',
'fish',
'deer',
'moose',
'series',
'species',
'money',
'rice',
'information',
'equipment',
'gold',
'bass',
'milk',
'food',
'water',
'bread',
'sugar',
'tea',
'cheese',
'coffee',
'currency',
'seafood',
'oil',
'software'
];
// save some time in the case that singular and plural are the same
if(uncountable.indexOf(this.toLowerCase()) >= 0)
return this;
// check for irregular forms
for(word in irregular){
if(revert){
var pattern = new RegExp(irregular[word]+'$', 'i');
var replace = word;
} else{ var pattern = new RegExp(word+'$', 'i');
var replace = irregular[word];
}
if(pattern.test(this))
return this.replace(pattern, replace);
}
if(revert) var array = singular;
else var array = plural;
// check for matches using regular expressions
for(reg in array){
var pattern = new RegExp(reg, 'i');
if(pattern.test(this))
return this.replace(pattern, array[reg]);
}
return this;
}
function clamp(num, min, max) {
return num <= min
? min
: num >= max
? max
: num
}
function toTitleCase(str) {
return str.replace(
/\w\S*/g,
text => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase()
);
}
function stripPunctuation(str) {
return str.replaceAll(/((\.)|(!))\s*$/g, "")
}
var fantasyFemaleNames = ["Luna", "Kayla", "Serenity", "Eira", "Mirah", "Elowen", "Keira", "Calantha", "Natalia", "Eirlys", "Freya", "Ophelia", "Piper", "Alethea", "Melara", "Seraphina", "Delilah", "Lorna", "Echo", "Bree", "Daniella", "Branwen", "Matilda", "Eve", "Brynhild", "Ithilda", "Belinda", "Catarina", "Jora", "Zelda", "Thalia", "Rowan", "Aurora", "Coral", "Vivian", "Briella", "Elvina", "Lylah", "Mirastral", "Nadira", "Marcella", "Kestrel", "Avis", "Laura", "Vesper", "Lucilla", "Sabine", "Evelyn", "Kalinda", "Celeste", "Lilith", "Wren", "Jasmine", "Ondine", "Gabriella", "Astrid", "Elise", "Helena", "Nova", "Lyndal", "Zara", "Niamh", "Vynessa", "Erin", "Lyriel", "Dracaena", "Lila", "Brynna", "Zephyr", "Kira", "Ava", "Elinor", "Carmilla", "Isabella", "Ariana", "Rhianna", "Sylvie", "Kymberley", "Hazel", "Lirien", "Bridget", "Lyra", "Galatea", "Nadine", "Alethia", "Larissa", "Sariel", "Theodora", "Gwynneth", "Eleanor", "Odessa", "Meryll", "Sophia", "Kaia", "Brynhilda", "Haven", "Eluned", "Selene", "Bryony", "Ciara"]
var fantasyMaleNames = ["Alexander", "Thane", "Gabriel", "Orion", "Grayson", "Cedric", "Sebastian", "Arin", "Liam", "Byerson", "Julian", "Zaneth", "Kel", "Eramon", "Ashfur", "Tristam", "Leonidas", "Ryzlen", "Caspian", "Jarron", "Eudicles", "Tarquin", "Terrence", "Ereth", "Thayon", "Braxton", "Twilight", "Argent", "Whisper", "Daemon", "Victor", "Blackthorn", "Dawnrunner", "Gareth", "Caelum", "Zephyr", "Brennan", "Theo", "Draco", "Cian", "Valoric", "Skye", "Sunfor", "Damon", "Maverick", "Bryson", "Lumo", "Drakken", "Ewen", "Waverley", "Lachlan", "Atlas", "Arden", "Ryker", "Asterion", "Bryon", "Judson", "Griffith", "Logan", "Ethan", "Darius", "Brodeth", "Cassius", "Eamon", "Rowan", "Paxton", "Michael", "Dommon", "Aragorn", "Bastier", "Maximus", "Kenrick", "Jasper", "Lucien", "Bryce", "Ryder", "Damian", "Daxton", "Brantley", "Griffin", "Xander", "Galen", "Brody", "Erek", "Drake", "Thayer", "Kieran", "Heath", "Raeleus", "Alistair", "Bastian", "Asher", "Ronan", "Zane", "Jaxon", "Ambrose", "Malcolm", "Axel", "Ehtan", "Avery", "Kael", "Riley"]
var scifiFemaleNames = ["Jala", "Clea", "Jocosa", "Artemis", "Serafina", "Sevyn", "Tesla", "Lux", "Nine", "Kiara", "Valentina", "Morticia", "Rio", "Xyleena", "Libby", "Valkyrie", "Panika", "Lara", "Fenglina", "Makiko", "Katja", "Paige", "Elie", "Lucie", "Samanta", "Hazel", "Helena", "Leia", "Luminara", "Katan", "Vala", "Inara", "Saffron", "Zoe", "Jayne", "Kaylee", "Maeve", "Kara", "Athena", "Cally", "Anastasia", "Pegi", "Alita", "Alkhema", "Arcena", "Ko", "Bodika", "Candi", "Chi", "Rae", "Cylla", "Daria", "Chalma", "Elita", "Eryx", "Eva", "Nova", "Celeste", "Guri", "Hexen", "Indigo", "Juli", "Katana", "Talia", "Lala", "Mika", "Miranda", "Nebula", "Six", "Sasha", "Silica", "Sky", "Strika", "Terra", "Yori", "Andromeda", "Astra", "Bellatrix", "Callista", "Cosima", "Delphine", "Electra", "Phantasy", "Farrah", "Geneva", "Haven", "Jade", "Juno", "Lillix", "Lynx", "Nya", "Oria", "Parris", "Priya", "Rue", "Clarity", "Bloom", "Decca", "Domonique", "Grazi", "Helvetica", "Cadence"]
var scifiMaleNames = ["Ares", "Astro", "Macro", "Cadmus", "Cyno", "Fade", "Hack", "Hax", "Indigo", "Hinge", "Jarno", "Jax", "Knox", "Link", "Maxx", "Merrick", "Miles", "Mirari", "Niko", "Nano", "Oberon", "Onyx", "Orion", "Osso", "Paradox", "Pip", "Phoenix", "Radius", "Rexx", "Razlin", "Reznor", "Rian", "Roscoe", "Ryker", "Rush", "Riden", "Drake", "Frost", "Cassian", "Neyo", "Maverick", "Azriel", "Auryn", "Daggar", "Evyn", "Jace", "Jaron", "Loki", "Oren", "Ridley", "Sagan", "Silas","Solon", "Stellan", "Sorrel", "Seth", "Theron", "Zen", "Klay", "Blaze", "Xander", "Mace", "Dozer", "Eno", "Tip", "Ray", "Genesis", "Galac", "Eclipse", "Zev", "Zaid", "Wilder", "Sol", "Jupiter", "Mars", "Star", "Cosmo", "Aster", "Lazer", "Zeno", "Sirius", "Azra", "Atom", "Teague", "Rigel", "Cato", "Zhane", "Ace", "Rocket", "Kip", "Meter", "Starbuck", "Roman", "Fiat", "Kyron", "Nyx", "Rune", "Nero", "Quantum", "Nym", "Morphius", "Striker", "Bridger"]
var modernFemaleNames = ["Olivia", "Emma", "Amelia", "Ella", "Isabella", "Mia", "Valerie", "Eliana", "Charlotte", "Mila", "Aria", "Luna", "Harper", "Grace", "Zoey", "Jemma", "Priscilla", "Scarlett", "Hazel", "Ellie", "Naya", "Nila", "Tamia", "Cecilia", "Arianna", "Abigail", "Riley", "Autumn", "Maya", "Madelyn", "Maria", "Melody", "Sophia", "Ava", "Luz", "Eleanor", "Ivy", "Freya", "Alice", "Violet", "Clara", "Daphne", "Evelyn", "Nora", "Lucy", "Poppy", "Rose", "Chloe", "Phoebe", "Elsie", "Cordelia", "Willow", "Daisy", "Thea", "Adeline", "Arabella", "Maisie", "Lola", "Olive", "Sienna", "Sierra", "Elena", "Sadie", "Sophie", "Julia", "Alexandra", "Jane", "Mira", "Talia", "Zara", "Vera", "Amara", "Cynthia", "Hannah", "Aurora", "Anya", "Erin", "Felicity", "Juno", "Yelena", "Naomi", "Caroline", "Miriam", "Veronica", "Molly", "June", "Nina", "Piper", "Helena", "Amari", "Everly", "Bonnie", "Alina", "Emilia", "Harriet", "Isabel", "Sofia", "Kayla", "Lena", "Megan", "Diana"]
var modernMaleNames = ["Jackson", "Aiden", "Charles", "Adam", "Christopher", "Daniel", "Liam", "Oliver", "Mateo", "Henry", "Lucas", "William", "Theodore", "Noah", "John", "Arnold", "Norman", "Ralph", "Virgil", "Will", "Sam", "Luca", "David", "Joseph", "Mason", "Luke", "Matthew", "Dylan", "Jacob", "Isaac", "Anthony", "Carter", "Caleb", "Cooper", "Josiah", "Nolan", "Cameron", "Nathan", "Josh", "Angel", "Andrew", "Aaron", "Ian", "Eli", "Ryan", "Everett", "Enzo", "Parker", "Jeremiah", "Landon", "Jordan", "Austin", "Jameson", "Myles", "Dominic", "Nicholas", "Kayden", "Hunter", "Harrison", "Milo", "Arthur", "Ryder", "Archer", "Luis", "George", "Evan", "Carlos", "Juan", "Jason", "Leon", "Calvin", "Ivan", "Cole", "Chase", "Dean", "Jayce", "Olliver", "Alan", "Jesus", "Charlie", "Tyler", "Elliot", "Kevin", "Ayden", "Felix", "Tate", "Jesse", "Brody", "Tucker", "Peter", "Joel", "Edward", "Oscar", "Victor", "Brandon", "Bruce", "Abel", "Richard", "Riley", "Patrick", "Eric", "Elian", "Louis"]
var nordicFemaleNames = ["Freya", "Dagny", "Ingrid", "Froya", "Elin", "Solveig", "Maja", "Sol", "Linnea", "Vilde", "Var", "Aldis", "Alfrida", "Alfsol", "Alva", "Alvdis", "Alvida", "Andora", "Anveig", "Asa", "Astri", "Astrid", "Bolette", "Brynhild", "Disa", "Eir", "Eira", "Eidis", "Elevine", "Elfi", "Embla", "Erna", "Freja", "Frida", "Fredrikke", "Gerda", "Gry", "Gurina", "Gurine", "Gyda", "Haddy", "Halgerd", "Helga", "Helje", "Helle", "Herdis", "Herfrid", "Hilde", "Hulda", "Inga", "Idun", "Isfrid", "Iverna", "Iverine", "Jorgina", "Kari", "Lagertha", "Liv", "Livunn", "Malfrid", "Malmfrid", "Nanna", "Oda", "Odel", "Odine", "Olava", "Runa", "Ragnfrid", "Randi", "Ragnhild", "Saga", "Sif", "Sigrid", "Siv", "Solvei", "Soma", "Svanild", "Thora", "Tora", "Thurid", "Torveig", "Torfrid", "Trude", "Tyra", "Tyri", "Udna", "Unni", "Una", "Unnlaug", "Unnveig", "Valdine", "Vedis", "Valborg", "Vivil", "Ylva", "Yngva", "Thoril", "Thorine", "Sigfrida", "Sigun", "Sigvor", "Signe", "Reidunn"]
var nordicMaleNames = ["Erik", "Bjorn", "Lars", "Asmund", "Harald", "Arne", "Odin", "Ivar", "Leif", "Aesir", "Axel", "Aren", "Aric", "Balder", "Birger", "Bjarke", "Bjarne", "Nils", "Steig", "Erling", "Espen", "Fenrir", "Frey", "Einar", "Garald", "Anders", "Gunnar", "Hagan", "Halfthor", "Halfdan", "Kjell", "Hanne", "Ingvar", "Helge", "Herleif", "Jarl", "Joran", "Magnus", "Norrell", "Njord", "Olaf", "Osman", "Ragnar", "Sigurd", "Steffen", "Sten", "Sven", "Tor", "Torben", "Troels", "Tyr", "Tyrell", "Ulf", "Viggo", "Vali", "Vidar", "Volund", "Wayde", "Waddell", "Alviss", "Anneli", "Stig", "Eino", "Haakon", "Haldor", "Iver", "Sindri", "Trym", "Varg", "Alf", "Amund", "Arn", "Arnstein", "Arvid", "Bjarni", "Bjoern", "Bragi", "Brede", "Dag", "Dagfinn", "Egil", "Endre", "Erlend", "Even", "Finn", "Flosi", "Fredrik", "Frode", "Freyr", "Geir", "Gisli", "Grim", "Gudbrand", "Gustav", "Hakan", "Hakon", "Hans", "Helgi", "Ingolf", "Jomar", "Knut", "Orm"]
function generateName(genre, male) {
if (genre.toLowerCase() == "fantasy") {
if (male) {
if (state.fantasyMaleIndex == null || state.fantasyMaleIndex >= fantasyMaleNames.length) {
state.fantasyMaleIndex = 0
state.fantasyMaleSeed = getRandomInteger(1, 1000)
}
shuffle(fantasyMaleNames, state.fantasyMaleSeed)
return fantasyMaleNames[state.fantasyMaleIndex++]
} else {
if (state.fantasyFemaleIndex == null || state.fantasyFemaleIndex >= fantasyFemaleNames.length) {
state.fantasyFemaleIndex = 0
state.fantasyFemaleSeed = getRandomInteger(1, 1000)
}
shuffle(fantasyFemaleNames, state.fantasyFemaleSeed)
return fantasyFemaleNames[state.fantasyFemaleIndex++]
}
} else if (genre.toLowerCase() == "modern") {
if (male) {
if (state.modernMaleIndex == null || state.modernMaleIndex >= modernMaleNames.length) {
state.modernMaleIndex = 0
state.modernMaleSeed = getRandomInteger(1, 1000)
}
shuffle(modernMaleNames, state.modernMaleSeed)
return modernMaleNames[state.modernMaleIndex++]
} else {
if (state.modernFemaleIndex == null || state.modernFemaleIndex >= modernFemaleNames.length) {
state.modernFemaleIndex = 0
state.modernFemaleSeed = getRandomInteger(1, 1000)
}
shuffle(modernFemaleNames, state.modernFemaleSeed)
return modernFemaleNames[state.modernFemaleIndex++]
}
} else if (genre.toLowerCase() == "scifi") {
if (male) {
if (state.scifiMaleIndex == null || state.scifiMaleIndex >= scifiMaleNames.length) {
state.scifiMaleIndex = 0
state.scifiMaleSeed = getRandomInteger(1, 1000)
}
shuffle(scifiMaleNames, state.scifiMaleSeed)
return scifiMaleNames[state.scifiMaleIndex++]
}
else {
if (state.scifiFemaleIndex == null || state.scifiFemaleIndex >= scifiFemaleNames.length) {
state.scifiFemaleIndex = 0
state.scifiFemaleSeed = getRandomInteger(1, 1000)
}
shuffle(scifiFemaleNames, state.scifiFemaleSeed)
return scifiFemaleNames[state.scifiFemaleIndex++]
}
} else if (genre.toLowerCase() == "nordic") {
if (male) {
if (state.nordicMaleIndex == null || state.nordicMaleIndex >= nordicMaleNames.length) {
state.nordicMaleIndex = 0
state.nordicMaleSeed = getRandomInteger(1, 1000)
}
shuffle(nordicMaleNames, state.nordicMaleSeed)
return nordicMaleNames[state.nordicMaleIndex++]
}
else {
if (state.nordicFemaleIndex == null || state.nordicFemaleIndex >= nordicFemaleNames.length) {
state.nordicFemaleIndex = 0
state.nordicFemaleSeed = getRandomInteger(1, 1000)
}
shuffle(nordicFemaleNames, state.nordicFemaleSeed)
return nordicFemaleNames[state.nordicFemaleIndex++]
}
}
}