mirror of
https://github.com/em-squared/5e-drs.git
synced 2025-10-29 20:54:19 +00:00
WIP bestiaire
This commit is contained in:
parent
bde611ae9b
commit
510db9f858
58 changed files with 29311 additions and 365 deletions
|
|
@ -25,6 +25,25 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Unique ID of current classification
|
||||
id: 'monster',
|
||||
// Meta title for spell list page
|
||||
title: 'Bestiaire',
|
||||
// Target directory
|
||||
dirname: '_monsters',
|
||||
// Path of the `entry page` (or `list page`)
|
||||
path: '/bestiaire/',
|
||||
layout: 'MonstersLayout',
|
||||
itemLayout: 'MonsterLayout',
|
||||
itemPermalink: '/bestiaire/:slug',
|
||||
pagination: {
|
||||
lengthPerPage: 1000,
|
||||
sorter: (prev, next) => {
|
||||
return prev.path - next.path
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Unique ID of current classification
|
||||
id: 'magicitem',
|
||||
|
|
@ -52,15 +71,18 @@ module.exports = {
|
|||
'sitemap', {
|
||||
hostname: 'https://heros-et-dragons.fr'
|
||||
},
|
||||
]
|
||||
],
|
||||
],
|
||||
extendPageData ($page) {
|
||||
$page.rawContent = ($page._strippedContent)
|
||||
},
|
||||
markdown: {
|
||||
anchor: {
|
||||
permalinkBefore: false,
|
||||
permalinkSymbol: '<i class="v-icon notranslate mdi mdi-link-variant"></i>'
|
||||
},
|
||||
extendMarkdown: md => {
|
||||
md.use(require('markdown-it-div'))
|
||||
md.use(require('markdown-it-div'), {marker: "§"})
|
||||
md.use(require('markdown-it-multimd-table'), {
|
||||
multiline: true,
|
||||
rowspan: true,
|
||||
|
|
@ -357,6 +379,23 @@ module.exports = {
|
|||
{
|
||||
title: 'Pour les meneurs',
|
||||
children: [
|
||||
{
|
||||
title: "Créatures & oppositions",
|
||||
children: [
|
||||
{
|
||||
title: "Comprendre le profil technique des monstres",
|
||||
path: '/comprendre-le-profil-technique-des-monstres/'
|
||||
},
|
||||
{
|
||||
title: "Inventer un monstre ou un PNJ",
|
||||
path: '/inventer-un-monstre-ou-un-pnj/'
|
||||
},
|
||||
{
|
||||
title: "Construire une rencontre",
|
||||
path: '/construire-une-rencontre/'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Les trésors",
|
||||
path: '/les-tresors/'
|
||||
|
|
|
|||
19
docs/.vuepress/data/stats.js
Normal file
19
docs/.vuepress/data/stats.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
export const stats = {
|
||||
abilities: {
|
||||
for: {label: 'Force', abbr: 'For'},
|
||||
dex: {label: 'Dextérité', abbr: 'Dex'},
|
||||
con: {label: 'Constitution', abbr: 'Con'},
|
||||
int: {label: 'Intelligence', abbr: 'Int'},
|
||||
sag: {label: 'Sagesse', abbr: 'Sag'},
|
||||
cha: {label: 'Charisme', abbr: 'Cha'},
|
||||
},
|
||||
|
||||
sizes: {
|
||||
tp: { label: "Très petit", abbr: "TP", hitDie: 4 },
|
||||
p: { label: "Petit", abbr: "P", hitDie: 6 },
|
||||
m: { label: "Moyen", abbr: "M", hitDie: 8 },
|
||||
g: { label: "Grand", abbr: "G", hitDie: 10 },
|
||||
tg: { label: "Très grand", abbr: "TG", hitDie: 12 },
|
||||
gig: { label: "Gigantesque", abbr: "Gig", hitDie: 20 },
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ export default new Vuex.Store({
|
|||
},
|
||||
|
||||
state: {
|
||||
loading: false,
|
||||
drawer: true,
|
||||
rightDrawer: false,
|
||||
hasRightDrawer: false,
|
||||
|
|
@ -21,6 +22,7 @@ export default new Vuex.Store({
|
|||
},
|
||||
|
||||
getters: {
|
||||
loading: state => state.loading,
|
||||
drawer: state => state.drawer,
|
||||
rightDrawer: state => state.rightDrawer,
|
||||
hasRightDrawer: state => state.hasRightDrawer,
|
||||
|
|
@ -29,6 +31,9 @@ export default new Vuex.Store({
|
|||
},
|
||||
|
||||
actions: {
|
||||
updateLoading: ({ commit }, payload) => {
|
||||
commit('setLoading', payload)
|
||||
},
|
||||
updateDrawer: ({ commit }, payload) => {
|
||||
commit('setDrawer', payload)
|
||||
},
|
||||
|
|
@ -47,6 +52,9 @@ export default new Vuex.Store({
|
|||
},
|
||||
|
||||
mutations: {
|
||||
setLoading: (state, payload) => {
|
||||
state.loading = payload
|
||||
},
|
||||
setDrawer: (state, payload) => {
|
||||
state.drawer = payload
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@
|
|||
<div class="theme-default-content">
|
||||
<h1>{{ $page.title }}</h1>
|
||||
<div class="magic-item-details">
|
||||
<span>{{ $page.frontmatter.type }}</span>
|
||||
<span v-if="$page.frontmatter.subtype"> ({{ $page.frontmatter.subtype }})</span>
|
||||
<span>, {{ $page.frontmatter.rarity }}</span>
|
||||
<span v-if="$page.frontmatter.attunement"> ({{ $page.frontmatter.attunement }})</span>
|
||||
{{displayItemMeta()}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -19,8 +16,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
import {displayItemMeta} from '@theme/util/magicItemHelpers'
|
||||
|
||||
export default {
|
||||
methods : {
|
||||
displayItemMeta () {
|
||||
return displayItemMeta(this.$page.frontmatter)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
140
docs/.vuepress/theme/components/Monster.vue
Normal file
140
docs/.vuepress/theme/components/Monster.vue
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
<template>
|
||||
<main class="page content">
|
||||
|
||||
<div class="theme-default-content">
|
||||
<h1>{{ $page.title }}</h1>
|
||||
<div class="monster-hit-points">
|
||||
<strong>Points de vie</strong>
|
||||
<span>{{ displayHP() }}</span>
|
||||
</div>
|
||||
<div class="monster-details">
|
||||
<!-- Statblock -->
|
||||
<div class="monster-ability-scores">
|
||||
<div class="ability-str">
|
||||
{{ displayAbilityScore(monster.abilityScores.for) }}
|
||||
</div>
|
||||
<div class="ability-dex">
|
||||
{{ displayAbilityScore(monster.abilityScores.dex) }}
|
||||
</div>
|
||||
<div class="ability-con">
|
||||
{{ displayAbilityScore(monster.abilityScores.con) }}
|
||||
</div>
|
||||
<div class="ability-int">
|
||||
{{ displayAbilityScore(monster.abilityScores.int) }}
|
||||
</div>
|
||||
<div class="ability-wis">
|
||||
{{ displayAbilityScore(monster.abilityScores.sag) }}
|
||||
</div>
|
||||
<div class="ability-cha">
|
||||
{{ displayAbilityScore(monster.abilityScores.cha) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="monster-saving-throws">
|
||||
<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">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<Content slot-key="special-traits" class="mt-4" />
|
||||
<Content slot-key="actions" class="mt-4" />
|
||||
<Content slot-key="reactions" class="mt-4" />
|
||||
<Content slot-key="legendary-actions" class="mt-4" />
|
||||
<Content/>
|
||||
|
||||
<p v-if="$page.frontmatter.source" class="source">Source : <em>{{ monster.source }}</em></p>
|
||||
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
displayBonus,
|
||||
getModifier,
|
||||
displayAbilityScore,
|
||||
getProficiencyBonus
|
||||
} from '@theme/util/monsterHelpers'
|
||||
|
||||
import {stats} from '../../data/stats.js'
|
||||
|
||||
export default {
|
||||
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
monster () {
|
||||
return this.$page.frontmatter
|
||||
},
|
||||
proficiencyBonus () {
|
||||
return this.getProficiencyBonus()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
displayAbilityScore (value) { return displayAbilityScore(value) },
|
||||
getModifier (value) { return getModifier(value) },
|
||||
getProficiencyBonus () { return getProficiencyBonus(this.monster.level) },
|
||||
|
||||
displaySavingThrowBonus (ability) {
|
||||
let result = stats.abilities[ability].abbr
|
||||
let bonus = displayBonus(getModifier(this.monster.abilityScores[ability]) + this.proficiencyBonus)
|
||||
result += ' ' + bonus
|
||||
return result
|
||||
},
|
||||
|
||||
displaySkillBonus (skill) {
|
||||
let result = skill.name
|
||||
let bonus = getModifier(this.monster.abilityScores[skill.ability]) + this.proficiencyBonus
|
||||
if (skill.isExpert) {
|
||||
bonus += this.proficiencyBonus // Bonus de maître doublé pour les experts
|
||||
}
|
||||
bonus = displayBonus(bonus)
|
||||
result += ' ' + bonus
|
||||
return result
|
||||
},
|
||||
|
||||
displayHP () {
|
||||
if (this.monster.customHP) {
|
||||
return this.monster.customHP
|
||||
} else if (this.monster.level) {
|
||||
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 hitDiceBonus = 1
|
||||
if (this.monster.level > 1) {
|
||||
hitDiceBonus = Math.floor(this.monster.level / 2)
|
||||
}
|
||||
let averageHP = this.monster.level * (hitDieSize / 2) + this.monster.level * getModifier(this.monster.abilityScores.con) + hitDiceBonus
|
||||
let conMod = ""
|
||||
if (getModifier(this.monster.abilityScores.con) != 0) {
|
||||
conMod = this.monster.level * getModifier(this.monster.abilityScores.con)
|
||||
conMod = displayBonus(conMod)
|
||||
}
|
||||
return averageHP + ' (' + this.monster.level + "d" + hitDieSize + conMod + ')'
|
||||
}
|
||||
return ""
|
||||
},
|
||||
},
|
||||
|
||||
mounted () {
|
||||
//console.log(this.$page)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
<script>
|
||||
import matchQuery from './match-query'
|
||||
import { displaySchoolLevel } from '@theme/util/spellHelpers'
|
||||
import { displayItemMeta } from '@theme/util/magicItemHelpers'
|
||||
|
||||
/* global SEARCH_MAX_SUGGESTIONS, SEARCH_PATHS, SEARCH_HOTKEYS */
|
||||
export default {
|
||||
|
|
@ -111,10 +112,16 @@ export default {
|
|||
title: p.title,
|
||||
path: p.path
|
||||
}))
|
||||
} else if (p.pid && p.pid == 'magicitem') {
|
||||
res.push(Object.assign({}, p, {
|
||||
subtitle: displayItemMeta(p.frontmatter, true),
|
||||
title: p.title,
|
||||
path: p.path
|
||||
}))
|
||||
} else {
|
||||
res.push(p)
|
||||
}
|
||||
} else if (p.headers) {
|
||||
} else if (p.headers && p.pid != 'monster') { // Only parse relevent headers. Monster headers are not
|
||||
for (let j = 0; j < p.headers.length; j++) {
|
||||
if (res.length >= max) break
|
||||
const h = p.headers[j]
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<v-overlay :value="loading">
|
||||
<v-progress-circular indeterminate size="64"></v-progress-circular>
|
||||
</v-overlay>
|
||||
</v-content>
|
||||
</v-app>
|
||||
</template>
|
||||
|
|
@ -40,6 +43,9 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
loading () {
|
||||
return this.$store.state.loading
|
||||
},
|
||||
hasRightDrawer() {
|
||||
return this.$store.state.hasRightDrawer
|
||||
}
|
||||
|
|
|
|||
29
docs/.vuepress/theme/layouts/MonsterLayout.vue
Normal file
29
docs/.vuepress/theme/layouts/MonsterLayout.vue
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<div class="monster">
|
||||
<Breadcrumb />
|
||||
<Monster />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Breadcrumb from '@theme/components/Breadcrumb'
|
||||
import Monster from '@theme/components/Monster'
|
||||
|
||||
export default {
|
||||
name: 'MonsterLayout',
|
||||
|
||||
components: {
|
||||
Breadcrumb,
|
||||
Monster
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$store.commit('setHasRightDrawer', false)
|
||||
this.$store.commit('setRightDrawer', false)
|
||||
this.$store.commit('setInRightDrawer', null)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
15
docs/.vuepress/theme/util/magicItemHelpers.js
Normal file
15
docs/.vuepress/theme/util/magicItemHelpers.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export function displayItemMeta (item, short = false) {
|
||||
let result = item.type
|
||||
if (item.subtype) {
|
||||
result += ' (' + item.subtype + ')'
|
||||
}
|
||||
result += ', ' + item.rarity
|
||||
if (item.attunement) {
|
||||
if (short) {
|
||||
result += ' (harmonisation requise)'
|
||||
} else {
|
||||
result += ' (' + item.attunement + ')'
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
26
docs/.vuepress/theme/util/monsterHelpers.js
Normal file
26
docs/.vuepress/theme/util/monsterHelpers.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Calcul du modificateur de caractéristique
|
||||
export function getModifier (score) {
|
||||
return Math.floor((score - 10) / 2)
|
||||
}
|
||||
|
||||
// Ajoute un + devant les valeurs positives pour l'affichage
|
||||
export function displayBonus (value) {
|
||||
if (value >= 0) {
|
||||
value = '+' + value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Affichage d'un score de caractéristiques sous la forme 16 (+3)
|
||||
export function displayAbilityScore (score) {
|
||||
let modifier = getModifier(score)
|
||||
if (modifier >= 0) {
|
||||
modifier = '+' + modifier
|
||||
}
|
||||
return score + ' (' + modifier + ')'
|
||||
}
|
||||
|
||||
// Calcul du bonus de maîtrise en fonction du niveau
|
||||
export function getProficiencyBonus (level) {
|
||||
return Math.ceil(level / 4) + 1
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue