Skip to content

Commit

Permalink
Merge pull request #118 from ebshimizu/dev
Browse files Browse the repository at this point in the history
2.2.7
  • Loading branch information
ebshimizu authored Oct 11, 2023
2 parents 838fafe + 8f9f300 commit bc835c0
Show file tree
Hide file tree
Showing 20 changed files with 1,314 additions and 4,734 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ There are also some special tokens that can be used anywhere:
- {NAME} for the monster's name
- {#d#} for computing a dice roll (e.g. {3d6})
- {DC:STAT} for computing a Save DC based on the given stat. Stat must be one of: STR, DEX, CON, INT, WIS, CHA
- {XP:[cr]} for displaying the XP of a monster with given CR (e.g. {XP:1/2} renders to 100 XP). You can put a + at the end to declare the total as additive to the monster's listed CR. These tokens mostly exist to automate part of the Mythic Actions preamble.

### Calculating CR

Expand Down
5,334 changes: 612 additions & 4,722 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "5e-monster-maker",
"version": "2.2.6",
"version": "2.2.7",
"description": "A monster builder and generator for 5th Edition Dungeons and Dragons. Effortlessly create a monster with tools for automatically computing CR, formatting a statblock, and managing your monster actions and traits.",
"productName": "Falindrith's D&D Monster Maker",
"author": "Evan Shimizu <[email protected]>",
Expand Down
38 changes: 38 additions & 0 deletions src/components/ChangelogContent.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
<template>
<q-timeline color="secondary">
<q-timeline-entry
title="v2.2.7"
subtitle="Minor Update - 10/10/23"
icon="update"
color="primary"
>
<div class="text-body2">
<ul>
<li>
<github-issue-link :issue="111" /> Added an inventory field in case
you want to write down what additional items or loot your monster
has. Note that the values written in this field do not affect the
monster's actual stats.
</li>
<li>
<github-issue-link :issue="115" /> Added XP tokens to better support
the Mythic Actions preamble. You can now type {XP:[cr]} to render
the XP corresponding to the listed CR. Adding a + at the end adds
the specified XP total to the monster's listed CR XP. See the new
default Mythic Actions preamble to see the tokens in action.
</li>
<li>
<github-issue-link :issue="116" /> The renderer no longer displays
the die or bonus if you are using 0 dice or a d1 to compute flat
damage.
</li>
<li>
<github-issue-link :issue="117" /> Bugfix: fixes a crash caused by
setting the monster's CR to undefined (really, this should be
disallowed by Quasar but you can apparently make any dropdown null
by hitting backspace).
</li>
<li>
Dev chores: updated packages, tightened some typescript typedefs.
</li>
</ul>
</div>
</q-timeline-entry>
<q-timeline-entry
title="v2.2.6"
subtitle="Bugfix - 7/10/23"
Expand Down
8 changes: 7 additions & 1 deletion src/components/editor/BasicsEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@
emit-value
:label="$t('monster.cr')"
class="col-2 q-pa-sm"
@update:model-value="monster.setCR"
@update:model-value="(value: number | undefined) => {
if (value != null) {
monster.setCR(value)
} else {
monster.setCR(0)
}
}"
>
<template #after>
<lock-toggle-button
Expand Down
31 changes: 31 additions & 0 deletions src/components/editor/InventoryEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import { useMonsterStore } from 'src/stores/monster-store'
import MonsterTextEditor from './MonsterTextEditor.vue'
const monster = useMonsterStore()
</script>

<template>
<q-expansion-item
expand-separator
icon="luggage"
:label="$t('editor.inventory.label')"
>
<q-card>
<q-card-section class="row">
<div class="col-12 flex justify-start items-center">
{{ $t('editor.inventory.help') }}
</div>
<div class="col-12 q-pa-sm">
<monster-text-editor
:field="monster.inventory"
i18n-label-key="editor.inventory.label"
:show-reset="true"
@update:model-value="(value: string) => monster.inventory = value"
@reset="monster.inventory = ''"
/>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
</template>
4 changes: 2 additions & 2 deletions src/components/file/importers/useOpen5eImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
saveModifierForStat,
statModifier,
} from 'src/components/rendering/mathRendering'
import { getCrByString } from 'src/data/CR'
import { CR, getCrByString } from 'src/data/CR'
import { SKILL } from 'src/data/SKILL'
import { useMonsterStore } from 'src/stores/monster-store'
import { v4 } from 'uuid'
Expand Down Expand Up @@ -643,7 +643,7 @@ export function useOpen5eImport() {
monster.languages = data.languages

// challenge rating
const cr = getCrByString(data.challenge_rating)
const cr = getCrByString(data.challenge_rating) ?? CR[0]
monster.CR = cr.index
monster.proficiency = cr.proficiency

Expand Down
6 changes: 6 additions & 0 deletions src/components/file/useFileLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,12 @@ export function useFileLoader() {
monster.saveVersion = 7
}

// version 8 adds a notes field for the monster's inventory
if (monster.saveVersion < 8) {
monster.inventory = ''
monster.saveVersion = 8
}

// adjust saves in the attack field. null is ok but let's make it 0
for (const attack of monster.attacks) {
if (attack.save === null) attack.save = 0
Expand Down
1 change: 1 addition & 0 deletions src/components/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ export interface Monster {
lairActions: LairAction[]
regionalEffects: { id: string; description: string }[]
regionalEffectDescription: string
inventory: string
autoEstimateDefenseCr: boolean
}

Expand Down
9 changes: 9 additions & 0 deletions src/components/rendering/WebRenderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@
></li>
</ul>
</div>
<div v-if="monster.inventory !== ''" class="inventory">
<h3 class="section">{{ $t('editor.inventory.label') }}</h3>
<div v-html="inventory"></div>
</div>
</div>
</template>

Expand Down Expand Up @@ -306,6 +310,10 @@ export default defineComponent({
const cr = computed(() => sanitizeWebString(textRenderer.cr.value))
const inventory = computed(() =>
sanitizeWebString(textRenderer.inventory.value)
)
return {
monster,
...textRenderer,
Expand All @@ -328,6 +336,7 @@ export default defineComponent({
regionalEffectPreamble,
regionalEffects,
columns,
inventory,
}
},
})
Expand Down
11 changes: 10 additions & 1 deletion src/components/rendering/useHomebrewery3Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ ${renderer.regionalEffectPreamble.value}`
return `\n${preamble}\n${formattedEffects.join('\n')}`
}

const getInventory = () => {
if (monster.inventory === '') return ''

return `\n### ${t('editor.inventory.label')}\n${mdFormatter(
renderer.inventory.value
)}`
}

// formatted for the Homebrewery system, version 3
// https://homebrewery.naturalcrit.com/
const renderMarkdownV3 = (twoCol = false) => {
Expand Down Expand Up @@ -200,6 +208,7 @@ ${renderer.regionalEffectPreamble.value}`
const reactions = getReactions()
const lair = getLairActions()
const regional = getRegionalEffects()
const inventory = getInventory()

return `{{monster,frame${twoCol ? ',wide' : ''}
## ${monster.name}
Expand Down Expand Up @@ -234,7 +243,7 @@ ${traits}${mythicTrait}### ${t(
monster.spellcasting.standard.length === 0 ? '' : `${spellcasting}`
}${
monster.spellcasting.atWill.length === 0 ? '' : `${innate}`
}${bonusActions}${legendary}${mythic}${reactions}${lair}${regional}
}${bonusActions}${legendary}${mythic}${reactions}${lair}${regional}${inventory}
}}`
}

Expand Down
8 changes: 8 additions & 0 deletions src/components/rendering/useLatexRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ ${latexFormatter(renderer.lairActionPreamble.value)}`
\\end{itemize}`
}

const getInventory = () => {
return `\\DndMonsterSection{${t(
'editor.inventory.label'
)}}\n${latexFormatter(renderer.inventory.value)}`
}

// exporter for the rpgtex template
// https://github.com/rpgtex/DND-5e-LaTeX-Template
// notes:
Expand Down Expand Up @@ -383,6 +389,8 @@ ${latexFormatter(renderer.lairActionPreamble.value)}`
${monster.regionalEffects.length > 0 ? getRegionalEffects() : ''}
${monster.inventory !== '' ? getInventory() : ''}
${twoCol ? '\\end{multicols}' : ''}
\\end{DndMonster}`
}
Expand Down
13 changes: 12 additions & 1 deletion src/components/rendering/useMdRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ ${formattedActions.join('\n>\n')}\n>`
return `\n${preamble}\n${formattedEffects.join('\n')}`
}

const getInventory = () => {
if (monster.inventory === '') return ''

const inventory = `> ### ${t('editor.inventory.label')}\n> ${mdFormatter(
renderer.inventory.value
)}`

return inventory
}

// formatted for the Homebrewery system
// https://homebrewery.naturalcrit.com/
const renderMarkdown = (twoCol = false) => {
Expand Down Expand Up @@ -215,6 +225,7 @@ ${formattedActions.join('\n>\n')}\n>`
const reactions = getReactions()
const lair = getLairActions()
const regional = getRegionalEffects()
const inventory = getInventory()

return `___${twoCol ? '\n___' : ''}
> ## ${monster.name}
Expand Down Expand Up @@ -248,7 +259,7 @@ ${traits}${mythicTrait}> ### ${t(
monster.spellcasting.standard.length === 0 ? '' : `${spellcasting}\n>`
}${
monster.spellcasting.atWill.length === 0 ? '' : `${innate}\n>`
}${bonusActions}${legendary}${mythic}${reactions}${lair}${regional}`
}${bonusActions}${legendary}${mythic}${reactions}${lair}${regional}${inventory}`
}

return {
Expand Down
35 changes: 34 additions & 1 deletion src/components/rendering/useProcessTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import _ from 'lodash'
import { useI18n } from 'vue-i18n'
import N2W from 'number-to-words'
import { useClasses } from 'src/data/CLASS'
import { getCrByNumber, getCrByString } from 'src/data/CR'

export type MonsterContext =
| MonsterTrait
Expand Down Expand Up @@ -61,7 +62,16 @@ export function useProcessTokens() {
input = input.replace(dice, (match, count, dice, modifier) => {
const cleanModifier =
modifier && modifier !== '' ? parseInt(modifier.replace(' ', '')) : 0
const avg = avgRoll(parseInt(count), parseInt(dice)) + cleanModifier

const diceVal = parseInt(dice)
const countVal = parseInt(count)

const avg = avgRoll(countVal, diceVal) + cleanModifier

if (diceVal === 1 || countVal === 0) {
return `${avg}`
}

return `${avg} (${count}d${dice}${
modifier ? renderBonus(cleanModifier) : ''
})`
Expand Down Expand Up @@ -96,6 +106,29 @@ export function useProcessTokens() {
match.replace('the', 'The')
)

// XP rendering
const xp = RegExp(/\{XP:([\d/]+|monster)(\+)?\}/gi)
input = input.replace(xp, (match, cr, additive) => {
// change lookup based on token used
const crData =
cr.toLowerCase() === 'monster'
? getCrByNumber(monster.CR)
: getCrByString(cr)

if (crData) {
if (additive != null) {
// add xp to the monster's cr
const monsterCr = getCrByNumber(monster.CR)

return `${(crData.xp + monsterCr.xp).toLocaleString()} XP`
} else {
return `${crData.xp.toLocaleString()} XP`
}
} else {
return match
}
})

// generic tokens
const generic = RegExp(/\{monster.([\w\d\[\].]+)}/gi)
input = input.replace(generic, (match, prop) => {
Expand Down
7 changes: 6 additions & 1 deletion src/components/rendering/useTextRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export function useTextRenderer() {

nonZero.push({
name: 'Passive Perception',
value: monster.computedPassivePerception,
value: monster.computedPassivePerception ?? 0,
})

const senses = nonZero.map(
Expand Down Expand Up @@ -267,6 +267,10 @@ export function useTextRenderer() {
)
)

const inventory = computed(() =>
processTokens(monster.inventory, undefined, monster, 'none')
)

return {
stats,
hp,
Expand Down Expand Up @@ -299,5 +303,6 @@ export function useTextRenderer() {
lairActions,
regionalEffectPreamble,
regionalEffects,
inventory,
}
}
7 changes: 5 additions & 2 deletions src/data/CR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,10 @@ export const CR_SELECT = CR.map((cr, idx) => {
})

// the cr retrieval functions are a disaster let's fix that
function getCrByRange(value: number, field: keyof typeof rawCR[number]) {
function getCrByRange(
value: number,
field: Exclude<keyof (typeof rawCR)[number], 'cr'>
) {
// check if the value is between index.field and index + 1.field
for (let i = 0; i < CR.length - 1; i++) {
if (CR[i][field] <= value && value < CR[i + 1][field]) {
Expand All @@ -468,7 +471,7 @@ function getCrByRange(value: number, field: keyof typeof rawCR[number]) {
export function getCrByString(crString: string) {
const maybeCr = CR.find((cr) => cr.cr === crString)

return maybeCr ?? CR[0]
return maybeCr
}

export function getCrByDamage(damage: number) {
Expand Down
Loading

0 comments on commit bc835c0

Please sign in to comment.