Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

Commit

Permalink
feat: uses charna for sheets
Browse files Browse the repository at this point in the history
  • Loading branch information
villetakanen committed Nov 30, 2021
1 parent 6d56bc2 commit 0462745
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 173 deletions.
36 changes: 36 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@vuelidate/validators": "^2.0.0-alpha.21",
"algoliasearch": "^4.10.5",
"axios": "^0.21.4",
"charna": "^0.1.2",
"downscale": "^1.0.6",
"firebase": "^9.0.2",
"luxon": "^2.0.2",
Expand Down
22 changes: 6 additions & 16 deletions src/components/character/CharacterSheet.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
<template>
<div class="CharacterSheet">
<div
v-for="(block, blockIndex) in character.sheet.layout"
:key="blockIndex"
v-for="key in character.statKeys()"
:key="key"
>
<div
v-for="(row, rowIndex) in block"
:key="rowIndex"
>
<template
v-for="stat in row"
:key="stat"
>
<CharacterStat
:character="character"
:stat="stat"
/>
</template>
</div>
<CharacterStat
:character="character"
:stat="key"
/>
</div>
</div>
</template>
Expand Down
8 changes: 4 additions & 4 deletions src/components/character/CharacterStat.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div vlass="CharacterStat">
<template v-if="type === 'rich-text'">
<template v-if="type === 'string'">
<RichTextEditor v-model:content="editableStat" />
</template>
<template v-else>
Expand Down Expand Up @@ -35,12 +35,12 @@ export default defineComponent({
},
setup (props) {
const { showAdminTools } = useAuth()
const type = computed(() => props.character.getStatType(props.stat))
const type = computed(() => props.character.getStat(props.stat)?.type || 'number')
const editableStat = computed({
get: () => props.character.getStat(props.stat),
get: () => props.character.getStat(props.stat)?.value,
set: (value) => {
props.character.setStat(props.stat, value)
props.character.setStat(props.stat, value || 0)
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/components/keeper/CharacterList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export default defineComponent({
if (characters.value.size > 0) {
const [first] = characters.value.values()
logDebug('CharacterList.vue', 'setup', 'first', first)
return Array.from(first.stats.keys())
return first.statKeys()
}
return []
})
Expand Down
122 changes: 15 additions & 107 deletions src/state/characters/Character.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { logDebug } from '@/utils/eventLogger'
import { DocumentData } from '@firebase/firestore'
import { create, all } from 'mathjs'
import ddCharSheet from './ddCharSheet.json'
import basicCharacterSheet from './basicCharacterSheet.json'
import { CharacterSheet } from 'charna/lib/CharacterSheet'
import { SheetModel } from 'charna/lib/models/SheetModel'
import { logDebug } from '@/utils/eventLogger'

export interface CharacterStatModel {
label?: {
Expand All @@ -14,140 +15,47 @@ export interface CharacterStatModel {
formula?: string
}
export interface CharacterStat {
[key: string]: number|string|boolean
}

export interface CharacterSheetModel {
layout: Array<Array<Array<string>>>
stats: {
[key: string]: CharacterStatModel
}
[key: string]: number|string
}

export const CHARACTER_SHEET_TYPES:{ [key: string]: CharacterSheetModel } = {
export const CHARACTER_SHEET_TYPES:{ [key: string]: SheetModel } = {
default: basicCharacterSheet,
dd: ddCharSheet
}

export class Character {
readonly id: string
export class Character extends CharacterSheet {
public player: string|undefined
public name: string
public htmlDescription: string
public site: string|undefined
public sheet: CharacterSheetModel = CHARACTER_SHEET_TYPES.default
public stats: Map<string, number>
private math = create(all)
public characterSheetType: string
public avatarURL: string|undefined

constructor (id?: string, data?:DocumentData) {
this.id = id || ''
logDebug('Character.constructor', id, data)
super(id || '')
this.player = data?.player || undefined
this.name = data?.name || 'N.N.'
this.htmlDescription = data?.htmlDescription || ''
this.site = data?.site || undefined
this.stats = Character.parseStats(data?.stats || {})
this.characterSheetType = data?.characterSheetType || 'default'
if (data?.characterSheetType) {
this.applyCharacterSheet(data?.characterSheetType as string)
}
this.avatarURL = data?.avatarURL || undefined
this.model = CHARACTER_SHEET_TYPES[this.characterSheetType] || basicCharacterSheet
this.ingestStats(data?.stats || {})
}

private static parseStats (stats:{ [key: string]: number }): Map<string, number> {
const result = new Map<string, number>()
for (const [key, value] of Object.entries(stats)) {
result.set(key, value)
}
return result
}

public applyCharacterSheet (characterSheet: string): void {
if (!Object.keys(CHARACTER_SHEET_TYPES).includes(characterSheet)) {
logDebug('Unknown character sheet type', characterSheet)
this.sheet = CHARACTER_SHEET_TYPES.default
return
}
this.sheet = CHARACTER_SHEET_TYPES[characterSheet]
}

public getStat (stat: string): number {
if (!this.stats.has(stat)) {
logDebug('Trying to get a stat that´s not defined', stat)
return 0
}
return this.stats.get(stat) || 0
}

public getStatLabel (stat: string, code: string): string {
// logDebug('getStatLabel', stat, code, this.sheet?.stats[stat])
if (!this.sheet) {
return stat
}
const statModel = this.sheet.stats[stat]
if (!statModel) {
return stat
}
if (!statModel.label) return stat
return statModel.label[code] || statModel.label.en || stat
}

public getStatType (stat: string): string {
if (!this.sheet) {
return 'string'
}
return this.sheet.stats[stat]?.type || 'string'
}

public setStat (stat: string, value: number): void {
this.stats.set(stat, value)
}

public deriveStat (stat: string): number {
if (!this.sheet) {
return 0
}

// A primary stat, not derived
if (this.stats.has(stat)) {
return this.stats.get(stat) || 0
}

const statModel = this.sheet.stats[stat]
// We do not have a model for this stat, return 0
if (!statModel) {
return 0
}

// We have a model, but no formula, return 0
if (!statModel.formula) {
return 0
}

const parser = this.math.parser()
// We have a formula, let's try to evaluate it
statModel.formula.split(' ').forEach(v => {
// logDebug('Parsing', v, this?.sheet?.stats[v]?.type)
if (this?.sheet?.stats[v]?.type === 'number') parser.set(v, this.getStat(v) || 0)
ingestStats (stats: { [key: string]: number|string }): void {
Object.keys(stats).forEach(k => {
logDebug('Character.ingestStats', k, stats[k])
this.setStat(k, stats[k])
})
// logDebug('Composite stats', parser.getAll(), statModel.formula)
const result = parser.evaluate(statModel.formula) || 0

// logDebug('deriveStat', result, statModel.formula)

return Math.floor(result)
}

public dryCopy (): { [x: string]: string|CharacterStat } {
const dry: { [x: string]: undefined|string|CharacterStat } = {
id: this.id,
...this.toJSON(),
name: this.name,
htmlDescription: this.htmlDescription,
site: this.site,
characterSheetType: this.characterSheetType,
player: this.player,
stats: Object.fromEntries(this.stats.entries()) as { [key: string]: number|string|boolean },
avatarURL: this.avatarURL
}
Object.keys(dry).forEach(k => dry[k] === undefined ? delete dry[k] : null)
Expand Down
13 changes: 3 additions & 10 deletions src/state/characters/basicCharacterSheet.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
{
"layout": [
[
["description"]
]
],
"id": "Basic Charactersheet",
"stats": {
"description": {
"type": "rich-text",
"label": {
"en": "Description",
"fi": "Kuvaus"
}
"type": "string",
"initialValue": "..."
}
}
}
42 changes: 7 additions & 35 deletions src/state/characters/ddCharSheet.json
Original file line number Diff line number Diff line change
@@ -1,56 +1,28 @@
{
"layout": [[
["strength", "strength bonus"],
["dexterity", "dexterity bonus"],
["constitution", "constitution bonus"],
["intelligence", "intelligence bonus"],
["wisdom", "wisdom bonus"],
["charisma", "charisma bonus"]
]],
"id": "D&D 5th edition sheet redacted variant",
"stats": {
"strength": {
"type": "number",
"label": {
"en": "Strenght",
"fi": "Voimakkuus"
}
"initialValue": 10
},
"dexterity": {
"type": "number",
"label": {
"en": "Dexterity",
"fi": "Ketteryys"
}
"initialValue": 10
},
"constitution": {
"type": "number",
"label": {
"en": "Constitution",
"fi": "Vahvuus"
}
"initialValue": 10
},
"strength bonus": {
"type": "derived",
"label": {
"en": "Strenght bonus",
"fi": "Voimakkuus -bonus"
},
"type": "composite",
"formula": "( strength - 10 ) / 2"
},
"dexterity bonus": {
"type": "derived",
"label": {
"en": "Dexterity bonus",
"fi": "Ketteryys -bonus"
},
"type": "composite",
"formula": "( dexterity - 10 ) / 2"
},
"constitution bonus": {
"type": "derived",
"label": {
"en": "Constitution bonus",
"fi": "Vahvuus -bonus"
},
"type": "composite",
"formula": "( constitution - 10 ) / 2"
}
}
Expand Down

0 comments on commit 0462745

Please sign in to comment.