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

@ -43,6 +43,16 @@
crumbs.push({to: page.path, disabled: disabled, text: 'Bestiaire'})
} else if (page.path == '/liste-objets-magiques/') {
crumbs.push({to: page.path, disabled: disabled, text: 'Liste des objets magiques'})
} else if (page.path == '/mon-grimoire/') {
crumbs.push({to: page.path, disabled: disabled, text: 'Mon grimoire'})
} else if (page.path == '/mon-bestiaire/') {
crumbs.push({to: page.path, disabled: disabled, text: 'Mon bestiaire'})
} else if (page.path == '/mes-objets-magiques/') {
crumbs.push({to: page.path, disabled: disabled, text: 'Mes objets magiques'})
} else if (page.path == '/creation-de-sort/') {
crumbs.push({to: page.path, disabled: disabled, text: 'Création de sort'})
} else if (page.path == '/creation-de-monstre-pnj/') {
crumbs.push({to: page.path, disabled: disabled, text: 'Création de monstre ou PNJ'})
} else {
crumbs.push({to: page.path, disabled: disabled, text: page.frontmatter.breadcrumb || page.title})
}

View file

@ -2,13 +2,17 @@
<main class="page content">
<div class="theme-default-content">
<h1>{{ $page.title }}</h1>
<div class="magic-item-details">
<template v-if="!hideTitle">
<h1 v-if="!isList">{{ magicItem.title }}</h1>
<h2 v-else>{{ magicItem.title }}</h2>
</template>
<div class="magic-item-details title">
{{displayItemMeta()}}
</div>
</div>
<Content class="mt-4" />
<Content v-if="!magicItem.custom" :pageKey="magicItem.key" class="mt-4" />
<div v-else v-html="md.render(magicItem.content)" class="mt-4"></div>
<p v-if="$page.frontmatter.source" class="source">Source : <em>{{ $page.frontmatter.source }}</em></p>
@ -17,11 +21,22 @@
<script>
import {displayItemMeta} from '@theme/util/magicItemHelpers'
import MarkdownIt from 'markdown-it'
export default {
name: 'MagicItem',
data () {
return {
md: new MarkdownIt()
}
},
props: ['magicItem', 'isList', 'hideTitle'],
methods : {
displayItemMeta () {
return displayItemMeta(this.$page.frontmatter)
return displayItemMeta(this.magicItem.frontmatter)
}
}
}

View file

@ -0,0 +1,64 @@
<template>
<v-card class="d-flex flex-column mb-6 magic-item-card">
<v-card-title>
{{ magicItem.title }}
<v-spacer></v-spacer>
<v-card-actions v-if="showActions">
<v-btn dark icon class="d-print-none mr-2" link :to="{ path: '/creation-d-objet-magique/', query: { key: magicItem.key } }"><v-icon>mdi-pencil</v-icon></v-btn>
<v-btn dark icon class="d-print-none" @click="$store.commit('myMagicItems/removeMagicItem', magicItem)"><v-icon>mdi-delete</v-icon></v-btn>
</v-card-actions>
</v-card-title>
<v-card-text>
<div class="magic-item-details mt-3">
<div class="magic-item-rarity-attunement title" v-html="displayItemMeta()"></div>
</div>
<v-divider class="mt-3" />
<Content v-if="!magicItem.custom" :pageKey="magicItem.key" class="mt-4" />
<div v-else v-html="md.render(magicItem.content)" class="mt-4"></div>
<p v-if="magicItem.frontmatter.source" class="source">Source : <em>{{ magicItem.frontmatter.source }}</em></p>
</v-card-text>
</v-card>
</template>
<script>
import { displayItemMeta } from '@theme/util/magicItemHelpers'
import MarkdownIt from 'markdown-it'
export default {
name: 'MagicItemCard',
props: ['magicItem', 'showActions', 'isShort'],
data () {
return {
md: new MarkdownIt()
}
},
methods: {
displayItemMeta () {
return displayItemMeta(this.magicItem.frontmatter)
}
},
}
</script>
<style lang="scss">
@import '../styles/colors';
.magic-item-card {
.v-card__title {
background-color: $color-dragon;
color: #fff;
padding-top: 0;
padding-bottom: 0;
}
p.source {
margin-bottom: 0;
}
}
</style>

View file

@ -2,133 +2,140 @@
<main class="page content">
<div class="theme-default-content">
<h1>{{ $page.title }}</h1>
<div class="monster-type-size-alignment">
<template v-if="!hideTitle">
<h1 v-if="!isList">{{ monster.title }}</h1>
<h2 v-else>{{ monster.title }}</h2>
</template>
<div class="monster-type-size-alignment title">
{{ displayMonsterTypeSizeAlignment() }}
</div>
<div class="monster-details">
<!-- Statblock -->
<div class="monster-armor-class">
<strong>Classe d'armure</strong>
<span>{{ displayAC() }}</span>
</div>
<div class="monster-hit-points">
<strong>Points de vie</strong>
<span>{{ displayHP() }}</span>
</div>
<div class="monster-movement">
<strong>Vitesse</strong>
<template>{{ displayMovement() }}</template>
</div>
<div class="monster-ability-scores d-flex">
<div class="monster-ability-scores-physical d-flex">
<div class="ability-str text-center">
<div class="ability-label">
<strong>For</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monster.abilityScores.for) }}
</div>
</div>
<div class="ability-dex text-center">
<div class="ability-label">
<strong>Dex</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monster.abilityScores.dex) }}
</div>
</div>
<div class="ability-con text-center">
<div class="ability-label">
<strong>Con</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monster.abilityScores.con) }}
</div>
</div>
<div class="break-avoid">
<!-- Statblock -->
<div class="monster-armor-class">
<strong>Classe d'armure</strong>
<span>{{ displayAC() }}</span>
</div>
<div class="monster-ability-scores-mental d-flex">
<div class="ability-int text-center">
<div class="ability-label">
<strong>Int</strong>
<div class="monster-hit-points">
<strong>Points de vie</strong>
<span>{{ hp }}</span>
</div>
<div class="monster-movement">
<strong>Vitesse</strong>
<template>{{ displayMovement() }}</template>
</div>
<div class="monster-ability-scores d-flex">
<div class="monster-ability-scores-physical d-flex">
<div class="ability-str text-center">
<div class="ability-label">
<strong>For</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monsterStats.abilityScores.for) }}
</div>
</div>
<div class="ability-score">
{{ displayAbilityScore(monster.abilityScores.int) }}
<div class="ability-dex text-center">
<div class="ability-label">
<strong>Dex</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monsterStats.abilityScores.dex) }}
</div>
</div>
<div class="ability-con text-center">
<div class="ability-label">
<strong>Con</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monsterStats.abilityScores.con) }}
</div>
</div>
</div>
<div class="ability-wis text-center">
<div class="ability-label">
<strong>Sag</strong>
<div class="monster-ability-scores-mental d-flex">
<div class="ability-int text-center">
<div class="ability-label">
<strong>Int</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monsterStats.abilityScores.int) }}
</div>
</div>
<div class="ability-score">
{{ displayAbilityScore(monster.abilityScores.sag) }}
<div class="ability-wis text-center">
<div class="ability-label">
<strong>Sag</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monsterStats.abilityScores.sag) }}
</div>
</div>
</div>
<div class="ability-cha text-center">
<div class="ability-label">
<strong>Cha</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monster.abilityScores.cha) }}
<div class="ability-cha text-center">
<div class="ability-label">
<strong>Cha</strong>
</div>
<div class="ability-score">
{{ displayAbilityScore(monsterStats.abilityScores.cha) }}
</div>
</div>
</div>
</div>
</div>
<div class="monster-saving-throws" v-if="monster.savingThrows">
<strong>Jets de sauvegarde</strong>
<span class="monster-saving-throw" v-for="(savingThrow, idx) in monster.savingThrows">
<template>{{displaySavingThrowBonus(savingThrow)}}</template><template v-if="idx < monster.savingThrows.length - 1">, </template>
</span>
</div>
<div class="monster-skills" v-if="monster.skills">
<strong>Compétences</strong>
<span class="monster-skill" v-for="(skill, idx) in monster.skills">
<template>{{displaySkillBonus(skill)}}</template><template v-if="idx < monster.skills.length - 1">, </template>
</span>
</div>
<div class="monster-damage-type-vulnerabilities" v-if="monster.damageTypeVulnerabilities">
<strong>Vulnérabilité aux dégâts</strong>
<span v-html="displayDamageTypes(monster.damageTypeVulnerabilities)"></span>
</div>
<div class="monster-damage-type-resistances" v-if="monster.damageTypeResistances">
<strong>Résistance aux dégâts</strong>
<span v-html="displayDamageTypes(monster.damageTypeResistances)"></span>
</div>
<div class="monster-damage-type-immunities" v-if="monster.damageTypeImmunities">
<strong>Immunité contre les dégâts</strong>
<span v-html="displayDamageTypes(monster.damageTypeImmunities)"></span>
</div>
<div class="monster-condition-immunities" v-if="monster.conditionImmunities">
<strong>Immunité contre les états</strong>
<span v-html="displayConditionImmunities()"></span>
</div>
<div class="monster-senses">
<strong>Sens</strong>
<template>{{ displaySenses() }}</template>
</div>
<div class="monster-languages">
<strong>Langes</strong>
<template v-if="monster.languages">{{ displayLanguages() }}</template>
<template v-else></template>
</div>
<div class="monster-challenge">
<strong>Dangerosité</strong>
<template>{{ displayChallenge() }}</template>
</div>
<div class="monster-environments" v-if="monster.environments">
<strong>Environnements :</strong>
<span v-html="displayList(monster.environments)"></span>
</div>
<div class="monster-dungeon-types" v-if="monster.dungeonTypes">
<strong>Types de donjons :</strong>
<span v-html="displayList(monster.dungeonTypes)"></span>
<div class="break-avoid">
<div class="monster-saving-throws" v-if="monsterStats.savingThrows && monsterStats.savingThrows.length > 0">
<strong>Jets de sauvegarde</strong>
<span class="monster-saving-throw" v-for="(savingThrow, idx) in monsterStats.savingThrows">
<template>{{displaySavingThrowBonus(savingThrow)}}</template><template v-if="idx < monsterStats.savingThrows.length - 1">, </template>
</span>
</div>
<div class="monster-skills" v-if="monsterStats.skills && monsterStats.skills.length > 0">
<strong>Compétences</strong>
<span class="monster-skill" v-for="(skill, idx) in monsterStats.skills">
<template>{{displaySkillBonus(skill)}}</template><template v-if="idx < monsterStats.skills.length - 1">, </template>
</span>
</div>
<div class="monster-damage-type-vulnerabilities" v-if="monsterStats.damageTypeVulnerabilities && monsterStats.damageTypeVulnerabilities.length > 0">
<strong>Vulnérabilité aux dégâts</strong>
<span v-html="displayDamageTypes(monsterStats.damageTypeVulnerabilities)"></span>
</div>
<div class="monster-damage-type-resistances" v-if="monsterStats.damageTypeResistances && monsterStats.damageTypeResistances.length > 0">
<strong>Résistance aux dégâts</strong>
<span v-html="displayDamageTypes(monsterStats.damageTypeResistances)"></span>
</div>
<div class="monster-damage-type-immunities" v-if="monsterStats.damageTypeImmunities && monsterStats.damageTypeImmunities.length > 0">
<strong>Immunité contre les dégâts</strong>
<span v-html="displayDamageTypes(monsterStats.damageTypeImmunities)"></span>
</div>
<div class="monster-condition-immunities" v-if="monsterStats.conditionImmunities && monsterStats.conditionImmunities.length > 0">
<strong>Immunité contre les états</strong>
<span v-html="displayConditionImmunities()"></span>
</div>
<div class="monster-senses">
<strong>Sens</strong>
<template>{{ displaySenses() }}</template>
</div>
<div class="monster-languages">
<strong>Langes</strong>
<template>{{ languages }}</template>
</div>
<div class="monster-challenge">
<strong>Dangerosité</strong>
<template>{{ displayChallenge() }}</template>
</div>
<div class="monster-environments" v-if="monsterStats.environments">
<strong>Environnements :</strong>
<span v-html="displayList(monsterStats.environments)"></span>
</div>
<div class="monster-dungeon-types" v-if="monsterStats.dungeonTypes">
<strong>Types de donjons :</strong>
<span v-html="displayList(monsterStats.dungeonTypes)"></span>
</div>
</div>
</div>
</div>
<Content class="mt-4"/>
<Content v-if="!monster.custom" :pageKey="monster.key" class="mt-4" />
<div v-else v-html="md.render(monster.content)" class="mt-4"></div>
<p v-if="$page.frontmatter.source" class="source">Source : <em>{{ monster.source }}</em></p>
<p v-if="$page.frontmatter.source" class="source">Source : <em>{{ monsterStats.source }}</em><template v-if="monsterStats.source_page">, page {{ monsterStats.source_page }}</template></p>
</main>
</template>
@ -145,26 +152,29 @@ import {
import {stats} from '../../data/stats.js'
import {armorTypes} from '../../data/armorTypes.js'
import MarkdownIt from 'markdown-it'
export default {
props: ['monster', 'isList', 'hideTitle'],
data () {
return {
md: new MarkdownIt()
}
},
computed: {
monster () {
return this.$page.frontmatter
monsterStats () {
return this.monster.frontmatter
},
proficiencyBonus () {
return this.getProficiencyBonus()
},
passivePerception () {
let result = 10 + getModifier(this.monster.abilityScores.sag)
if (this.monster.skills) {
this.monster.skills.forEach((skill, idx) => {
let result = 10 + getModifier(this.monsterStats.abilityScores.sag)
if (this.monsterStats.skills) {
this.monsterStats.skills.forEach((skill, idx) => {
if (skill.name == 'perception') {
if (skill.isExpert) {
result += this.proficiencyBonus * 2
@ -176,35 +186,73 @@ export default {
}
return result
},
hp () {
if (this.monsterStats.customHP) {
return this.monsterStats.customHP
} else if (this.monsterStats.hitDiceCount) {
let hitDieSize = 8 // Dé de vie moyen par défaut
if (this.monsterStats.hitDieSize) {
hitDieSize = this.monsterStats.hitDieSize
} else if (this.monsterStats.size) {
hitDieSize = stats.sizes[this.monsterStats.size].hitDie
}
let hitPointsBonus = 1
if (this.monsterStats.hitDiceCount > 1) {
hitPointsBonus = Math.floor(this.monsterStats.hitDiceCount / 2)
}
let averageHP = this.monsterStats.hitDiceCount * (hitDieSize / 2) + this.monsterStats.hitDiceCount * getModifier(this.monsterStats.abilityScores.con) + hitPointsBonus
let conMod = ""
if (getModifier(this.monsterStats.abilityScores.con) != 0) {
conMod = this.monsterStats.hitDiceCount * getModifier(this.monsterStats.abilityScores.con)
conMod = displayBonus(conMod)
}
return averageHP + ' (' + this.monsterStats.hitDiceCount + "d" + hitDieSize + conMod + ')'
}
return ""
},
languages () {
let result = this.monsterStats.languages.join(', ')
if (this.monsterStats.customLanguage) {
if (result != '') {
result += ', '
}
result += this.monsterStats.customLanguage
}
if (this.monsterStats.telepathy) {
if (result != '') {
result += ', '
}
result += 'télépathie ' + this.monsterStats.telepathy + ' m'
}
if (result == '') {
return '—'
}
return result
},
},
methods: {
displayList (list) { return list.join(', ') },
displayAbilityScore (value) { return displayAbilityScore(value) },
getModifier (value) { return getModifier(value) },
getProficiencyBonus () { return getProficiencyBonus(this.monster.challenge) },
getProficiencyBonus () { return getProficiencyBonus(this.monsterStats.challenge) },
displayMonsterTypeSizeAlignment () {
return displayMonsterTypeSizeAlignment(this.monster)
return displayMonsterTypeSizeAlignment(this.monsterStats)
},
displaySavingThrowBonus (ability) {
let result = stats.abilities[ability].abbr
let bonus = displayBonus(getModifier(this.monster.abilityScores[ability]) + this.proficiencyBonus)
let bonus = displayBonus(getModifier(this.monsterStats.abilityScores[ability]) + this.proficiencyBonus)
result += ' ' + bonus
return result
},
displaySkillBonus (skill) {
if (skill.name == 'Perception') {
if (skill.isExpert) {
this.monster.perceptionProficiency == 'expert'
} else {
this.monster.perceptionProficiency == 'proficient'
}
}
let result = stats.skills[skill.name].label
let bonus = getModifier(this.monster.abilityScores[stats.skills[skill.name].ability]) + this.proficiencyBonus
let bonus = getModifier(this.monsterStats.abilityScores[stats.skills[skill.name].ability]) + this.proficiencyBonus
if (skill.isExpert) {
bonus += this.proficiencyBonus // Bonus de maître doublé pour les experts
}
@ -213,66 +261,41 @@ export default {
return result
},
displayHP () {
if (this.monster.customHP) {
return this.monster.customHP
} else if (this.monster.hitDiceCount) {
let hitDieSize = 8 // Dé de vie moyen par défaut
if (this.monster.hitDieSize) {
hitDieSize = this.monster.hitDieSize
} else if (this.monster.size) {
hitDieSize = stats.sizes[this.monster.size].hitDie
}
let hitPointsBonus = 1
if (this.monster.hitDiceCount > 1) {
hitPointsBonus = Math.floor(this.monster.hitDiceCount / 2)
}
let averageHP = this.monster.hitDiceCount * (hitDieSize / 2) + this.monster.hitDiceCount * getModifier(this.monster.abilityScores.con) + hitPointsBonus
let conMod = ""
if (getModifier(this.monster.abilityScores.con) != 0) {
conMod = this.monster.hitDiceCount * getModifier(this.monster.abilityScores.con)
conMod = displayBonus(conMod)
}
return averageHP + ' (' + this.monster.hitDiceCount + "d" + hitDieSize + conMod + ')'
}
return ""
},
displayChallenge () {
return displayChallenge(this.monster.challenge, true)
return displayChallenge(this.monsterStats.challenge, true)
},
displayMovement () {
let result = ''
if (this.monster.movement.walk) {
result += this.monster.movement.walk + ' m'
if (this.monsterStats.movement.walk) {
result += this.monsterStats.movement.walk + ' m'
} else {
result += '0 m'
}
if (this.monster.movement.climb) {
if (this.monsterStats.movement.climb) {
if (result != '') {
result += ', '
}
result += 'escalade ' + this.monster.movement.climb + ' m'
result += 'escalade ' + this.monsterStats.movement.climb + ' m'
}
if (this.monster.movement.burrow) {
if (this.monsterStats.movement.burrow) {
if (result != '') {
result += ', '
}
result += 'fouissement ' + this.monster.movement.burrow + ' m'
result += 'fouissement ' + this.monsterStats.movement.burrow + ' m'
}
if (this.monster.movement.swim) {
if (this.monsterStats.movement.swim) {
if (result != '') {
result += ', '
}
result += 'nage ' + this.monster.movement.swim + ' m'
result += 'nage ' + this.monsterStats.movement.swim + ' m'
}
if (this.monster.movement.fly) {
if (this.monsterStats.movement.fly) {
if (result != '') {
result += ', '
}
result += 'vol ' + this.monster.movement.fly + ' m'
if (this.monster.movement.hover) {
result += 'vol ' + this.monsterStats.movement.fly + ' m'
if (this.monsterStats.movement.hover) {
result += ' (vol stationnaire)'
}
}
@ -287,44 +310,48 @@ export default {
let armor = ''
// Le monstre n'a pas d'armure.
// CA = 10 + Dex
if (!this.monster.ac.armorType) {
ac = 10 + getModifier(this.monster.abilityScores.dex)
if (!this.monsterStats.ac.armorType) {
ac = 10 + getModifier(this.monsterStats.abilityScores.dex)
} else {
// Le type d'armure n'est pas formalisé. On prend la valeur brute
if (this.monster.ac.armorType == 'custom') {
return this.monster.ac.value
if (this.monsterStats.ac.armorType == 'custom') {
return this.monsterStats.ac.value
}
// Le monstre a une armure naturelle.
// CA = 10 + Armure naturelle + Dex
if (this.monster.ac.armorType == 'armure naturelle') {
armor = this.monster.ac.armorType
ac = ac + this.monster.ac.value + getModifier(this.monster.abilityScores.dex)
} else if (this.monster.ac.armorType == 'armure du mage') {
if (this.monsterStats.ac.armorType == 'armure naturelle') {
armor = this.monsterStats.ac.armorType
if (parseInt(this.monsterStats.ac.value)) {
ac = ac + parseInt(this.monsterStats.ac.value) + getModifier(this.monsterStats.abilityScores.dex)
} else {
ac = ac + getModifier(this.monsterStats.abilityScores.dex)
}
} else if (this.monsterStats.ac.armorType == 'armure du mage') {
hasMageArmor = true
ac = ac + getModifier(this.monster.abilityScores.dex)
mageArmorAc = mageArmorAc + getModifier(this.monster.abilityScores.dex)
ac = ac + getModifier(this.monsterStats.abilityScores.dex)
mageArmorAc = mageArmorAc + getModifier(this.monsterStats.abilityScores.dex)
armor = mageArmorAc + ' avec armure du mage'
} else {
// Le monstre a un type d'armure défini.
// On calcule sa CA selon le type
let armorType = armorTypes[this.monster.ac.armorType]
let armorType = armorTypes[this.monsterStats.ac.armorType]
// Le type d'armure n'existe pas. On l'ignore.
// CA = 10 + Dex
if (!armorType) {
ac = ac + getModifier(this.monster.abilityScores.dex)
ac = ac + getModifier(this.monsterStats.abilityScores.dex)
} else {
// L'armure n'impose pas de limite de Dex
armor = this.monster.ac.armorType
armor = this.monsterStats.ac.armorType
if (armorType.maxDex === false) {
ac = armorType.value + getModifier(this.monster.abilityScores.dex)
ac = armorType.value + getModifier(this.monsterStats.abilityScores.dex)
} else {
// La limite de Dex de l'armure est inférieure à la Dex du monstre
if (armorType.maxDex <= getModifier(this.monster.abilityScores.dex)) {
if (armorType.maxDex <= getModifier(this.monsterStats.abilityScores.dex)) {
ac = armorType.value + armorType.maxDex
} else {
ac = armorType.value + getModifier(this.monster.abilityScores.dex)
ac = armorType.value + getModifier(this.monsterStats.abilityScores.dex)
}
}
}
@ -333,7 +360,7 @@ export default {
// Le monstre a un bouclier. Sa CA augmente de 2.
if (this.monster.ac.hasShield) {
if (this.monsterStats.ac.hasShield) {
ac = ac + 2
mageArmorAc = mageArmorAc + 2
if (armor != '') {
@ -353,33 +380,29 @@ export default {
return ac
},
displayLanguages () {
return this.monster.languages.join(', ')
},
displaySenses () {
let result = ''
if (this.monster.senses) {
if (this.monster.senses.tremorsense) {
result += 'perception des vibrations ' + this.monster.senses.tremorsense + ' m'
if (this.monsterStats.senses) {
if (this.monsterStats.senses.tremorsense) {
result += 'perception des vibrations ' + this.monsterStats.senses.tremorsense + ' m'
}
if (this.monster.senses.blindsight) {
if (this.monsterStats.senses.blindsight) {
if (result != '') {
result += ', '
}
result += 'vision aveugle ' + this.monster.senses.blindsight + ' m'
result += 'vision aveugle ' + this.monsterStats.senses.blindsight + ' m'
}
if (this.monster.senses.darkvision) {
if (this.monsterStats.senses.darkvision) {
if (result != '') {
result += ', '
}
result += 'vision dans le noir ' + this.monster.senses.darkvision + ' m'
result += 'vision dans le noir ' + this.monsterStats.senses.darkvision + ' m'
}
if (this.monster.senses.truesight) {
if (this.monsterStats.senses.truesight) {
if (result != '') {
result += ', '
}
result += 'vision parfaite ' + this.monster.senses.truesight + ' m'
result += 'vision parfaite ' + this.monsterStats.senses.truesight + ' m'
}
if (result != '') {
result += ', '
@ -392,9 +415,9 @@ export default {
displayConditionImmunities () {
let result = ''
this.monster.conditionImmunities.forEach((condition, idx) => {
this.monsterStats.conditionImmunities.forEach((condition, idx) => {
if (result != '') {
if (idx == this.monster.conditionImmunities.length - 1) {
if (idx == this.monsterStats.conditionImmunities.length - 1) {
result += ' et '
} else {
result += ', '
@ -432,7 +455,7 @@ export default {
.monster-ability-scores {
margin: 12px 0;
.ability-label, .ability-score {
padding: 0 8px;
}

View file

@ -0,0 +1,76 @@
<template>
<v-card class="d-flex flex-column mb-6 monster-card">
<v-card-title>
{{ monster.title }}
<v-spacer></v-spacer>
<v-card-actions v-if="showActions">
<v-btn dark icon class="d-print-none mr-2" link :to="{ path: '/creation-de-monstre-pnj/', query: { key: monster.key } }"><v-icon>mdi-pencil</v-icon></v-btn>
<v-btn dark icon class="d-print-none" @click="$store.commit('myMonsters/removeMonster', monster)"><v-icon>mdi-delete</v-icon></v-btn>
</v-card-actions>
</v-card-title>
<v-card-text>
<div class="monster-card-details mt-3">
<Monster :monster="monster" :hideTitle="true" />
</div>
<v-divider class="mt-3" />
<p v-if="monster.frontmatter.source" class="source">Source : <em>{{ monster.frontmatter.source }}</em></p>
</v-card-text>
</v-card>
</template>
<script>
import Monster from '@theme/components/Monster'
import { displaySchoolLevel } from '@theme/util/monsterHelpers'
import MarkdownIt from 'markdown-it'
export default {
name: 'MonsterCard',
components: { Monster },
props: ['monster', 'showActions', 'isShort'],
data () {
return {
md: new MarkdownIt()
}
},
methods: {
displaySchoolLevel () {
return displaySchoolLevel(this.monster.frontmatter)
}
},
}
</script>
<style lang="scss">
@import '../styles/colors';
.monster-card {
.v-card__title {
background-color: $color-dragon;
color: #fff;
padding-top: 0;
padding-bottom: 0;
}
.monster-card-details {
column-count: 2;
.monster-ability-scores, .break-avoid {
break-inside: avoid;
}
}
p.source {
margin-bottom: 0;
}
.break-avoid {
break-inside: avoid;
}
}
</style>

View file

@ -0,0 +1,58 @@
<template>
<main class="page content">
<div class="theme-default-content">
<div v-if="magicItems.length > 0">
<masonry class="d-print-none" :cols="{'default': 2, 960: 1}" :gutter="24">
<MagicItemCard v-for="(magicItem, idx) in magicItems" :magicItem="magicItem" :showActions="true" :key="idx">
</MagicItemCard>
</masonry>
<div class="d-none d-print-block" v-for="magicItem in magicItems">
<div>
<h2 class="d-flex align-center">
<div class="mr-4">{{ magicItem.title }}</div>
<v-btn class="d-print-none mr-2" small depressed link :to="{ path: '/creation-de-sort/', query: { key: magicItem.key } }"><v-icon left>mdi-pencil</v-icon> Modifier</v-btn>
<v-btn color="error" class="d-print-none" small depressed @click="$store.commit('myMagicItems/removeMagicItem', magicItem)"><v-icon left>mdi-delete</v-icon> Supprimer</v-btn>
</h2>
</div>
<MagicItem :magicItem="magicItem" :isList="true" :hideTitle="true" />
</div>
</div>
<template v-else>
Vous n'avez aucun objet magique.
</template>
</div>
</main>
</template>
<script>
import MagicItem from '@theme/components/MagicItem'
import MagicItemCard from '@theme/components/MagicItemCard'
export default {
name: 'MyMagicItems',
components: {
MagicItem,
MagicItemCard
},
data () {
return {
}
},
computed: {
magicItems () {
return this.$store.state.myMagicItems.magicItems
}
},
methods: {
}
}
</script>
<style lang="scss">
</style>

View file

@ -0,0 +1,56 @@
<template>
<main class="page content">
<div class="theme-default-content">
<template v-if="monsters.length > 0">
<MonsterCard v-for="(monster, idx) in monsters" :monster="monster" :showActions="true" :key="idx">
</MonsterCard>
<div class="d-none d-print-block" v-for="monster in monsters">
<div>
<h1 class="d-flex align-center">
<div class="mr-4">{{ monster.title }}</div>
<v-btn class="d-print-none mr-2" small depressed link :to="{ path: '/creation-de-monstre-pnj/', query: { key: monster.key } }"><v-icon left>mdi-pencil</v-icon> Modifier</v-btn>
<v-btn color="error" class="d-print-none" small depressed @click="$store.commit('myMonsters/removeMonster', monster)"><v-icon left>mdi-delete</v-icon> Supprimer</v-btn>
</h1>
</div>
<Monster :monster="monster" :isList="true" :hideTitle="true" />
</div>
</template>
<template v-else>
Vous n'avez recensé aucun monstre dans votre bestiaire.
</template>
</div>
</main>
</template>
<script>
import Monster from '@theme/components/Monster'
import MonsterCard from '@theme/components/MonsterCard'
export default {
name: 'MyMonsters',
components: {
Monster,
MonsterCard
},
data () {
return {
}
},
computed: {
monsters () {
return this.$store.state.myMonsters.monsters
}
},
methods: {
}
}
</script>
<style lang="scss">
</style>

View file

@ -0,0 +1,58 @@
<template>
<main class="page content">
<div class="theme-default-content">
<div v-if="spells.length > 0">
<masonry class="d-print-none" :cols="{'default': 2, 960: 1}" :gutter="24">
<SpellCard v-for="(spell, idx) in spells" :spell="spell" :showActions="true" :key="idx">
</SpellCard>
</masonry>
<div class="d-none d-print-block" v-for="spell in spells">
<div>
<h2 class="d-flex align-center">
<div class="mr-4">{{ spell.title }}</div>
<v-btn class="d-print-none mr-2" small depressed link :to="{ path: '/creation-de-sort/', query: { key: spell.key } }"><v-icon left>mdi-pencil</v-icon> Modifier</v-btn>
<v-btn color="error" class="d-print-none" small depressed @click="$store.commit('mySpells/removeSpell', spell)"><v-icon left>mdi-delete</v-icon> Supprimer</v-btn>
</h2>
</div>
<Spell :spell="spell" :isList="true" :hideTitle="true" />
</div>
</div>
<template v-else>
Vous n'avez écrit aucun sort dans votre grimoire.
</template>
</div>
</main>
</template>
<script>
import Spell from '@theme/components/Spell'
import SpellCard from '@theme/components/SpellCard'
export default {
name: 'MySpells',
components: {
Spell,
SpellCard
},
data () {
return {
}
},
computed: {
spells () {
return this.$store.state.mySpells.spells
}
},
methods: {
}
}
</script>
<style lang="scss">
</style>

View file

@ -16,6 +16,9 @@
<template v-for="item in items">
<v-list-group v-if="item.children" :key="item.title" :value="isExpanded(item)" color="accent">
<template v-slot:activator>
<v-list-item-icon v-if="item.icon">
<v-icon v-text="item.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
{{ item.title }}
@ -26,25 +29,37 @@
<template v-for="child in item.children">
<v-list-group v-if="child.children" :key="child.title" sub-group :value="isExpanded(child)" color="accent">
<template v-slot:activator>
<v-list-item-icon v-if="child.icon">
<v-icon v-text="child.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
{{ child.title }}
<v-chip v-if="child.badge" class="ml-2" color="primary" x-small label v-html="displayBadge(child.badge)"></v-chip>
</v-list-item-title>
</v-list-item-content>
</template>
<v-list-item v-for="subchild in child.children" link :to="{path: subchild.path}" :exact="subchild.exact">
<v-list-item-icon v-if="subchild.icon">
<v-icon v-text="subchild.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
{{ subchild.title }}
<v-chip v-if="subchild.badge" class="ml-2" color="primary" x-small label v-html="displayBadge(subchild.badge)"></v-chip>
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-group>
<v-divider v-else-if="child.type == 'divider'" />
<v-list-item v-else :key="child.title" link :to="{path: child.path}" :exact="child.exact">
<v-list-item-icon v-if="child.icon">
<v-icon v-text="child.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>
{{ child.title }}
<v-chip v-if="child.badge" class="ml-2" color="primary" x-small label v-html="displayBadge(child.badge)"></v-chip>
</v-list-item-title>
</v-list-item-content>
</v-list-item>
@ -195,6 +210,15 @@ export default {
setIsThemeDark () {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark
this.$store.commit('setIsThemeDark', this.$vuetify.theme.dark)
},
displayBadge (badge) {
if (badge == 'mySpells') {
return this.$store.state.mySpells.spells.length
} else if (badge == 'myMonsters') {
return this.$store.state.myMonsters.monsters.length
} else if (badge == 'myMagicItems') {
return this.$store.state.myMagicItems.magicItems.length
}
}
}
}

View file

@ -5,7 +5,7 @@
<v-btn class="hidden-sm-and-down site-title" text link :to="{ path: '/' }"><img src="/dragon_blanc.svg" />&nbsp;{{ $site.title }}</v-btn>
</v-toolbar-title>
<SRDSearchBox v-if="$site.themeConfig.search !== false && $page.frontmatter.search !== false" />
<v-spacer />
<v-spacer class="hidden-sm-and-down" />
<v-btn class="hidden-sm-and-down" @click.stop="setIsThemeDark" icon>
<v-icon v-html="$vuetify.theme.dark ? 'mdi-brightness-4' : 'mdi-brightness-7'"></v-icon>
</v-btn>

View file

@ -2,37 +2,64 @@
<main class="page content">
<div class="theme-default-content">
<h1>{{ $page.title }}</h1>
<template v-if="!hideTitle">
<h1 v-if="!isList">{{ spell.title }}</h1>
<h2 v-else>{{ spell.title }}</h2>
</template>
<div class="spell-details">
<div class="spell-school-level" v-html="displaySchoolLevel()"></div>
<div class="spell-casting-time"><strong>Temps d'incantation</strong> : {{ $page.frontmatter.casting_time }}</div>
<div class="spell-range"><strong>Portée</strong> : {{ $page.frontmatter.range }}</div>
<div class="spell-school-level title" v-html="displaySchoolLevel()"></div>
<div class="spell-casting-time"><strong>Temps d'incantation</strong> : {{ spell.frontmatter.casting_time }}</div>
<div class="spell-range"><strong>Portée</strong> : {{ spell.frontmatter.range }}</div>
<div class="spell-components"><strong>Composantes</strong> :
<template v-if="$page.frontmatter.components.verbal">V</template><template v-if="$page.frontmatter.components.somatic || $page.frontmatter.components.material">,</template>
<template v-if="$page.frontmatter.components.somatic">S</template><template v-if="$page.frontmatter.components.material">,</template>
<template v-if="$page.frontmatter.components.material">M</template>
<template v-if="$page.frontmatter.components.materials">({{$page.frontmatter.components.materials}})</template>
<template v-if="spell.frontmatter.components.verbal">V</template><template v-if="spell.frontmatter.components.somatic || spell.frontmatter.components.material">,</template>
<template v-if="spell.frontmatter.components.somatic">S</template><template v-if="spell.frontmatter.components.material">,</template>
<template v-if="spell.frontmatter.components.material">M</template>
<template v-if="spell.frontmatter.components.material && spell.frontmatter.components.materials">({{spell.frontmatter.components.materials}})</template>
</div>
<div class="spell-duration"><strong>Durée</strong> : <span v-if="spell.frontmatter.concentration">concentration, </span>{{ spell.frontmatter.duration }}</div>
<div class="spell-classes" v-if="!isShort">
<strong>Classe</strong> : <span v-for="(c, idx) in spell.frontmatter.classes" :key="idx">{{c}}<template v-if="idx != spell.frontmatter.classes.length-1">, </template><template v-if="idx == spell.frontmatter.classes.length-1 && spell.frontmatter.customClasses">, </template></span>
<template v-if="spell.frontmatter.customClasses">
<template>{{ spell.frontmatter.customClasses }}</template>
</template>
</div>
<div class="spell-duration"><strong>Durée</strong> : <span v-if="$page.frontmatter.concentration">concentration, </span>{{ $page.frontmatter.duration }}</div>
<div class="spell-classes"><strong>Classe</strong> : <span v-for="(c, idx) in $page.frontmatter.classes" :key="idx">{{c}}<template v-if="idx != $page.frontmatter.classes.length-1">, </template></span></div>
</div>
</div>
<Content class="mt-4" />
<template v-if="!isShort">
<Content v-if="!spell.custom" :pageKey="spell.key" class="mt-4" />
<div v-else v-html="md.render(spell.content)" class="mt-4"></div>
</template>
<div v-else v-html="spell.frontmatter.description" class="mt-4"></div>
<p v-if="$page.frontmatter.source" class="source">Source : <em>{{ $page.frontmatter.source }}</em></p>
<p v-if="spell.frontmatter.source" class="source">Source : <em>{{ spell.frontmatter.source }}</em></p>
</main>
</template>
<script>
import { displaySchoolLevel } from '@theme/util/spellHelpers'
import MarkdownIt from 'markdown-it'
export default {
name: 'Spell',
props: ['spell', 'isList', 'hideTitle', 'isShort'],
data () {
return {
md: new MarkdownIt()
}
},
methods: {
displaySchoolLevel () {
return displaySchoolLevel(this.$page.frontmatter)
return displaySchoolLevel(this.spell.frontmatter)
}
},
mounted () {
// console.log(this.spell)
}
}
</script>

View file

@ -0,0 +1,91 @@
<template>
<v-card class="d-flex flex-column mb-6 spell-card">
<v-card-title>
{{ spell.title }}
<v-spacer></v-spacer>
<v-card-actions v-if="showActions">
<v-btn dark icon class="d-print-none mr-2" link :to="{ path: '/creation-de-sort/', query: { key: spell.key } }"><v-icon>mdi-pencil</v-icon></v-btn>
<v-btn dark icon class="d-print-none" @click="$store.commit('mySpells/removeSpell', spell)"><v-icon>mdi-delete</v-icon></v-btn>
</v-card-actions>
</v-card-title>
<v-card-text>
<div class="spell-details mt-3">
<div class="spell-school-level title" v-html="displaySchoolLevel()"></div>
<v-row>
<v-col cols="12" md="6" class="pb-0">
<div class="spell-casting-time"><strong>Temps d'incantation</strong> : {{ spell.frontmatter.casting_time }}</div>
</v-col>
<v-col cols="12" md="6" class="pb-0">
<div class="spell-range"><strong>Portée</strong> : {{ spell.frontmatter.range }}</div>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6" class="pb-0">
<div class="spell-components"><strong>Composantes</strong> :
<template v-if="spell.frontmatter.components.verbal">V</template><template v-if="spell.frontmatter.components.somatic || spell.frontmatter.components.material">,</template>
<template v-if="spell.frontmatter.components.somatic">S</template><template v-if="spell.frontmatter.components.material">,</template>
<template v-if="spell.frontmatter.components.material">M</template>
<template v-if="spell.frontmatter.components.material && spell.frontmatter.components.materials">({{spell.frontmatter.components.materials}})</template>
</div>
</v-col>
<v-col cols="12" md="6" class="pb-0">
<div class="spell-duration"><strong>Durée</strong> : <span v-if="spell.frontmatter.concentration">concentration, </span>{{ spell.frontmatter.duration }}</div>
</v-col>
</v-row>
</div>
<v-divider class="mt-3" />
<Content v-if="!spell.custom" :pageKey="spell.key" class="mt-4" />
<div v-else v-html="md.render(spell.content)" class="mt-4"></div>
<div class="spell-classes" v-if="!isShort">
<strong>Classe</strong> : <span v-for="(c, idx) in spell.frontmatter.classes" :key="idx">{{c}}<template v-if="idx != spell.frontmatter.classes.length-1">, </template><template v-if="idx == spell.frontmatter.classes.length-1 && spell.frontmatter.customClasses">, </template></span>
<template v-if="spell.frontmatter.customClasses">
<template>{{ spell.frontmatter.customClasses }}</template>
</template>
</div>
<p v-if="spell.frontmatter.source" class="source">Source : <em>{{ spell.frontmatter.source }}</em></p>
</v-card-text>
</v-card>
</template>
<script>
import { displaySchoolLevel } from '@theme/util/spellHelpers'
import MarkdownIt from 'markdown-it'
export default {
name: 'SpellCard',
props: ['spell', 'showActions', 'isShort'],
data () {
return {
md: new MarkdownIt()
}
},
methods: {
displaySchoolLevel () {
return displaySchoolLevel(this.spell.frontmatter)
}
},
}
</script>
<style lang="scss">
@import '../styles/colors';
.spell-card {
.v-card__title {
background-color: $color-dragon;
color: #fff;
padding-top: 0;
padding-bottom: 0;
}
p.source {
margin-bottom: 0;
}
}
</style>