diff --git a/Input.js b/Input.js index 7f50b6b..69bf497 100644 --- a/Input.js +++ b/Input.js @@ -81,6 +81,7 @@ const setDamageSynonyms = ["setdamage"] const setProficiencySynonyms = ["setproficiency", "setweaponproficiency"] const healPartySynonyms = ["healparty", "healcharacters"] const blockSynonyms = ["block", "parry", "nullify", "invalidate"] +const repeatTurnSynonyms = ["repeatturn", "repeat"] const helpSynonyms = ["help"] const modifier = (text) => { @@ -129,7 +130,7 @@ const modifier = (text) => { return { text } } - if (!found) found = processCommandSynonyms(command, commandName, helpSynonyms.concat(rollSynonyms, noteSynonyms, eraseNoteSynonyms, showNotesSynonyms, clearNotesSynonyms, showCharactersSynonyms, removeCharacterSynonyms, generateNameSynonyms, setDefaultDifficultySynonyms, showDefaultDifficultySynonyms, renameCharacterSynonyms, cloneCharacterSynonyms, createLocationSynonyms, showLocationsSynonyms, goToLocationSynonyms, removeLocationSynonyms, getLocationSynonyms, clearLocationsSynonyms, goNorthSynonyms, goSouthSynonyms, goEastSynonyms, goWestSynonyms, encounterSynonyms, showEnemiesSynonyms, addEnemySynonyms, removeEnemySynonyms, clearEnemiesSynonyms, initiativeSynonyms, turnSynonyms, fleeSynonyms, versionSynonyms, setupEnemySynonyms, healSynonyms, damageSynonyms, restSynonyms, addExperienceSynonyms, healPartySynonyms, blockSynonyms, resetSynonyms), function () {return true}) + if (!found) found = processCommandSynonyms(command, commandName, helpSynonyms.concat(rollSynonyms, noteSynonyms, eraseNoteSynonyms, showNotesSynonyms, clearNotesSynonyms, showCharactersSynonyms, removeCharacterSynonyms, generateNameSynonyms, setDefaultDifficultySynonyms, showDefaultDifficultySynonyms, renameCharacterSynonyms, cloneCharacterSynonyms, createLocationSynonyms, showLocationsSynonyms, goToLocationSynonyms, removeLocationSynonyms, getLocationSynonyms, clearLocationsSynonyms, goNorthSynonyms, goSouthSynonyms, goEastSynonyms, goWestSynonyms, encounterSynonyms, showEnemiesSynonyms, addEnemySynonyms, removeEnemySynonyms, clearEnemiesSynonyms, initiativeSynonyms, turnSynonyms, fleeSynonyms, versionSynonyms, setupEnemySynonyms, healSynonyms, damageSynonyms, restSynonyms, addExperienceSynonyms, healPartySynonyms, blockSynonyms, repeatTurnSynonyms, resetSynonyms), function () {return true}) if (found == null) { if (state.characterName == null) { @@ -225,6 +226,7 @@ const modifier = (text) => { if (text == null) text = processCommandSynonyms(command, commandName, setProficiencySynonyms, doSetProficiency) if (text == null) text = processCommandSynonyms(command, commandName, healPartySynonyms, doHealParty) if (text == null) text = processCommandSynonyms(command, commandName, blockSynonyms, doBlock) + if (text == null) text = processCommandSynonyms(command, commandName, repeatTurnSynonyms, doRepeatTurn) if (text == null) text = processCommandSynonyms(command, commandName, helpSynonyms, doHelp) if (text == null) { var character = getCharacter() @@ -2671,57 +2673,11 @@ function doTurn(command) { return "\nDefeat! The entire party has been incapacitated.\n" } - var activeCharacter = state.initiativeOrder[0] - var activeCharacterName = toTitleCase(activeCharacter.name) - var possessiveName = getPossessiveName(activeCharacter.name) - if (possessiveName == "Your") possessiveName = "your" + return executeTurn(state.initiativeOrder[0]) +} - if (activeCharacter.className != null) { - state.show = "none" - return `\n[It is ${possessiveName} turn]\n` - } else { - var characters = state.characters.filter(x => x.health > 0) - var target = characters[getRandomInteger(0, characters.length - 1)] - var areWord = target.name == "You" ? "are" : "is" - var targetNameAdjustedCase = target.name == "You" ? "you" : toTitleCase(target.name) - var attack = calculateRoll(`1d20${activeCharacter.hitModifier > 0 ? "+" + activeCharacter.hitModifier : activeCharacter.hitModifier < 0 ? activeCharacter.hitModifier : ""}`) - var hit = attack >= target.ac - - var text = `\n[It is ${possessiveName} turn]\n` - if (getRandomBoolean() || activeCharacter.spells.length == 0) { - if (hit) { - state.blockCharacter = target - state.blockPreviousHealth = target.health - var damage = isNaN(activeCharacter.damage) ? calculateRoll(activeCharacter.damage) : activeCharacter.damage - target.health = Math.max(target.health - damage, 0) - - text += `\n[Character AC: ${target.ac} Attack roll: ${attack}]\n` - - text += `${activeCharacterName} attacks ${targetNameAdjustedCase} for ${damage} damage!\n` - if (target.health == 0) text += ` ${toTitleCase(target.name)} ${areWord} unconscious! \n` - else text += ` ${toTitleCase(target.name)} ${areWord} at ${target.health} health.\n` - } else text += `${activeCharacterName} attacks ${targetNameAdjustedCase} but misses!\n` - } else { - var spell = activeCharacter.spells[getRandomInteger(0, activeCharacter.spells.length - 1)] - var diceMatches = spell.match(/(?<=^.*)\d*d\d+((\+|-)\d+)?$/gi) - if (diceMatches == null) text += `${activeCharacterName} casts spell ${spell}!` - else { - if (hit) { - var damage = calculateRoll(diceMatches[0]) - var spell = spell.substring(0, spell.length - diceMatches[0].length) - target.health = Math.max(target.health - damage, 0) - - text += `\n[Character AC: ${target.ac} Attack roll: ${attack}]\n` - - text += `${activeCharacterName} casts spell ${spell} at ${targetNameAdjustedCase} for ${damage} damage!` - - if (target.health == 0) text += ` ${toTitleCase(target.name)} ${areWord} unconscious!\n` - else text += ` ${toTitleCase(target.name)} ${areWord} at ${target.health} health.\n` - } else text += `${activeCharacterName} casts spell ${spell} at ${targetNameAdjustedCase} but misses!\n` - } - } - return text - } +function doRepeatTurn(command) { + return executeTurn(state.initiativeOrder[0]) } function doBlock(command) { diff --git a/Library.js b/Library.js index 2ed833e..7962552 100644 --- a/Library.js +++ b/Library.js @@ -314,6 +314,59 @@ function deleteCharacter(name) { state.characters.splice(index, 1) } +function executeTurn(activeCharacter) { + var activeCharacterName = toTitleCase(activeCharacter.name) + var possessiveName = getPossessiveName(activeCharacter.name) + if (possessiveName == "Your") possessiveName = "your" + + if (activeCharacter.className != null) { + state.show = "none" + return `\n[It is ${possessiveName} turn]\n` + } else { + var characters = state.characters.filter(x => x.health > 0) + var target = characters[getRandomInteger(0, characters.length - 1)] + var areWord = target.name == "You" ? "are" : "is" + var targetNameAdjustedCase = target.name == "You" ? "you" : toTitleCase(target.name) + var attack = calculateRoll(`1d20${activeCharacter.hitModifier > 0 ? "+" + activeCharacter.hitModifier : activeCharacter.hitModifier < 0 ? activeCharacter.hitModifier : ""}`) + var hit = attack >= target.ac + + var text = `\n[It is ${possessiveName} turn]\n` + if (getRandomBoolean() || activeCharacter.spells.length == 0) { + if (hit) { + state.blockCharacter = target + state.blockPreviousHealth = target.health + var damage = isNaN(activeCharacter.damage) ? calculateRoll(activeCharacter.damage) : activeCharacter.damage + target.health = Math.max(target.health - damage, 0) + + text += `\n[Character AC: ${target.ac} Attack roll: ${attack}]\n` + + text += `${activeCharacterName} attacks ${targetNameAdjustedCase} for ${damage} damage!\n` + if (target.health == 0) text += ` ${toTitleCase(target.name)} ${areWord} unconscious! \n` + else text += ` ${toTitleCase(target.name)} ${areWord} at ${target.health} health.\n` + } else text += `${activeCharacterName} attacks ${targetNameAdjustedCase} but misses!\n` + } else { + var spell = activeCharacter.spells[getRandomInteger(0, activeCharacter.spells.length - 1)] + var diceMatches = spell.match(/(?<=^.*)\d*d\d+((\+|-)\d+)?$/gi) + if (diceMatches == null) text += `${activeCharacterName} casts spell ${spell}!` + else { + if (hit) { + var damage = calculateRoll(diceMatches[0]) + var spell = spell.substring(0, spell.length - diceMatches[0].length) + target.health = Math.max(target.health - damage, 0) + + text += `\n[Character AC: ${target.ac} Attack roll: ${attack}]\n` + + text += `${activeCharacterName} casts spell ${spell} at ${targetNameAdjustedCase} for ${damage} damage!` + + if (target.health == 0) text += ` ${toTitleCase(target.name)} ${areWord} unconscious!\n` + else text += ` ${toTitleCase(target.name)} ${areWord} at ${target.health} health.\n` + } else text += `${activeCharacterName} casts spell ${spell} at ${targetNameAdjustedCase} but misses!\n` + } + } + return text + } +} + function createEncounter(listName) { var encounter = { text: "", diff --git a/Output.js b/Output.js index 27de7bc..4e70781 100644 --- a/Output.js +++ b/Output.js @@ -475,6 +475,8 @@ const modifier = (text) => { text += "\n Assigns initiative to all characters and enemies. This begins combat." text += "\n#turn" text += "\n Updates the turn to the next character in combat. If it is an enemy, the enemy will attack. If it's a player character, the system will allow the player to take their turn. If there are no enemies left or all the player characters are dead, combat ends." + text += "\n#repeatTurn" + text += "\n Repeats the turn. If it is currently an enemy's turn, it will attack or cast another spell again." text += "\n#block" text += "\n Reverses the damage that has been inflicted in the last turn. This applies to damage on characters and enemies." text += "\n#flee (difficulty_class or automatic|effortless|easy|medium|hard|impossible)"