mirror of
https://github.com/raeleus/Hashtag-DnD.git
synced 2025-07-04 20:50:27 -04:00
Initial commit
This commit is contained in:
commit
0e80d726b4
7 changed files with 2354 additions and 0 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
5
Context.js
Normal file
5
Context.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const modifier = (text) => {
|
||||
return { text }
|
||||
}
|
||||
|
||||
modifier(text)
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2024 raeleus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
399
Library.js
Normal file
399
Library.js
Normal file
|
@ -0,0 +1,399 @@
|
|||
function getRandomInteger(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1) ) + min;
|
||||
}
|
||||
|
||||
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) {
|
||||
return command.substring(match.index).replace(/^"/, "").replace(/"$/, "").replaceAll(/\\"/g, '"')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function searchArgument(command, pattern) {
|
||||
var index = searchArgumentIndex(command, pattern)
|
||||
if (index == -1) 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 matches[0]
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
function getSides(rolltext) {
|
||||
var matches = rolltext.match(/(?<=d)\d+/)
|
||||
if (matches != null) {
|
||||
return matches[0]
|
||||
}
|
||||
|
||||
return 20
|
||||
}
|
||||
|
||||
function formatRoll(text) {
|
||||
var matches = text.match(/(?<=.*)\d*d\d+(?=.*)/)
|
||||
if (matches != null) {
|
||||
return matches[0]
|
||||
}
|
||||
|
||||
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 score = 0;
|
||||
for (i = 0; i < dice; i++) {
|
||||
score += getRandomInteger(1, sides)
|
||||
}
|
||||
|
||||
return score
|
||||
}
|
||||
|
||||
function getCharacter(characterName) {
|
||||
if (characterName == null) characterName = state.characterName
|
||||
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
|
||||
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
|
||||
}
|
||||
state.characters.push(character)
|
||||
return character
|
||||
}
|
||||
|
||||
function deleteCharacter(name) {
|
||||
var index = state.characters.findIndex((element) => element.name == name)
|
||||
state.characters.splice(index, 1)
|
||||
}
|
||||
|
||||
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 => {
|
||||
const oldLevel = getLevel(x.experience)
|
||||
x.experience += experience
|
||||
const newLevel = getLevel(x.experience)
|
||||
if (newLevel > oldLevel) leveledUp += `\n[${x.name} has 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.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()
|
||||
);
|
||||
}
|
300
Output.js
Normal file
300
Output.js
Normal file
|
@ -0,0 +1,300 @@
|
|||
const modifier = (text) => {
|
||||
if (state.show == null) return { text }
|
||||
|
||||
if (state.characterName == null) {
|
||||
text = " "
|
||||
return { text }
|
||||
}
|
||||
var character = getCharacter()
|
||||
var possessiveName = character == null ? null : getPossessiveName(character.name)
|
||||
var type = history[history.length - 1].type
|
||||
const originalText = text
|
||||
text = type != "story" ? "" : history[history.length - 1].text.endsWith("\n") ? "" : "\n"
|
||||
|
||||
switch (state.show) {
|
||||
case "create":
|
||||
switch (state.createStep) {
|
||||
case 0:
|
||||
text += `***CHARACTER CREATION***\nCharacter: ${state.tempCharacter.name}\nWould you like to use a prefab character? (y/n/q to quit)\n`
|
||||
break
|
||||
case 1:
|
||||
text += `What class is your character?\n`
|
||||
break
|
||||
case 2:
|
||||
text += `You rolled the following stat dice: ${state.statDice}\nChoose your abilities in order from highest to lowest\n1. Strength: Physical power and endurance\n2. Dexterity: Agility and coordination\n3. Constitution: Toughness and physique \n4. Intelligence: Reasoning and memory\n5. Wisdom: Judgement and insight\n6. Charisma: Force of personality and persuasiveness\n\nEnter the numbers with spaces between or q to quit.\n`
|
||||
break
|
||||
case 3:
|
||||
text += `What ability is your spell casting ability?\n1. Intelligence\n2. Wisdom\n3. Charisma\n4. Not a spell caster\nq to quit\n`
|
||||
break
|
||||
case 4:
|
||||
text += `Enter a short summary about your character or q to quit\n`
|
||||
break
|
||||
case 100:
|
||||
text += `What character will you choose?\n1. Fighter: A skilled melee warrior specializing in weapons and armor.\n2. Cleric: A follower of a deity that can call on divine power.\n3. Rogue: An expert in stealth, subterfuge, and exploitation.\n4. Ranger: A talented hunter adept in tracking, survival, and animal handling.\n5. Barbarian: Combat expert focused on brute strength and raw fury.\n6. Bard: A musician that can transform song and word into magic.\n7. Druid: Commands the natural world to cast spells and harness its power.\n8. Monk: A martial artist who has mastered melee and unarmed combat.\n9. Paladin: A virtuous holy warrior with expertise in armor and mysticism.\n10. Wizard: An expert in magic ability who found their power through arcane knowledge.\n11. Sorcerer: A masterful spellcaster deriving their power from an innate source.\n12. Warlock: A magic user granted ability by a pact with a powerful patron.\n13. Artificer: An inventor and alchemist capable of imbuing objects with magic.\n\nEnter the number or q to quit.\n`
|
||||
break
|
||||
case 500:
|
||||
text += `${state.tempCharacter.name} the ${state.tempCharacter.className} has been created.\nType #bio to see a summary of your character.\n***********\n`
|
||||
break;
|
||||
case null:
|
||||
text += `[Character creation has been aborted!]\n`
|
||||
break
|
||||
}
|
||||
break
|
||||
case "bio":
|
||||
text += `*** ${possessiveName.toUpperCase()} BIO ***\n`
|
||||
text += `Class: ${character.className}\n`
|
||||
text += `Health: ${character.health}/${getHealthMax()}\n`
|
||||
text += `Experience: ${character.experience}\n`
|
||||
text += `Level: ${getLevel(character.experience)}\n`
|
||||
var nextLevel = getNextLevelXp(character.experience)
|
||||
text += `Next level at: ${nextLevel == - 1 ? "(at maximum)": nextLevel + " xp"}\n\n`
|
||||
text += `-ABILITIES-\n`
|
||||
|
||||
character.stats.forEach(function(x) {
|
||||
text += `* ${x.name} ${x.value}\n`
|
||||
})
|
||||
|
||||
text += `----\n\n`
|
||||
|
||||
text += `-SKILLS-\n`
|
||||
|
||||
character.skills.forEach(function(x) {
|
||||
const stat = character.stats.find(y => y.name.toLowerCase() == x.stat.toLowerCase())
|
||||
var modifier = x.modifier + (stat != null ? getModifier(stat.value): 0)
|
||||
if (modifier >= 0) modifier = `+${modifier}`
|
||||
text += `* ${toTitleCase(x.name)} (${x.stat}) ${modifier}\n`
|
||||
})
|
||||
|
||||
text += `----\n\n`
|
||||
|
||||
text += `Melee Ability: ${character.meleeStat == null ? "none" : character.meleeStat}\n\n`
|
||||
text += `Ranged Ability: ${character.rangedStat == null ? "none" : character.rangedStat}\n\n`
|
||||
text += `Spellcasting Ability: ${character.spellStat == null ? "none" : character.spellStat}\n\n`
|
||||
|
||||
if (character.spellStat != null) {
|
||||
text += `-SPELLS-\n`
|
||||
|
||||
character.spells.forEach(function(x) {
|
||||
text += `* ${x}\n`
|
||||
})
|
||||
|
||||
text += `----\n\n`
|
||||
}
|
||||
|
||||
text += `-INVENTORY-\n`
|
||||
|
||||
character.inventory.forEach(function(x) {
|
||||
text += `* ${x.quantity} ${toTitleCase(x.name.plural(x.quantity == 1))}\n`
|
||||
})
|
||||
|
||||
text += `----\n\n`
|
||||
|
||||
text += `Summary: ${character.summary}\n\n`
|
||||
|
||||
text += `**************\n\n`
|
||||
break
|
||||
case "showNotes":
|
||||
text += "*** NOTES ***"
|
||||
var counter = 1
|
||||
state.notes.forEach(function(x) {
|
||||
text += `\n${counter++}. ${x}`
|
||||
})
|
||||
text += "\n**************\n\n"
|
||||
break
|
||||
case "clearNotes":
|
||||
text += "[Notes cleared successfully]\n"
|
||||
break
|
||||
case "inventory":
|
||||
text += `*** ${possessiveName.toUpperCase()} INVENTORY ***`
|
||||
if (character.inventory.length > 0) {
|
||||
character.inventory.forEach(function(x) {
|
||||
text += `\n* ${x.quantity} ${toTitleCase(x.name.plural(x.quantity == 1))}`
|
||||
})
|
||||
} else {
|
||||
text += `\n${possessiveName} inventory is empty!`
|
||||
}
|
||||
text += "\n******************\n\n"
|
||||
break
|
||||
case "characters":
|
||||
text += `*** CHARACTERS ***`
|
||||
if (state.characters.length > 0) {
|
||||
state.characters.forEach(function(x) {
|
||||
text += `\n* ${x.name} the ${x.className}: ${x.summary}`
|
||||
})
|
||||
} else {
|
||||
text += `\n${possessiveName} inventory is empty!`
|
||||
}
|
||||
text += "\n******************\n\n"
|
||||
break
|
||||
case "spellbook":
|
||||
text += `*** ${possessiveName.toUpperCase()} SPELLBOOK ***`
|
||||
if (character.spells.length > 0) {
|
||||
character.spells.forEach(function(x) {
|
||||
text += "\n* " + x
|
||||
})
|
||||
} else {
|
||||
text += `\n${possessiveName} spellbook is empty!`
|
||||
}
|
||||
text += "\n******************\n\n"
|
||||
break
|
||||
case "stats":
|
||||
text += `*** ${possessiveName.toUpperCase()} ABILITIES ***\n`
|
||||
if (character.stats.length > 0) {
|
||||
character.stats.forEach(function(x) {
|
||||
text += `* ${x.name} ${x.value}\n`
|
||||
})
|
||||
} else {
|
||||
text += `${character.name} has no abilities!\n`
|
||||
}
|
||||
text += "******************\n\n"
|
||||
break
|
||||
case "skills":
|
||||
text += `*** ${possessiveName.toUpperCase()} SKILLS ***\n`
|
||||
if (character.skills.length > 0) {
|
||||
character.skills.forEach(function(x) {
|
||||
const stat = character.stats.find(y => y.name.toLowerCase() == x.stat.toLowerCase())
|
||||
var modifier = x.modifier + (stat != null ? getModifier(stat.value): 0)
|
||||
if (modifier >= 0) modifier = `+${modifier}`
|
||||
text += `* ${toTitleCase(x.name)} (${x.stat}) ${modifier}\n`
|
||||
})
|
||||
} else {
|
||||
text += `${character.name} has no skills!\n`
|
||||
}
|
||||
text += "******************\n\n"
|
||||
break
|
||||
case "none":
|
||||
text += " "
|
||||
break
|
||||
case "prefix":
|
||||
text = state.prefix + originalText
|
||||
break
|
||||
case "clearInventory":
|
||||
text += `[${possessiveName} inventory has been emptied]\n`
|
||||
break
|
||||
case "reset":
|
||||
text += "[All settings have been reset]\n"
|
||||
break
|
||||
case "help":
|
||||
|
||||
text += "--Basic Hashtags--"
|
||||
text += "\n#roll (advantage|disadvantage) (dice_value)"
|
||||
text += "\n Rolls a die/dice and shows the result. dice_value can be in the following formats 5d20 or d20 or 20"
|
||||
text += "\n#shownotes"
|
||||
text += "\n Shows all the notes."
|
||||
text += "\n#note message"
|
||||
text += "\n Adds the specified message as a note."
|
||||
text += "\n#clearnotes"
|
||||
text += "\n Removes all notes."
|
||||
text += "\n#removenote value"
|
||||
text += "\n Removes the specified note as indicated by the number listed in #shownotes."
|
||||
|
||||
text += "\n\n--Characters--"
|
||||
text += "\n#setup"
|
||||
text += "\n Launches the create character setup."
|
||||
text += "\n#bio"
|
||||
text += "\n Shows the character's abilities, skills, spells, inventory, and everything else about this character."
|
||||
text += "\n#setclass"
|
||||
text += "\n Sets the class of the character for player reference."
|
||||
text += "\n#setsummary"
|
||||
text += "\n Sets the summary of the character for player reference."
|
||||
text += "\n#sethealth value"
|
||||
text += "\n Sets the character's health to specified value. It's capped at the character's max health."
|
||||
text += "\n#heal value"
|
||||
text += "\n Increases the character's health by the specified value. It's capped at the character's max health."
|
||||
text += "\n#damage value"
|
||||
text += "\n Decreases the character's health by the specified value. Reaching 0 causes the character to become \"unconcious\"."
|
||||
text += "\n#rest"
|
||||
text += "\n Sets all of the characters' health to their maximums. Use #shortrest to only restore half health."
|
||||
text += "\n#setxp value"
|
||||
text += "\n Sets the character's experience to the specified value."
|
||||
text += "\n#addxp value"
|
||||
text += "\n Increases the character's experience by the specified value. The player is notified if there is a level up."
|
||||
text += "\n#setautoxp value"
|
||||
text += "\n Automatically increases the experience of all party members when a #try, #attack, or #cast is called. The amount of experience is scaled based on the difficulty of the check with any check 20 or higher will result in the maximum specified by value. Set to 0 to disable."
|
||||
text += "\n#showautoxp"
|
||||
text += "\n Shows the value of the auto xp."
|
||||
text += "\n#levelup"
|
||||
text += "\n Increases the character's experience by the exact amount needed to reach the next level."
|
||||
text += "\n#showcharacters"
|
||||
text += "\n Lists all current characters and their classes/summaries."
|
||||
text += "\n#removecharacter name"
|
||||
text += "\n Removes the character that has the indicated name."
|
||||
|
||||
text += "\n\n--Character Checks--"
|
||||
text += "\n#check (ability|skill) (advantage|disadvantage) (difficulty_value or effortless|easy|medium|hard|impossible)"
|
||||
text += "\n Rolls a d20 and compares the result (modified by the character's ability/skill) to the specified difficulty"
|
||||
text += "\n#try (ability|skill) (advantage|disadvantage) (difficulty_value or effortless|easy|medium|hard|impossible) task"
|
||||
text += "\n Attempts to do the task based on the character's ability/skill against the specified difficulty."
|
||||
text += "\n#attack (ranged) (advantage|disadvantage) (ac or effortless|easy|medium|hard|impossible) target"
|
||||
text += "\n Attacks the specified target with a melee (the default) or ranged attack. The roll is compared against the specified AC which will determine if the attack succeeds or misses."
|
||||
text += "\n#cast (advantage|disadvantage) (difficulty_value or effortless|easy|medium|hard|impossible) spell(target)"
|
||||
text += "\n Character will cast the indicated spell if the spell is in their spellbook. It will be a targeted spell if a target is indicated. The roll is modified by the spell casting ability of the character. You may type a phrase without quotes for spell such as \"cast fire bolt at the giant chicken\""
|
||||
|
||||
text += "\n\n--Abilities--"
|
||||
text += "\n#setability ability value"
|
||||
text += "\n Adds the ability to the character if necessary and sets it to the specified value."
|
||||
text += "\n#showabilities"
|
||||
text += "\n Shows the character's list of abilities."
|
||||
text += "\n#removeability ability"
|
||||
text += "\n Removes the ability from the character's list of abilities."
|
||||
text += "\n#clearabilities"
|
||||
text += "\n Removes all abilities from the character."
|
||||
text += "\n#setspellability ability"
|
||||
text += "\n Sets the ability that affects the modifier for #cast."
|
||||
text += "\n#setmeleeability ability"
|
||||
text += "\n Sets the character's ability modifier that affects melee attacks."
|
||||
text += "\n#setrangedability ability"
|
||||
text += "\n Sets the character's ability modifier that affects ranged attacks."
|
||||
|
||||
text += "\n\n--Skills--"
|
||||
text += "\n#setskill skill ability value"
|
||||
text += "\n Adds the skill to the character if necessary, and associates it with the specified ability and value."
|
||||
text += "\n#showskills"
|
||||
text += "\n Shows the character's list of skills"
|
||||
text += "\n#removeskill"
|
||||
text += "\n Removes the skill from the character's list of skills."
|
||||
text += "\n#clearskills"
|
||||
text += "\n Removes all skills from the character."
|
||||
|
||||
text += "\n\n--Inventory--"
|
||||
text += "\n#take (quantity) item"
|
||||
text += "\n Adds the specified quantity of item to the character's inventory. If a quantity is omitted, it's assumed to be 1. The words the, a, and an are ignored."
|
||||
text += "\n#buy (buy_quantity) buy_item (sell_quantity) sell_item"
|
||||
text += "\n Adds the specified buy_quantity of the buy_item to the character's inventory and also removes the sell_quantity of sell_item. If quantities are omitted, they are assumed to be 1. Quotes are necessary for items with spaces. The words for, with, the, a, and an are ignored."
|
||||
text += "\n#sell (sell_quantity) sell_item (buy_quantity) buy_item"
|
||||
text += "\n Just like #buy, but with the parameters reversed. Adds the specified buy_quantity of the buy_item to the character's inventory and also removes the sell_quantity of sell_item. If quantities are omitted, they are assumed to be 1. The words for, with, the, a, and an are ignored."
|
||||
text += "\n#drop (quantity or all|every) item"
|
||||
text += "\n Removes the specified quantity of item from the character's inventory. If a quantity is omitted, it's assumed to be 1. The words the, a, and an are ignored."
|
||||
text += "\n#give other_character (quantity or all|every) item"
|
||||
text += "\n Removes the quantity of item from the character's inventory and adds it to the other_character's inventory. If a quantity is omitted, it's assumed to be 1. The words the, a, and an are ignored."
|
||||
text += "\n#inventory"
|
||||
text += "\n Shows the items in the inventory of the character."
|
||||
text += "\n#clearinventory"
|
||||
text += "\n Removes all items from the character's inventory."
|
||||
|
||||
text += "\n\n--Spells--"
|
||||
text += "\n#learnspell spell"
|
||||
text += "\n Adds the specified spell to the character's spellbook. Creates a story card if necessary."
|
||||
text += "\n#forgetSpell"
|
||||
text += "\n Removes the specified spell from the character's spellbook"
|
||||
text += "\n#clearspells"
|
||||
text += "\n Removes all spells from the character's spellbook."
|
||||
text += "\n#spellbook"
|
||||
text += "\n Shows the list of spells that the character has learned."
|
||||
|
||||
text += "\n\n--Danger Zone--"
|
||||
text += "\n#reset"
|
||||
text += "\n Removes all characters and changes all settings to their defaults. Use with caution!"
|
||||
|
||||
text += "\n\n--Other--"
|
||||
text += "\n#help"
|
||||
text += "\n This long ass help menu. I am paid by lines of codes."
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
state.show = null
|
||||
return { text }
|
||||
}
|
||||
|
||||
modifier(text)
|
2
README.md
Normal file
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Hashtag-DnD
|
||||
Scenario script for AI Dungeon
|
Loading…
Add table
Add a link
Reference in a new issue