1
0
Fork 0
mirror of https://github.com/em-squared/5e-drs.git synced 2025-10-30 13:14:20 +00:00

outils de création de sorts/monstres/objets

This commit is contained in:
Maxime Moraine 2020-04-22 11:17:05 +02:00
parent 6237f0e6a2
commit a6986c42c6
48 changed files with 2743 additions and 259 deletions

View file

@ -0,0 +1,231 @@
<template>
<div class="create-magic-item">
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/mes-objets-magiques/">Mes objets magiques</v-btn>
<v-btn color="primary" depressed link to="/liste-objets-magiques/">Liste des objets magiques</v-btn>
</div>
<h1 class="d-print-none">Création de sort</h1>
<div class="my-4 d-flex flex-wrap d-print-none">
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="print"><v-icon>mdi-printer</v-icon> Imprimer</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="download"><v-icon>mdi-file-download</v-icon> Sauvegarder</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed :loading="isUploading" @click="onUploadClick">
<v-icon left>mdi-file-upload</v-icon> Charger
</v-btn>
<input ref="uploader" class="d-none" type="file" @change="upload">
<v-btn :outlined="!isMagicItemInTreasureChest" color="accent" class="mr-1 mb-1" depressed @click="toggleMagicItemInTreasureChest"><v-icon>mdi-book</v-icon> {{ displayToggleMagicItemButton }}</v-btn>
<v-btn :disabled="!isMagicItemInTreasureChest" outlined color="accent" class="mr-1 mb-1" depressed @click="updateMagicItemInTreasureChest"><v-icon>mdi-update</v-icon> MàJ dans le grimoire</v-btn>
<v-btn outlined color="error" class="mb-1" depressed @click="reset"><v-icon>mdi-eraser</v-icon> Réinitialiser</v-btn>
</div>
<v-row>
<v-col class="d-print-none" :col="6">
<v-row>
<v-col>
<v-text-field label="Nom" outlined dense v-model="magicItem.title"></v-text-field>
</v-col>
<v-col>
<v-select :items="types" label="Type" outlined dense v-model="magicItem.frontmatter.type"></v-select>
</v-col>
<v-col>
<v-select :items="rarities" label="Rareté" outlined dense v-model="magicItem.frontmatter.rarity"></v-select>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field label="Sous-type" outlined dense v-model="magicItem.frontmatter.subtype"></v-text-field>
</v-col>
<v-col>
<v-switch class="my-0" v-model="magicItem.hasAttunement" label="Harmonisation" @change="switchAttunement" dense></v-switch>
</v-col>
<v-col v-if="magicItem.hasAttunement">
<v-text-field label="Type d'armonisation" outlined dense v-model="magicItem.frontmatter.attunement"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col>
<v-textarea outlined label="Description" v-model="magicItem.content"></v-textarea>
</v-col>
</v-row>
</v-col>
<v-col :col="6">
<MagicItem :magicItem="magicItem" />
</v-col>
</v-row>
</div>
</template>
<script>
import Breadcrumb from '@theme/components/Breadcrumb'
import MagicItem from '@theme/components/MagicItem'
import { saveAs } from 'file-saver'
import { MAGICITEMTYPES, RARITIES } from '../../data/magicItems'
import { getUrlParameter } from '@theme/util/filterHelpers'
export default {
name: 'CreateMagicItemLayout',
components: {
Breadcrumb,
MagicItem
},
computed: {
isMagicItemInTreasureChest () {
let isInTreasureChest = false
for (let s of this.$store.state.myMagicItems.magicItems) {
if (s.key == this.magicItem.key) {
isInTreasureChest = true
}
}
return isInTreasureChest
},
displayToggleMagicItemButton () {
if (this.isMagicItemInTreasureChest) {
return 'Supprimer de mes objets magiques'
}
return 'Ajouter à mes objets magiques'
},
displayAttunement () {
if (this.customAttunement !== "") {
return this.customAttunement
} else {
return 'harmonisation requise'
}
}
},
data () {
return {
isUploading: false,
types: MAGICITEMTYPES,
rarities: RARITIES,
customAttunement: '',
magicItem: {
custom: true,
pid: 'magicItem',
key: null,
title: '',
content: '',
hasAttunement: false,
frontmatter: {
type: '',
subtype: '',
rarity: '',
attunement: '',
}
}
}
},
methods: {
download () {
saveAs(new Blob([JSON.stringify(this.magicItem)], {
type: "text/plain;charset=utf-8"
}), "objet-magique.json")
},
upload (e) {
let file = e.target.files[0]
let reader = new FileReader()
let self = this
reader.onload = function() {
let result = JSON.parse(reader.result)
if (result.pid == 'magicItem') {
self.magicItem = result
}
}
reader.readAsText(file)
},
onUploadClick () {
this.isUploading = true
window.addEventListener('focus', () => {
this.isUploading = false
}, { once: true })
this.$refs.uploader.click()
},
print () {
window.print()
},
toggleMagicItemInTreasureChest () {
if (this.isMagicItemInTreasureChest) {
this.$store.commit('myMagicItems/removeMagicItem', this.magicItem)
} else {
this.$store.commit('myMagicItems/addMagicItem', this.magicItem)
}
},
updateMagicItemInTreasureChest () {
if (this.isMagicItemInTreasureChest) {
this.$store.commit('myMagicItems/updateMagicItem', this.magicItem)
}
},
switchAttunement () {
if (this.magicItem.hasAttunement) {
this.magicItem.frontmatter.attunement = "harmonisation requise"
} else {
this.magicItem.frontmatter.attunement = ""
}
},
reset () {
this.customAttunement = '',
this.magicItem = {
custom: true,
pid: 'magicItem',
key: Math.random().toString(36).substr(2, 9),
title: '',
content: '',
hasAttunement: false,
frontmatter: {
type: '',
subtype: '',
rarity: '',
attunement: '',
}
}
}
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)
this.$store.commit('setInRightDrawer', null)
let magicItemKey = getUrlParameter(window.location.href, "key")
if (magicItemKey) {
for (let magicItem of this.$store.state.myMagicItems.magicItems) {
if (magicItem.key == magicItemKey) {
this.magicItem = magicItem
if (!this.magicItem.custom) {
this.magicItem.content = magicItem.rawContent
this.magicItem.custom = true
}
}
}
} else {
this.magicItem.key = Math.random().toString(36).substr(2, 9)
}
}
}
</script>
<style>
</style>

View file

@ -0,0 +1,402 @@
<template>
<div class="create-monster">
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/mon-bestiaire/">Mon Bestiaire</v-btn>
<v-btn color="primary" depressed link to="/bestiaire/">Bestiaire</v-btn>
</div>
<h1 class="d-print-none">Création de monstre/PNJ</h1>
<div class="my-4 d-flex flex-wrap d-print-none">
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="print"><v-icon>mdi-printer</v-icon> Imprimer</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="download"><v-icon>mdi-file-download</v-icon> Sauvegarder</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed :loading="isUploading" @click="onUploadClick">
<v-icon left>mdi-file-upload</v-icon> Charger
</v-btn>
<input ref="uploader" class="d-none" type="file" @change="upload">
<v-btn :outlined="!isMonsterInBestiary" color="accent" class="mr-1 mb-1" depressed @click="toggleMonsterInBestiary"><v-icon>mdi-book</v-icon> {{ displayToggleMonsterButton }}</v-btn>
<v-btn :disabled="!isMonsterInBestiary" outlined color="accent" class="mr-1 mb-1" depressed @click="updateMonsterInBestiary"><v-icon>mdi-update</v-icon> MàJ dans le bestiaire</v-btn>
<v-btn outlined color="error" class="mb-1" depressed @click="reset"><v-icon>mdi-eraser</v-icon> Réinitialiser</v-btn>
</div>
<v-row>
<v-col class="d-print-none" :col="6">
<v-row>
<v-col>
<v-text-field label="Nom" placeholder="Elfe noir" outlined dense v-model="monster.title"></v-text-field>
</v-col>
<v-col>
<v-select :items="sizes" item-text="label" item-value="abbr" label="Taille" outlined dense v-model="monster.frontmatter.size" @change="selectMonsterSize"></v-select>
</v-col>
<v-col>
<v-select :items="challenges" item-text="label" item-value="value" label="Dangerosité" persistent-hint :hint="challengeHint" outlined dense v-model="monster.frontmatter.challenge"></v-select>
</v-col>
</v-row>
<v-row>
<v-col>
<v-select :items="monsterTypes" label="Type" outlined dense v-model="monster.frontmatter.type"></v-select>
</v-col>
<v-col>
<v-text-field label="Sous-type" outlined dense v-model="monster.frontmatter.subtype"></v-text-field>
</v-col>
<v-col>
<v-text-field label="Alignement" placeholder="Chaotique mauvais" outlined dense v-model="monster.frontmatter.alignment"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex justify-space-between">
<v-switch :disabled="!monster.frontmatter.type" class="my-0 mr-4" v-model="monster.frontmatter.isSwarm" label="Nuée" dense @change="switchIsSwarm"></v-switch>
<v-select :disabled="!monster.frontmatter.isSwarm" :items="sizes" item-text="label" item-value="abbr" label="Taille des créatures" outlined dense v-model="monster.frontmatter.swarmSize"></v-select>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center">
<v-text-field class="mr-1" label="Force" type="number" min="1" outlined dense v-model="monster.frontmatter.abilityScores.for"></v-text-field>
<v-text-field class="mr-1" label="Dextérité" type="number" min="1" outlined dense v-model="monster.frontmatter.abilityScores.dex"></v-text-field>
<v-text-field class="mr-1" label="Constitution" type="number" min="1" outlined dense v-model="monster.frontmatter.abilityScores.con"></v-text-field>
<v-text-field class="mr-1" label="Intelligence" type="number" min="1" outlined dense v-model="monster.frontmatter.abilityScores.int"></v-text-field>
<v-text-field class="mr-1" label="Sagesse" type="number" min="1" outlined dense v-model="monster.frontmatter.abilityScores.sag"></v-text-field>
<v-text-field class="mr-0" label="Charisme" type="number" min="1" outlined dense v-model="monster.frontmatter.abilityScores.cha"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center">
<v-text-field label="Dés de vie" type="number" min="1" outlined dense v-model="monster.frontmatter.hitDiceCount"></v-text-field>
<v-switch class="my-0 mx-1" v-model="customHitDieSize" label="Dé de vie personnalisé" dense @change="switchCustomHitDizeSize"></v-switch>
<v-select :disabled="!customHitDieSize" :items="sizes" item-text="hitDie" item-value="hitDie" label="Taille du dé de vie" outlined dense v-model="monster.frontmatter.hitDieSize"></v-select>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center">
<v-select class="mr-1" :items="armorTypes" item-text="label" item-value="value" label="Type d'armure" outlined dense v-model="monster.frontmatter.ac.armorType" @change="selectArmorType"></v-select>
<v-text-field v-if="monster.frontmatter.ac.armorType == 'armure naturelle'" label="Armure naturelle" type="number" min="0" outlined dense v-model="monster.frontmatter.ac.value"></v-text-field>
<v-text-field v-if="monster.frontmatter.ac.armorType == 'custom'" label="Armure personnalisée" outlined dense v-model="monster.frontmatter.ac.value"></v-text-field>
<v-switch class="my-0 ml-1" v-if="monster.frontmatter.ac.armorType != 'custom'" v-model="monster.frontmatter.ac.hasShield" label="Bouclier" dense></v-switch>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center">
<v-select class="mr-1" multiple clearable :items="abilities" item-text="label" item-value="value" label="Jets de sauvegarde" outlined dense v-model="monster.frontmatter.savingThrows"></v-select>
<v-select class="mr-1" multiple clearable return-object :items="skills" item-text="label" item-value="value" label="Compétences" outlined dense v-model="selectedSkillsProficient" @change="selectSkill"></v-select>
<v-select class="mr-1" multiple clearable :items="selectedSkillsProficient" item-text="label" item-value="value" label="Compétences expert" outlined dense v-model="selectedSkillsExpert" @change="selectSkillExpert"></v-select>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center flex-wrap">
<v-select class="mr-1" multiple clearable :items="conditions" label="Immunité états spéciaux" outlined dense v-model="monster.frontmatter.conditionImmunities"></v-select>
<v-select class="mr-1" multiple clearable :items="damageTypes" label="Vulnérabilité au dégâts" outlined dense v-model="monster.frontmatter.damageTypeVulnerabilities"></v-select>
<v-select class="mr-1" multiple clearable :items="damageTypes" label="Résistance au dégâts" outlined dense v-model="monster.frontmatter.damageTypeResistances"></v-select>
<v-select class="mr-1" multiple clearable :items="damageTypes" label="Immunité au dégâts" outlined dense v-model="monster.frontmatter.damageTypeImmunities"></v-select>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center">
<v-text-field class="mr-1" label="Au sol" type="number" min="0" outlined dense v-model="monster.frontmatter.movement.walk"></v-text-field>
<v-text-field class="mr-1" label="Escalade" type="number" min="0" outlined dense v-model="monster.frontmatter.movement.climb"></v-text-field>
<v-text-field class="mr-1" label="Fouissement" type="number" min="0" outlined dense v-model="monster.frontmatter.movement.burrow"></v-text-field>
<v-text-field class="mr-1" label="Nage" type="number" min="0" outlined dense v-model="monster.frontmatter.movement.swim"></v-text-field>
<v-text-field class="mr-1" label="Vol" type="number" min="0" outlined dense v-model="monster.frontmatter.movement.fly"></v-text-field>
<v-switch class="my-0" v-model="monster.frontmatter.movement.hover" label="Vol stationnaire" dense></v-switch>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center">
<v-text-field class="mr-1" label="Perception des vibrations" type="number" min="0" outlined dense v-model="monster.frontmatter.senses.tremorsense"></v-text-field>
<v-text-field class="mr-1" label="Vision aveugle" type="number" min="0" outlined dense v-model="monster.frontmatter.senses.blindsight"></v-text-field>
<v-text-field class="mr-1" label="Vision dans le noir" type="number" min="0" outlined dense v-model="monster.frontmatter.senses.darkvision"></v-text-field>
<v-text-field class="mr-0" label="Vision parfaite" type="number" min="0" outlined dense v-model="monster.frontmatter.senses.truesight"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col class="d-flex align-center">
<v-select class="mr-1" multiple clearable :items="languages" label="Langues" outlined dense v-model="monster.frontmatter.languages"></v-select>
<v-text-field class="mr-1" label="Langue personnalisée" outlined dense v-model="monster.frontmatter.customLanguage"></v-text-field>
<v-text-field label="Télépathie" type="number" min="0" outlined dense v-model="monster.frontmatter.telepathy"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col>
<v-textarea outlined label="Capacités, Actions, Réactions, Actions légendaires" v-model="monster.content"></v-textarea>
</v-col>
</v-row>
</v-col>
<v-col :col="6">
<Monster :monster="monster" />
</v-col>
</v-row>
</div>
</template>
<script>
import Breadcrumb from '@theme/components/Breadcrumb'
import Monster from '@theme/components/Monster'
import { saveAs } from 'file-saver'
import { MONSTERTYPES, MONSTERSIZES, CHALLENGES, ABILITIES, SKILLS } from '../../data/monsters'
import { stats } from '../../data/stats'
import { ARMORTYPES } from '../../data/armorTypes'
import { CONDITIONS } from '../../data/conditions'
import { DAMAGETYPES } from '../../data/damageTypes'
import { LANGUAGES } from '../../data/languages'
import { getUrlParameter } from '@theme/util/filterHelpers'
import { getProficiencyBonus, displayBonus } from '@theme/util/monsterHelpers'
export default {
name: 'CreateMonsterLayout',
components: {
Breadcrumb,
Monster
},
computed: {
isMonsterInBestiary () {
let isInBestiary = false
for (let s of this.$store.state.myMonsters.monsters) {
if (s.key == this.monster.key) {
isInBestiary = true
}
}
return isInBestiary
},
displayToggleMonsterButton () {
if (this.isMonsterInBestiary) {
return 'Supprimer de mon bestiaire'
}
return 'Ajouter à mon bestiaire'
},
challengeHint () {
return 'Bonus de maîtrise : ' + displayBonus(getProficiencyBonus(this.monster.frontmatter.challenge))
},
},
data () {
return {
isUploading: false,
monsterTypes: MONSTERTYPES,
sizes: MONSTERSIZES,
armorTypes: ARMORTYPES,
abilities: ABILITIES,
skills: SKILLS,
skillObjects: stats.skills,
conditions: CONDITIONS,
damageTypes: DAMAGETYPES,
challenges: CHALLENGES,
languages: LANGUAGES,
customHitDieSize: false,
selectedSkillsProficient: [],
selectedSkillsExpert: [],
monster: {
custom: true,
pid: 'monster',
key: null,
title: '',
content: '',
frontmatter: {
type: '',
subtype: '',
size: '',
challenge: '0',
alignment: '',
isSwarm: false,
swarmSize: '',
hitDiceCount: 1,
hitDieSize: '',
abilityScores: {
for: 10,
dex: 10,
con: 10,
int: 10,
sag: 10,
cha: 10,
},
ac: {
armorType: null,
value: null, // Dans le cas du type d'armure "Armure naturelle"
hasShield: false,
},
savingThrow: null,
skills: null,
movement: {
walk: '',
climb: '',
burrow: '',
swim: '',
fly: '',
hover: false,
},
senses: {
tremorsense: '',
blindsight: '',
darkvision: '',
truesight: '',
},
conditionImmunities: [],
damageTypeVulnerabilities: [],
damageTypeResistances: [],
damageTypeImmunities: [],
languages: [],
customLanguage: '',
telepathy: null
}
}
}
},
methods: {
download () {
saveAs(new Blob([JSON.stringify(this.monster)], {
type: "text/plain;charset=utf-8"
}), "monstre.json")
},
upload (e) {
let file = e.target.files[0]
let reader = new FileReader()
let self = this
reader.onload = function() {
let result = JSON.parse(reader.result)
if (result.pid == 'monster') {
self.monster = result
}
}
reader.readAsText(file)
},
onUploadClick () {
this.isUploading = true
window.addEventListener('focus', () => {
this.isUploading = false
}, { once: true })
this.$refs.uploader.click()
},
print () {
window.print()
},
toggleMonsterInBestiary () {
if (this.isMonsterInBestiary) {
this.$store.commit('myMonsters/removeMonster', this.monster)
} else {
this.$store.commit('myMonsters/addMonster', this.monster)
}
},
updateMonsterInBestiary () {
if (this.isMonsterInBestiary) {
this.$store.commit('myMonsters/updateMonster', this.monster)
}
},
reset () {
this.monster = {
custom: true,
pid: 'monster',
key: Math.random().toString(36).substr(2, 9),
title: '',
content: '',
frontmatter: {
}
}
},
switchIsSwarm () {
if (!this.monster.frontmatter.isSwarm) {
this.monster.frontmatter.swarmSize = ''
}
},
selectMonsterSize (selected) {
},
switchCustomHitDizeSize () {
if (!this.customHitDieSize) {
this.monster.frontmatter.hitDieSize = ''
}
},
selectArmorType () {
if (this.monster.frontmatter.ac.armorType == 'armure naturelle' || this.monster.frontmatter.ac.armorType == 'custom') {
this.monster.frontmatter.ac.value = null
}
},
selectSkill () {
this.monster.frontmatter.skills = []
this.selectedSkillsProficient.forEach((skill, idx) => {
this.monster.frontmatter.skills.push({name: skill.value})
})
this.setSkillsExpert()
},
selectSkillExpert () {
this.selectSkill()
this.setSkillsExpert()
},
setSkillsExpert () {
this.monster.frontmatter.skills.forEach((mskill, idx) => {
this.monster.frontmatter.skills[idx].isExpert = this.selectedSkillsExpert.indexOf(mskill.name) >= 0
})
},
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)
this.$store.commit('setInRightDrawer', null)
let monsterKey = getUrlParameter(window.location.href, "key")
if (monsterKey) {
for (let monster of this.$store.state.myMonsters.monsters) {
if (monster.key == monsterKey) {
this.monster = monster
if (!this.monster.custom) {
this.monster.content = monster.rawContent
this.monster.custom = true
}
if (this.monster.frontmatter.skills) {
this.monster.frontmatter.skills.forEach((mskill, idx) => {
SKILLS.forEach((skill, jdx) => {
if (mskill.name == skill.value) {
this.selectedSkillsProficient.push(skill)
if (mskill.isExpert) {
this.selectedSkillsExpert.push(skill.value)
}
}
})
})
}
}
}
} else {
this.monster.key = Math.random().toString(36).substr(2, 9)
}
}
}
</script>
<style>
</style>

View file

@ -0,0 +1,276 @@
<template>
<div class="create-spell">
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/mon-grimoire/">Mon Grimoire</v-btn>
<v-btn color="primary" depressed link to="/grimoire/">Grimoire</v-btn>
</div>
<h1 class="d-print-none">Création de sort</h1>
<div class="my-4 d-flex flex-wrap d-print-none">
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="print"><v-icon>mdi-printer</v-icon> Imprimer</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="download"><v-icon>mdi-file-download</v-icon> Sauvegarder</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed :loading="isUploading" @click="onUploadClick">
<v-icon left>mdi-file-upload</v-icon> Charger
</v-btn>
<input ref="uploader" class="d-none" type="file" @change="upload">
<v-btn :outlined="!isSpellInSpellBook" color="accent" class="mr-1 mb-1" depressed @click="toggleSpellInSpellBook"><v-icon>mdi-book</v-icon> {{ displayToggleSpellButton }}</v-btn>
<v-btn :disabled="!isSpellInSpellBook" outlined color="accent" class="mr-1 mb-1" depressed @click="updateSpellInSpellBook"><v-icon>mdi-update</v-icon> MàJ dans le grimoire</v-btn>
<v-btn outlined color="error" class="mb-1" depressed @click="reset"><v-icon>mdi-eraser</v-icon> Réinitialiser</v-btn>
</div>
<v-row>
<v-col class="d-print-none" :col="6">
<v-row>
<v-col>
<v-text-field label="Nom" placeholder="Projectile magique" outlined dense v-model="spell.title"></v-text-field>
</v-col>
<v-col>
<v-select :items="schools" label="École" outlined dense v-model="spell.frontmatter.school"></v-select>
</v-col>
<v-col>
<v-select :items="levels" item-text="label" item-value="value" label="Niveau" outlined dense v-model="spell.frontmatter.level"></v-select>
</v-col>
<v-col>
<v-switch class="my-0" v-model="spell.frontmatter.ritual" label="Rituel" dense></v-switch>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field label="Temps d'incantation" placeholder="1 action" outlined dense v-model="spell.frontmatter.casting_time"></v-text-field>
</v-col>
<v-col>
<v-text-field label="Portée" placeholder="36 m" outlined dense v-model="spell.frontmatter.range"></v-text-field>
</v-col>
<v-col>
<v-text-field label="Duration" placeholder="instantanée" outlined dense v-model="spell.frontmatter.duration"></v-text-field>
</v-col>
<v-col>
<v-switch class="my-0" v-model="spell.frontmatter.concentration" label="Concentration" dense></v-switch>
</v-col>
</v-row>
<v-row>
<v-col>
<v-switch class="my-0" v-model="spell.frontmatter.components.verbal" label="Verbale" dense></v-switch>
</v-col>
<v-col>
<v-switch class="my-0" v-model="spell.frontmatter.components.somatic" label="Somatique" dense></v-switch>
</v-col>
<v-col>
<v-switch class="my-0" v-model="spell.frontmatter.components.material" label="Matérielle" dense></v-switch>
</v-col>
<v-col v-if="spell.frontmatter.components.material">
<v-text-field label="Composantes matérielles" outlined dense v-model="spell.frontmatter.components.materials"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col>
<v-select :items="classes" multiple clearable label="Disponible pour les classes de :" outlined dense v-model="spell.frontmatter.classes"></v-select>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field label="Classes personnalisées" placeholder="Forgesort" outlined dense v-model="spell.frontmatter.customClasses"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field outlined label="Résumé" v-model="spell.frontmatter.description"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col>
<v-textarea outlined label="Description" v-model="spell.content"></v-textarea>
</v-col>
</v-row>
</v-col>
<v-col :col="6">
<Spell :spell="spell" />
</v-col>
</v-row>
</div>
</template>
<script>
import Breadcrumb from '@theme/components/Breadcrumb'
import Spell from '@theme/components/Spell'
import { saveAs } from 'file-saver'
import { CLASSES } from '../../data/classes'
import { SPELLSCHOOLS, SPELLLEVELS } from '../../data/spells'
import { getUrlParameter } from '@theme/util/filterHelpers'
export default {
name: 'CreateSpellLayout',
components: {
Breadcrumb,
Spell
},
computed: {
isSpellInSpellBook () {
let isInSpellBook = false
for (let s of this.$store.state.mySpells.spells) {
if (s.key == this.spell.key) {
isInSpellBook = true
}
}
return isInSpellBook
},
displayToggleSpellButton () {
if (this.isSpellInSpellBook) {
return 'Supprimer de mon grimoire'
}
return 'Ajouter à mon grimoire'
}
},
data () {
return {
isUploading: false,
schools: SPELLSCHOOLS,
levels: SPELLLEVELS,
classes: CLASSES,
spell: {
custom: true,
pid: 'spell',
key: null,
title: '',
content: '',
frontmatter: {
description: '',
classes: '',
customClasses: '',
school: '',
level: '',
ritual: false,
casting_time: '',
range: '',
duration: '',
concentration: false,
components: {
verbal: false,
somatic: false,
material: false,
materials: null
}
}
}
}
},
methods: {
download () {
saveAs(new Blob([JSON.stringify(this.spell)], {
type: "text/plain;charset=utf-8"
}), "sort.json")
},
upload (e) {
let file = e.target.files[0]
let reader = new FileReader()
let self = this
reader.onload = function() {
let result = JSON.parse(reader.result)
if (result.pid == 'spell') {
self.spell = result
}
}
reader.readAsText(file)
},
onUploadClick () {
this.isUploading = true
window.addEventListener('focus', () => {
this.isUploading = false
}, { once: true })
this.$refs.uploader.click()
},
print () {
window.print()
},
toggleSpellInSpellBook () {
if (this.isSpellInSpellBook) {
this.$store.commit('mySpells/removeSpell', this.spell)
} else {
this.$store.commit('mySpells/addSpell', this.spell)
}
},
updateSpellInSpellBook () {
if (this.isSpellInSpellBook) {
this.$store.commit('mySpells/updateSpell', this.spell)
}
},
reset () {
this.spell = {
custom: true,
pid: 'spell',
key: Math.random().toString(36).substr(2, 9),
title: '',
content: '',
frontmatter: {
description: '',
classes: '',
customClasses: '',
school: '',
level: '',
ritual: false,
casting_time: '',
range: '',
duration: '',
concentration: false,
components: {
verbal: false,
somatic: false,
material: false,
materials: null
}
}
}
}
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)
this.$store.commit('setInRightDrawer', null)
let spellKey = getUrlParameter(window.location.href, "key")
if (spellKey) {
for (let spell of this.$store.state.mySpells.spells) {
if (spell.key == spellKey) {
this.spell = spell
if (!this.spell.custom) {
this.spell.content = spell.rawContent
this.spell.custom = true
}
}
}
} else {
this.spell.key = Math.random().toString(36).substr(2, 9)
}
}
}
</script>
<style>
</style>

View file

@ -101,6 +101,12 @@ export default {
if (THEMEISDARK === 'true') {
this.$vuetify.theme.dark = true
}
// Chargement des donées utilisateur depuis le navigateur
this.$store.commit('mySpells/initialiseStore')
this.$store.commit('myMonsters/initialiseStore')
this.$store.commit('myMagicItems/initialiseStore')
// this.$vuetify.theme.dark = this.$store.state.isThemeDark
// let conditionLinks = document.links

View file

@ -1,7 +1,12 @@
<template>
<div class="magic-item">
<Breadcrumb />
<MagicItem />
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/creation-d-objet-magique/"><v-icon left>mdi-plus</v-icon> Créer un objet magique</v-btn>
<v-btn :outlined="!isMagicItemInTreasureChest" color="accent" class="mr-4" depressed @click="toggleMagicItemInTreasureChest"><v-icon>mdi-book</v-icon> {{ displayToggleMagicItemButton }}</v-btn>
<v-btn color="primary" class="mr-4" depressed link to="/mon-grimoire/">Mes objets magiques</v-btn>
</div>
<MagicItem :magicItem="$page" />
<Edit />
</div>
</template>
@ -20,6 +25,35 @@ export default {
Edit
},
computed: {
isMagicItemInTreasureChest () {
let isInTreasureChest = false
for (let s of this.$store.state.myMagicItems.magicItems) {
if (s.key == this.$page.key) {
isInTreasureChest = true
}
}
return isInTreasureChest
},
displayToggleMagicItemButton () {
if (this.isMagicItemInTreasureChest) {
return 'Supprimer de mes objets magiques'
}
return 'Ajouter à mes objets magiques'
}
},
methods: {
toggleMagicItemInTreasureChest () {
if (this.isMagicItemInTreasureChest) {
this.$store.commit('myMagicItems/removeMagicItem', this.$page)
} else {
this.$store.commit('myMagicItems/addMagicItem', this.$page)
}
}
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', false)

View file

@ -1,7 +1,11 @@
<template>
<div class="magic-items">
<Breadcrumb />
<div class="d-flex align-center mb-4">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/creation-d-objet-magique/"><v-icon left>mdi-plus</v-icon> Créer un objet magique</v-btn>
<v-btn color="primary" depressed link to="/mes-objets-magiques/">Mes objets magiques</v-btn>
</div>
<h1>Liste des objets magiques</h1>
@ -16,6 +20,10 @@
:search="search"
>
<template v-slot:item.isInTreasureChest="{ item }">
<v-simple-checkbox off-icon="mdi-bookmark-outline" on-icon="mdi-bookmark" @input="toggleItemInTreasureChest(item)" :value="isItemInTreasureChest(item)"></v-simple-checkbox>
</template>
<template v-slot:item.title="{ item }">
<router-link :to="{ path: item.path }" class="subtitle-2">{{ item.title }}</router-link>
</template>
@ -40,6 +48,7 @@ export default {
sortBy: 'title',
sortDesc: false,
headers: [
{ text: "", align: 'center', sortable: false, value: 'isInTreasureChest' },
{ text: "Nom", align: 'start', sortable: true, value: 'title' },
{ text: "Type", align: 'start', sortable: false, value: 'frontmatter.type' },
{ text: "Rareté", align: 'start', sortable: false, value: 'frontmatter.rarity' },
@ -102,6 +111,25 @@ export default {
}
},
methods: {
isItemInTreasureChest (magicItem) {
let isInTreasureChest = false
for (let mi of this.$store.state.myMagicItems.magicItems) {
if (mi.key == magicItem.key) {
isInTreasureChest = true
}
}
return isInTreasureChest
},
toggleItemInTreasureChest (magicItem) {
if (this.isItemInTreasureChest(magicItem)) {
this.$store.commit('myMagicItems/removeMagicItem', magicItem)
} else {
this.$store.commit('myMagicItems/addMagicItem', magicItem)
}
}
},
mounted () {
this.$store.commit('setHasRightDrawer', true)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)

View file

@ -1,20 +1,57 @@
<template>
<div class="monster">
<Breadcrumb />
<Monster />
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/creation-de-monstre-pnj/"><v-icon left>mdi-plus</v-icon> Créer un monstre</v-btn>
<v-btn :outlined="!isMonsterInBestiary" color="accent" class="mr-4" depressed @click="toggleMonsterInBestiary"><v-icon>mdi-book</v-icon> {{ displayToggleMonsterButton }}</v-btn>
<v-btn color="primary" class="mr-4" depressed link to="/mon-bestiaire/">Mon Bestiaire</v-btn>
</div>
<Monster :monster="$page" />
<Edit />
</div>
</template>
<script>
import Breadcrumb from '@theme/components/Breadcrumb'
import Monster from '@theme/components/Monster'
import Edit from '@theme/components/Edit'
export default {
name: 'MonsterLayout',
components: {
Breadcrumb,
Monster
Monster,
Edit
},
computed: {
isMonsterInBestiary () {
let isInBestiary = false
for (let s of this.$store.state.myMonsters.monsters) {
if (s.key == this.$page.key) {
isInBestiary = true
}
}
return isInBestiary
},
displayToggleMonsterButton () {
if (this.isMonsterInBestiary) {
return 'Supprimer de mon grimoire'
}
return 'Ajouter à mon grimoire'
}
},
methods: {
toggleMonsterInBestiary () {
if (this.isMonsterInBestiary) {
this.$store.commit('myMonsters/removeMonster', this.$page)
} else {
this.$store.commit('myMonsters/addMonster', this.$page)
}
}
},
mounted () {

View file

@ -1,7 +1,11 @@
<template>
<div class="monsters">
<Breadcrumb />
<div class="d-flex align-center mb-4">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/creation-de-monstre-pnj/"><v-icon left>mdi-plus</v-icon> Créer un monstre</v-btn>
<v-btn color="primary" depressed link to="/mon-bestiaire/">Mon bestiaire</v-btn>
</div>
<h1>Bestiaire</h1>
@ -16,6 +20,10 @@
:search="search"
>
<template v-slot:item.isInBestiary="{ item }">
<v-simple-checkbox off-icon="mdi-bookmark-outline" on-icon="mdi-bookmark" @input="toggleMonsterInBestiary(item)" :value="isMonsterInBestiary(item)"></v-simple-checkbox>
</template>
<template v-slot:item.title="{ item }">
<router-link :to="{ path: item.path }" class="subtitle-2">{{ item.title }}</router-link>
</template>
@ -51,6 +59,7 @@ export default {
sortBy: 'title',
sortDesc: false,
headers: [
{ text: "", align: 'center', sortable: false, value: 'isInBestiary' },
{ text: "Nom", align: 'start', sortable: true, value: 'title' },
{ text: "ID", align: 'center', sortable: true, value: 'frontmatter.challenge' },
{ text: "Type", align: 'start', sortable: false, value: 'frontmatter.type' },
@ -153,6 +162,22 @@ export default {
methods: {
displayList (list) { return list.join(', ') },
displayChallenge (challenge) { return displayChallenge(challenge) },
isMonsterInBestiary (monster) {
let isInBestiary = false
for (let m of this.$store.state.myMonsters.monsters) {
if (m.key == monster.key) {
isInBestiary = true
}
}
return isInBestiary
},
toggleMonsterInBestiary (monster) {
if (this.isMonsterInBestiary(monster)) {
this.$store.commit('myMonsters/removeMonster', monster)
} else {
this.$store.commit('myMonsters/addMonster', monster)
}
}
},
mounted () {

View file

@ -0,0 +1,96 @@
<template>
<div class="my-magic-items">
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" depressed link to="/liste-objets-magiques/">Liste des objets magiques</v-btn>
</div>
<h1>Mes objets magiques</h1>
<div class="my-4 d-flex flex-wrap d-print-none">
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="print"><v-icon>mdi-printer</v-icon> Imprimer</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="download"><v-icon>mdi-file-download</v-icon> Sauvegarder</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed :loading="isUploading" @click="onUploadClick">
<v-icon left>mdi-file-upload</v-icon> Charger
</v-btn>
<input ref="uploader" class="d-none" type="file" @change="upload">
<v-btn outlined color="error" class="mb-1" depressed @click="$store.commit('myMagicItems/resetMagicItems')"><v-icon>mdi-delete</v-icon> Effacer les objets magiques</v-btn>
</div>
<MyMagicItems />
</div>
</template>
<script>
import Breadcrumb from '@theme/components/Breadcrumb'
import MyMagicItems from '@theme/components/MyMagicItems'
import { saveAs } from 'file-saver'
export default {
name: 'MyMagicItemsLayout',
components: {
Breadcrumb,
MyMagicItems
},
data () {
return {
isUploading: false
}
},
methods: {
download () {
saveAs(new Blob([JSON.stringify(this.$store.state.myMagicItems.magicItems)], {
type: "text/plain;charset=utf-8"
}), "objets-magiques.json")
},
upload (e) {
let file = e.target.files[0]
let reader = new FileReader()
let self = this
reader.onload = function() {
let result = JSON.parse(reader.result)
let isValid = true
if (result.length >= 1) {
for (var s of result) {
if (s.pid !== 'magicItem') {
isValid = false
}
}
}
if (isValid) {
self.$store.commit('myMagicItems/setMagicItems', result)
}
}
reader.readAsText(file)
},
onUploadClick () {
this.isUploading = true
window.addEventListener('focus', () => {
this.isUploading = false
}, { once: true })
this.$refs.uploader.click()
},
print () {
window.print()
}
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)
this.$store.commit('setInRightDrawer', null)
}
}
</script>
<style>
</style>

View file

@ -0,0 +1,96 @@
<template>
<div class="my-monsters">
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" depressed link to="/bestiaire/">Bestiaire</v-btn>
</div>
<h1>Mon bestiaire</h1>
<div class="my-4 d-flex flex-wrap d-print-none">
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="print"><v-icon>mdi-printer</v-icon> Imprimer</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="download"><v-icon>mdi-file-download</v-icon> Sauvegarder</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed :loading="isUploading" @click="onUploadClick">
<v-icon left>mdi-file-upload</v-icon> Charger
</v-btn>
<input ref="uploader" class="d-none" type="file" @change="upload">
<v-btn outlined color="error" class="mb-1" depressed @click="$store.commit('myMonsters/resetMonsters')"><v-icon>mdi-delete</v-icon> Effacer le bestiaire</v-btn>
</div>
<MyMonsters />
</div>
</template>
<script>
import Breadcrumb from '@theme/components/Breadcrumb'
import MyMonsters from '@theme/components/MyMonsters'
import { saveAs } from 'file-saver'
export default {
name: 'MyMonstersLayout',
components: {
Breadcrumb,
MyMonsters
},
data () {
return {
isUploading: false
}
},
methods: {
download () {
saveAs(new Blob([JSON.stringify(this.$store.state.myMonsters.monsters)], {
type: "text/plain;charset=utf-8"
}), "bestiaire.json")
},
upload (e) {
let file = e.target.files[0]
let reader = new FileReader()
let self = this
reader.onload = function() {
let result = JSON.parse(reader.result)
let isValid = true
if (result.length >= 1) {
for (var s of result) {
if (s.pid !== 'monster') {
isValid = false
}
}
}
if (isValid) {
self.$store.commit('myMonsters/setMonsters', result)
}
}
reader.readAsText(file)
},
onUploadClick () {
this.isUploading = true
window.addEventListener('focus', () => {
this.isUploading = false
}, { once: true })
this.$refs.uploader.click()
},
print () {
window.print()
}
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)
this.$store.commit('setInRightDrawer', null)
}
}
</script>
<style>
</style>

View file

@ -0,0 +1,96 @@
<template>
<div class="my-spells">
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" depressed link to="/grimoire/">Grimoire</v-btn>
</div>
<h1>Mon grimoire</h1>
<div class="my-4 d-flex flex-wrap d-print-none">
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="print"><v-icon>mdi-printer</v-icon> Imprimer</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed @click="download"><v-icon>mdi-file-download</v-icon> Sauvegarder</v-btn>
<v-btn outlined color="accent" class="mr-1 mb-1" depressed :loading="isUploading" @click="onUploadClick">
<v-icon left>mdi-file-upload</v-icon> Charger
</v-btn>
<input ref="uploader" class="d-none" type="file" @change="upload">
<v-btn outlined color="error" class="mb-1" depressed @click="$store.commit('mySpells/resetSpells')"><v-icon>mdi-delete</v-icon> Effacer le grimoire</v-btn>
</div>
<MySpells />
</div>
</template>
<script>
import Breadcrumb from '@theme/components/Breadcrumb'
import MySpells from '@theme/components/MySpells'
import { saveAs } from 'file-saver'
export default {
name: 'MySpellsLayout',
components: {
Breadcrumb,
MySpells
},
data () {
return {
isUploading: false
}
},
methods: {
download () {
saveAs(new Blob([JSON.stringify(this.$store.state.mySpells.spells)], {
type: "text/plain;charset=utf-8"
}), "grimoire.json")
},
upload (e) {
let file = e.target.files[0]
let reader = new FileReader()
let self = this
reader.onload = function() {
let result = JSON.parse(reader.result)
let isValid = true
if (result.length >= 1) {
for (var s of result) {
if (s.pid !== 'spell') {
isValid = false
}
}
}
if (isValid) {
self.$store.commit('mySpells/setSpells', result)
}
}
reader.readAsText(file)
},
onUploadClick () {
this.isUploading = true
window.addEventListener('focus', () => {
this.isUploading = false
}, { once: true })
this.$refs.uploader.click()
},
print () {
window.print()
}
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)
this.$store.commit('setInRightDrawer', null)
}
}
</script>
<style>
</style>

View file

@ -1,7 +1,12 @@
<template>
<div class="spell">
<Breadcrumb />
<Spell />
<div class="d-flex align-center mb-4 d-print-none">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/creation-de-sort/"><v-icon left>mdi-plus</v-icon> Créer un sort</v-btn>
<v-btn :outlined="!isSpellInSpellBook" color="accent" class="mr-4" depressed @click="toggleSpellInSpellBook"><v-icon>mdi-book</v-icon> {{ displayToggleSpellButton }}</v-btn>
<v-btn color="primary" class="mr-4" depressed link to="/mon-grimoire/">Mon Grimoire</v-btn>
</div>
<Spell :spell="$page" />
<Edit />
</div>
</template>
@ -20,6 +25,35 @@ export default {
Edit
},
computed: {
isSpellInSpellBook () {
let isInSpellBook = false
for (let s of this.$store.state.mySpells.spells) {
if (s.key == this.$page.key) {
isInSpellBook = true
}
}
return isInSpellBook
},
displayToggleSpellButton () {
if (this.isSpellInSpellBook) {
return 'Supprimer de mon grimoire'
}
return 'Ajouter à mon grimoire'
}
},
methods: {
toggleSpellInSpellBook () {
if (this.isSpellInSpellBook) {
this.$store.commit('mySpells/removeSpell', this.$page)
} else {
this.$store.commit('mySpells/addSpell', this.$page)
}
}
},
mounted () {
this.$store.commit('setHasRightDrawer', false)
this.$store.commit('setRightDrawer', this.$vuetify.breakpoint.lgAndUp)

View file

@ -1,10 +1,15 @@
<template>
<div class="spells">
<Breadcrumb />
<div class="d-flex align-center mb-4">
<Breadcrumb class="mr-auto" />
<v-btn color="primary" class="mr-4" depressed link to="/creation-de-sort/"><v-icon left>mdi-plus</v-icon> Créer un sort</v-btn>
<v-btn color="primary" depressed link to="/mon-grimoire/">Mon grimoire</v-btn>
</div>
<h1>Grimoire</h1>
<v-data-table
class="data-table"
:headers="headers"
@ -16,6 +21,10 @@
:search="search"
>
<template v-slot:item.isInSpellBook="{ item }">
<v-simple-checkbox off-icon="mdi-bookmark-outline" on-icon="mdi-bookmark" @input="toggleSpellInSpellBook(item)" :value="isSpellInSpellBook(item)"></v-simple-checkbox>
</template>
<template v-slot:item.title="{ item }">
<router-link :to="{ path: item.path }" class="subtitle-2">{{ item.title }}</router-link>
</template>
@ -61,6 +70,7 @@ export default {
sortBy: 'title',
sortDesc: false,
headers: [
{ text: "", align: 'center', sortable: false, value: 'isInSpellBook' },
{ text: "Nom", align: 'start', sortable: true, value: 'title' },
{ text: "Niveau", align: 'center', sortable: true, value: 'frontmatter.level' },
{ text: "École", align: 'start', sortable: false, value: 'frontmatter.school' },
@ -172,6 +182,25 @@ export default {
}
},
methods: {
isSpellInSpellBook (spell) {
let isInSpellBook = false
for (let s of this.$store.state.mySpells.spells) {
if (s.key == spell.key) {
isInSpellBook = true
}
}
return isInSpellBook
},
toggleSpellInSpellBook (spell) {
if (this.isSpellInSpellBook(spell)) {
this.$store.commit('mySpells/removeSpell', spell)
} else {
this.$store.commit('mySpells/addSpell', spell)
}
}
},
mounted () {
this.$store.commit('setDrawer', this.$vuetify.breakpoint.lgAndUp)
this.$store.commit('setHasRightDrawer', true)