Compare commits
1 Commits
13.1.0
...
LeRatierBr
| Author | SHA1 | Date | |
|---|---|---|---|
| b58995014c |
@@ -1,63 +0,0 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||
|
||||
#- uses: actions/checkout@v3
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Substitute the Manifest and Download URLs in the system.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: 'system.json'
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
manifest: https://www.uberwald.me/gitea/public/fvtt-yggdrasill/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-yggdrasill.zip
|
||||
|
||||
# Create a zip file with all files required by the module to add to the release
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./fvtt-yggdrasill.zip system.json README.md fonts/ images/ lang/ less/ modules/ packs/ styles/ templates/ template.json
|
||||
|
||||
- name: setup go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
|
||||
- name: Use Go Action
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
./fvtt-yggdrasill.zip
|
||||
system.json
|
||||
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'
|
||||
|
||||
- name: Publish to Foundry server
|
||||
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
|
||||
with:
|
||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
||||
id: 'fvtt-yggdrasill'
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: 'https://www.uberwald.me/gitea/public/fvtt-yggdrasill/releases/download/latest/system.json'
|
||||
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-yggdrasill.zip'
|
||||
compatibility-minimum: '13'
|
||||
compatibility-verified: '13'
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
.history/
|
||||
node_modules/
|
||||
packs/_source/
|
||||
@@ -17,7 +17,7 @@ test:
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- zip fvtt-yggdrasill.zip -r *.js *.json *.md fonts images packs module styles templates -x ".*"
|
||||
- zip fvtt-yggdrasill.zip -r *.js *.json *.md module styles templates -x ".*"
|
||||
artifacts:
|
||||
name: fvtt-yggdrasill
|
||||
when: on_success
|
||||
|
||||
28
LICENSE.md
28
LICENSE.md
@@ -1,28 +0,0 @@
|
||||
# Licence
|
||||
|
||||
## Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)
|
||||
|
||||
Ce système Foundry VTT pour Yggdrasill est sous licence Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International.
|
||||
|
||||
### Vous êtes autorisé à :
|
||||
|
||||
- **Partager** — copier et redistribuer le matériel sous quelque support ou format que ce soit
|
||||
|
||||
### Selon les conditions suivantes :
|
||||
|
||||
- **Attribution** — Vous devez créditer l'œuvre, fournir un lien vers la licence et indiquer si des modifications ont été effectuées. Vous devez indiquer ces informations par tous les moyens raisonnables, sans toutefois suggérer que l'offrant vous soutient ou soutient la façon dont vous avez utilisé son œuvre.
|
||||
|
||||
- **Pas d'Utilisation Commerciale** — Vous n'êtes pas autorisé à faire un usage commercial de cette œuvre, tout ou partie du matériel la composant.
|
||||
|
||||
- **Pas de modifications** — Dans le cas où vous effectuez un remix, que vous transformez, ou créez à partir du matériel composant l'œuvre originale, vous n'êtes pas autorisé à distribuer ou mettre à disposition l'œuvre modifiée.
|
||||
|
||||
- **Pas de restrictions complémentaires** — Vous n'êtes pas autorisé à appliquer des conditions légales ou des mesures techniques qui restreindraient légalement autrui à utiliser l'œuvre dans les conditions décrites par la licence.
|
||||
|
||||
### Texte complet de la licence
|
||||
|
||||
Pour consulter une copie complète de cette licence, visitez :
|
||||
https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode.fr
|
||||
|
||||
---
|
||||
|
||||
**Note** : Ce système est un projet non officiel et n'est pas affilié à l'éditeur du jeu de rôle Yggdrasill.
|
||||
11
README.md
11
README.md
@@ -1,11 +1,8 @@
|
||||
# Yggdrasill (7ième Cercle) pour FoundryVTT
|
||||
# Système Yggdrasill pour FoundryVTT
|
||||
|
||||
Ce système non-officiel est le portage du JdR Yggdrasill (7ième Cercle) pour le système FoundryVTT.
|
||||
|
||||
https://www.7emecercle.com/7C_site/jeux-de-roles/yggdrasill/
|
||||
Ce système est l'implémentation du jeu de rôle Yggdrasill (7ième Cercle) pour FoundryVTT.
|
||||
|
||||
Le livre de base d'Yggdrasill, disponible sur le site de 7ième cercle est nécessaire pour jouer.
|
||||
Yggdrasill le jeu de rôle est la propriété de 7ième Cercle.
|
||||
|
||||
The Vinque font used in this system is properly licensed for Web usage. The proof of the license agreement can be provided thru mail from here or on the French Discord (user @Thelvyn).
|
||||
Ce système n'est pas officiel, et nécessite le livre de base pour jouer.
|
||||
|
||||
Yggdrasill le JDR est la propriété de 7ième Cercle.
|
||||
|
||||
35
gulpfile.js
35
gulpfile.js
@@ -1,35 +0,0 @@
|
||||
const gulp = require('gulp');
|
||||
const less = require('gulp-less');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
|
||||
// Paths
|
||||
const paths = {
|
||||
styles: {
|
||||
src: 'less/**/*.less',
|
||||
dest: 'styles/'
|
||||
}
|
||||
};
|
||||
|
||||
// Compile LESS to CSS
|
||||
function styles() {
|
||||
return gulp.src('less/yggdrasill.less')
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(less())
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest(paths.styles.dest));
|
||||
}
|
||||
|
||||
// Watch files
|
||||
function watchFiles() {
|
||||
gulp.watch(paths.styles.src, styles);
|
||||
}
|
||||
|
||||
// Define complex tasks
|
||||
const build = gulp.series(styles);
|
||||
const watch = gulp.series(build, watchFiles);
|
||||
|
||||
// Export tasks
|
||||
exports.styles = styles;
|
||||
exports.build = build;
|
||||
exports.watch = watch;
|
||||
exports.default = build;
|
||||
27
lang/fr.json
27
lang/fr.json
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"TYPES": {
|
||||
"Item": {
|
||||
"competence": "Compétence",
|
||||
"don": "Don",
|
||||
"faiblesse": "Faiblesse",
|
||||
"blessure": "Blessure",
|
||||
"maladie": "Maladie",
|
||||
"poison": "Poison",
|
||||
"prouesse": "Prouesse",
|
||||
"sortsejdr": "Sort Sejdr",
|
||||
"sortgaldr": "Sort Galdr",
|
||||
"rune": "Rune",
|
||||
"armecc": "Arme de corps à corps",
|
||||
"armedist": "Arme de distance",
|
||||
"armure": "Armure",
|
||||
"bouclier": "Bouclier",
|
||||
"equipement": "Équipement",
|
||||
"monnaie": "Monnaie",
|
||||
"effetmagique": "Effet magique"
|
||||
},
|
||||
"Actor": {
|
||||
"personnage": "Personnage",
|
||||
"figurant": "Figurant"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,534 +0,0 @@
|
||||
/* ========================================
|
||||
CHAT MESSAGE STYLES - Viking Theme
|
||||
======================================== */
|
||||
|
||||
.ygg-chat-card {
|
||||
font-family: "Vinque", serif;
|
||||
background: linear-gradient(135deg, rgba(245, 235, 220, 0.95) 0%, rgba(230, 220, 205, 0.95) 100%);
|
||||
border: 3px solid #4a0404;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 0 20px rgba(218, 165, 32, 0.1);
|
||||
overflow: hidden;
|
||||
margin: 0.3rem 0;
|
||||
|
||||
/* Header Section */
|
||||
.ygg-chat-header {
|
||||
background: linear-gradient(135deg, #4a0404 0%, #6b0505 100%);
|
||||
color: #f5ead3;
|
||||
padding: 0.5rem 0.75rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
border-bottom: 2px solid #daa520;
|
||||
|
||||
.header-decorative-border {
|
||||
flex: 1;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent 0%, #daa520 50%, transparent 100%);
|
||||
}
|
||||
|
||||
.actor-portrait {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #daa520;
|
||||
box-shadow: 0 0 8px rgba(218, 165, 32, 0.5);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.actor-name {
|
||||
margin: 0;
|
||||
font-family: "CaslonAntique", serif;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
|
||||
color: #f5ead3;
|
||||
}
|
||||
|
||||
.roll-type {
|
||||
font-size: 0.75rem;
|
||||
font-weight: normal;
|
||||
opacity: 0.9;
|
||||
margin-top: -0.1rem;
|
||||
|
||||
i {
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Roll Description */
|
||||
.ygg-roll-description {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
border-bottom: 1px solid rgba(74, 4, 4, 0.2);
|
||||
font-size: 0.9rem;
|
||||
|
||||
strong {
|
||||
color: #4a0404;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.dice-formula,
|
||||
.skill-level,
|
||||
.carac-detail,
|
||||
.skill-detail {
|
||||
color: #555;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dice Section */
|
||||
.ygg-dice-section {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(255, 250, 240, 0.6);
|
||||
border-bottom: 1px solid rgba(74, 4, 4, 0.2);
|
||||
|
||||
.dice-results,
|
||||
.furor-results {
|
||||
margin-bottom: 0.4rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: #4a0404;
|
||||
margin-bottom: 0.3rem;
|
||||
font-size: 0.85rem;
|
||||
|
||||
i {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dice-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.die-result {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
padding: 0 0.4rem;
|
||||
background: linear-gradient(135deg, #fff 0%, #f5f5f5 100%);
|
||||
border: 2px solid #8b4513;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), inset 0 1px 2px rgba(255, 255, 255, 0.5);
|
||||
|
||||
&.high {
|
||||
background: linear-gradient(135deg, #90ee90 0%, #7ad87a 100%);
|
||||
border-color: #228b22;
|
||||
color: #004d00;
|
||||
}
|
||||
|
||||
&.low {
|
||||
background: linear-gradient(135deg, #ffcccb 0%, #ffb3b3 100%);
|
||||
border-color: #8b0000;
|
||||
color: #4d0000;
|
||||
}
|
||||
|
||||
&.furor {
|
||||
background: linear-gradient(135deg, #ff6b35 0%, #ff4500 100%);
|
||||
border-color: #8b0000;
|
||||
color: #fff;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculation Breakdown */
|
||||
.ygg-calculation {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-bottom: 1px solid rgba(74, 4, 4, 0.2);
|
||||
|
||||
.calc-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem 0;
|
||||
border-bottom: 1px dashed rgba(74, 4, 4, 0.15);
|
||||
font-size: 0.85rem;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.furor-row .calc-label i {
|
||||
color: #ff4500;
|
||||
}
|
||||
}
|
||||
|
||||
.calc-label {
|
||||
font-weight: 600;
|
||||
color: #4a0404;
|
||||
}
|
||||
|
||||
.calc-value {
|
||||
font-weight: bold;
|
||||
font-family: "MedievalSharp", serif;
|
||||
|
||||
&.negative {
|
||||
color: #8b0000;
|
||||
}
|
||||
|
||||
&.positive {
|
||||
color: #228b22;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Final Result */
|
||||
.ygg-result {
|
||||
padding: 0.75rem;
|
||||
background: linear-gradient(135deg, rgba(240, 230, 210, 0.8) 0%, rgba(230, 220, 200, 0.8) 100%);
|
||||
border-top: 3px double #4a0404;
|
||||
|
||||
&.critical-success {
|
||||
background: linear-gradient(135deg, rgba(144, 238, 144, 0.3) 0%, rgba(122, 216, 122, 0.3) 100%);
|
||||
border-top-color: #228b22;
|
||||
}
|
||||
|
||||
&.critical-failure {
|
||||
background: linear-gradient(135deg, rgba(255, 99, 71, 0.3) 0%, rgba(220, 20, 60, 0.3) 100%);
|
||||
border-top-color: #8b0000;
|
||||
}
|
||||
|
||||
&.success {
|
||||
background: linear-gradient(135deg, rgba(173, 216, 230, 0.2) 0%, rgba(135, 206, 235, 0.2) 100%);
|
||||
}
|
||||
|
||||
.result-total {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.4rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 2px solid rgba(74, 4, 4, 0.3);
|
||||
|
||||
.result-label {
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
color: #4a0404;
|
||||
font-family: "CaslonAntique", serif;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-size: 1.7rem;
|
||||
font-weight: bold;
|
||||
font-family: "MedievalSharp", serif;
|
||||
color: #4a0404;
|
||||
text-shadow: 2px 2px 4px rgba(218, 165, 32, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.result-vs {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
|
||||
.vs-label {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.vs-value {
|
||||
font-weight: bold;
|
||||
color: #4a0404;
|
||||
}
|
||||
}
|
||||
|
||||
.result-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 5px;
|
||||
border: 2px solid rgba(74, 4, 4, 0.2);
|
||||
|
||||
.status-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex-shrink: 0;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
font-family: "CaslonAntique", serif;
|
||||
|
||||
&.critical {
|
||||
color: #228b22;
|
||||
text-shadow: 0 0 8px rgba(34, 139, 34, 0.5);
|
||||
}
|
||||
|
||||
&.success {
|
||||
color: #4682b4;
|
||||
}
|
||||
|
||||
&.failure {
|
||||
color: #8b0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Damage Section */
|
||||
.ygg-damage {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: linear-gradient(135deg, rgba(139, 0, 0, 0.1) 0%, rgba(178, 34, 34, 0.1) 100%);
|
||||
border-top: 2px solid #8b0000;
|
||||
|
||||
.damage-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.4rem;
|
||||
|
||||
i {
|
||||
color: #8b0000;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.damage-label {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: #4a0404;
|
||||
}
|
||||
}
|
||||
|
||||
.damage-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #8b0000;
|
||||
font-family: "MedievalSharp", serif;
|
||||
text-shadow: 2px 2px 4px rgba(139, 0, 0, 0.2);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.damage-detail {
|
||||
font-size: 0.75rem;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.damage-note {
|
||||
margin-top: 0.4rem;
|
||||
padding: 0.3rem;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-left: 3px solid #daa520;
|
||||
font-size: 0.8rem;
|
||||
color: #4a0404;
|
||||
}
|
||||
}
|
||||
|
||||
/* Weapon Details */
|
||||
.ygg-weapon-details {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: linear-gradient(135deg, rgba(139, 69, 19, 0.08) 0%, rgba(160, 82, 45, 0.08) 100%);
|
||||
border-top: 2px solid #8b4513;
|
||||
|
||||
.weapon-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid rgba(139, 69, 19, 0.3);
|
||||
|
||||
&.collapsible {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background 0.2s ease;
|
||||
margin: -0.5rem -0.75rem 0;
|
||||
padding: 0.5rem 0.75rem 0.4rem;
|
||||
border-bottom: none;
|
||||
|
||||
&:hover {
|
||||
background: rgba(139, 69, 19, 0.1);
|
||||
}
|
||||
|
||||
.toggle-icon {
|
||||
margin-left: auto;
|
||||
transition: transform 0.3s ease;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
&.expanded .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
color: #8b4513;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: #4a0404;
|
||||
font-family: "CaslonAntique", serif;
|
||||
}
|
||||
}
|
||||
|
||||
.weapon-content {
|
||||
max-height: 500px;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease, opacity 0.3s ease;
|
||||
opacity: 1;
|
||||
|
||||
&.collapsed {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.weapon-properties {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.3rem 0.5rem;
|
||||
}
|
||||
|
||||
.weapon-property {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
font-size: 0.85rem;
|
||||
|
||||
.property-label {
|
||||
font-weight: 600;
|
||||
color: #4a0404;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.property-value {
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.weapon-description {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 5px;
|
||||
border-left: 3px solid #8b4513;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.4;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
/* Magic Details */
|
||||
.ygg-magic-details {
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: linear-gradient(135deg, rgba(138, 43, 226, 0.08) 0%, rgba(148, 0, 211, 0.08) 100%);
|
||||
border-top: 2px solid #8a2be2;
|
||||
|
||||
.magic-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid rgba(138, 43, 226, 0.3);
|
||||
|
||||
&.collapsible {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background 0.2s ease;
|
||||
margin: -0.5rem -0.75rem 0;
|
||||
padding: 0.5rem 0.75rem 0.4rem;
|
||||
border-bottom: none;
|
||||
|
||||
&:hover {
|
||||
background: rgba(138, 43, 226, 0.1);
|
||||
}
|
||||
|
||||
.toggle-icon {
|
||||
margin-left: auto;
|
||||
transition: transform 0.3s ease;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
&.expanded .toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
color: #8a2be2;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: #4a0404;
|
||||
font-family: "CaslonAntique", serif;
|
||||
}
|
||||
}
|
||||
|
||||
.magic-content {
|
||||
max-height: 500px;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease, opacity 0.3s ease;
|
||||
opacity: 1;
|
||||
|
||||
&.collapsed {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.magic-property {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.3rem;
|
||||
font-size: 0.85rem;
|
||||
|
||||
.property-label {
|
||||
font-weight: 600;
|
||||
color: #4a0404;
|
||||
min-width: 110px;
|
||||
}
|
||||
|
||||
.property-value {
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.rune-details {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
padding: 0.4rem;
|
||||
border-radius: 4px;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
.magic-description {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 5px;
|
||||
border-left: 3px solid #8a2be2;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.4;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
/* Chat Message Styles - Viking Theme */
|
||||
@import url("yggdrasill-chat-viking.less");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
// Main LESS file for Yggdrasill system
|
||||
// Importing all component styles
|
||||
|
||||
@import "yggdrasill-main";
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Index des applications AppV2 pour Yggdrasill
|
||||
* Ce fichier centralise tous les exports des applications
|
||||
*/
|
||||
|
||||
// Applications de feuilles d'acteurs
|
||||
export { default as YggdrasillPersonnageSheet } from './yggdrasill-personnage-sheet.mjs';
|
||||
export { default as YggdrasillFigurantSheet } from './yggdrasill-figurant-sheet.mjs';
|
||||
|
||||
// Applications de feuilles d'items
|
||||
export { default as YggdrasillCompetenceSheet } from './yggdrasill-competence-sheet.mjs';
|
||||
export { default as YggdrasillDonSheet } from './yggdrasill-don-sheet.mjs';
|
||||
export { default as YggdrasillFaiblesseSheet } from './yggdrasill-faiblesse-sheet.mjs';
|
||||
export { default as YggdrasillBlessureSheet } from './yggdrasill-blessure-sheet.mjs';
|
||||
export { default as YggdrasillMaladieSheet } from './yggdrasill-maladie-sheet.mjs';
|
||||
export { default as YggdrasillPoisonSheet } from './yggdrasill-poison-sheet.mjs';
|
||||
export { default as YggdrasillProuesseSheet } from './yggdrasill-prouesse-sheet.mjs';
|
||||
export { default as YggdrasillSortsejdrSheet } from './yggdrasill-sortsejdr-sheet.mjs';
|
||||
export { default as YggdrasillSortgaldrSheet } from './yggdrasill-sortgaldr-sheet.mjs';
|
||||
export { default as YggdrasillRuneSheet } from './yggdrasill-rune-sheet.mjs';
|
||||
export { default as YggdrasillArmeccSheet } from './yggdrasill-armecc-sheet.mjs';
|
||||
export { default as YggdrasillArmedistSheet } from './yggdrasill-armedist-sheet.mjs';
|
||||
export { default as YggdrasillArmureSheet } from './yggdrasill-armure-sheet.mjs';
|
||||
export { default as YggdrasillBouclierSheet } from './yggdrasill-bouclier-sheet.mjs';
|
||||
export { default as YggdrasillEquipementSheet } from './yggdrasill-equipement-sheet.mjs';
|
||||
export { default as YggdrasillMonnaieSheet } from './yggdrasill-monnaie-sheet.mjs';
|
||||
export { default as YggdrasillEffetmagiqueSheet } from './yggdrasill-effetmagique-sheet.mjs';
|
||||
@@ -1,449 +0,0 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
import { YggdrasillUtility } from "../../yggdrasill-utility.js"
|
||||
|
||||
export default class YggdrasillActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
/**
|
||||
* Different sheet modes.
|
||||
* @enum {number}
|
||||
*/
|
||||
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-yggdrasill", "sheet", "actor"],
|
||||
position: {
|
||||
width: 750,
|
||||
height: 720,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
tabs: [
|
||||
{
|
||||
navSelector: 'nav[data-group="primary"]',
|
||||
contentSelector: "section.sheet-body",
|
||||
initial: "principal",
|
||||
},
|
||||
],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: YggdrasillActorSheet.#onEditImage,
|
||||
toggleSheet: YggdrasillActorSheet.#onToggleSheet,
|
||||
editItem: YggdrasillActorSheet.#onEditItem,
|
||||
deleteItem: YggdrasillActorSheet.#onDeleteItem,
|
||||
createItem: YggdrasillActorSheet.#onCreateItem,
|
||||
equipItem: YggdrasillActorSheet.#onEquipItem,
|
||||
rollCarac: YggdrasillActorSheet.#onRollCarac,
|
||||
rollCompetence: YggdrasillActorSheet.#onRollCompetence,
|
||||
rollArme: YggdrasillActorSheet.#onRollArme,
|
||||
rollSort: YggdrasillActorSheet.#onRollSort,
|
||||
rollProuesse: YggdrasillActorSheet.#onRollProuesse,
|
||||
rollDamage: YggdrasillActorSheet.#onRollDamage,
|
||||
lockUnlock: YggdrasillActorSheet.#onLockUnlock,
|
||||
incrementPV: YggdrasillActorSheet.#onIncrementPV,
|
||||
decrementPV: YggdrasillActorSheet.#onDecrementPV,
|
||||
updateCompetence: YggdrasillActorSheet.#onUpdateCompetence,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Play' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPlayMode() {
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Edit' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isEditMode() {
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
*/
|
||||
tabGroups = {
|
||||
primary: "principal",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
actor: this.document,
|
||||
system: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
isEditMode: this.isEditMode,
|
||||
isPlayMode: this.isPlayMode,
|
||||
isEditable: this.isEditable,
|
||||
isGM: game.user.isGM,
|
||||
config: game.system.yggdrasill.config,
|
||||
editScore: this.isEditMode,
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
|
||||
// Activate tab navigation manually
|
||||
const nav = this.element.querySelector('nav.tabs[data-group], nav.sheet-tabs[data-group]')
|
||||
if (nav) {
|
||||
const group = nav.dataset.group
|
||||
// Activate the current tab
|
||||
const activeTab = this.tabGroups[group] || "principal"
|
||||
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||
const tab = link.dataset.tab
|
||||
link.classList.toggle('active', tab === activeTab)
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
this.tabGroups[group] = tab
|
||||
this.render()
|
||||
})
|
||||
})
|
||||
|
||||
// Show/hide tab content
|
||||
this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => {
|
||||
content.classList.toggle('active', content.dataset.tab === activeTab)
|
||||
})
|
||||
}
|
||||
|
||||
// Add change listener for competence niveau selects
|
||||
this.element.querySelectorAll('select.competence-niveau').forEach(select => {
|
||||
select.addEventListener('change', async (event) => {
|
||||
const itemId = event.target.dataset.itemId
|
||||
const item = this.document.items.get(itemId)
|
||||
if (item) {
|
||||
const newNiveau = parseInt(event.target.value)
|
||||
await item.update({ "system.niveau": newNiveau })
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates drag-and-drop handlers for this application
|
||||
* @returns {DragDrop[]} An array of DragDrop handlers
|
||||
* @private
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle changing a Document's image
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onEditImage(event, target) {
|
||||
const attr = target.dataset.edit
|
||||
const current = foundry.utils.getProperty(this.document, attr)
|
||||
const fp = new FilePicker({
|
||||
current,
|
||||
type: "image",
|
||||
callback: (path) => {
|
||||
this.document.update({ [attr]: path })
|
||||
},
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle sheet mode between Edit and Play
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onToggleSheet(event, target) {
|
||||
this._sheetMode = this.isEditMode
|
||||
? this.constructor.SHEET_MODES.PLAY
|
||||
: this.constructor.SHEET_MODES.EDIT
|
||||
this.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle item editing
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onEditItem(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
const item = this.document.items.get(itemId)
|
||||
if (item) item.sheet.render(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle item deletion
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onDeleteItem(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
const item = this.document.items.get(itemId)
|
||||
if (item) {
|
||||
await item.delete()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle item creation
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onCreateItem(event, target) {
|
||||
const itemType = target.dataset.itemType
|
||||
const itemData = {
|
||||
name: `Nouveau ${itemType}`,
|
||||
type: itemType,
|
||||
}
|
||||
await this.document.createEmbeddedDocuments("Item", [itemData])
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle item equip toggle
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onEquipItem(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
const item = this.document.items.get(itemId)
|
||||
if (item && item.system.equipe !== undefined) {
|
||||
await item.update({ "system.equipe": !item.system.equipe })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle characteristic roll
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onRollCarac(event, target) {
|
||||
const caracCateg = target.dataset.caracCateg
|
||||
const caracKey = target.dataset.caracKey
|
||||
this.document.rollCarac(caracCateg, caracKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle competence roll
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onRollCompetence(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
this.document.rollCompetence(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle weapon roll
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onRollArme(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
this.document.rollArme(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle lock/unlock toggle
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onLockUnlock(event, target) {
|
||||
this._sheetMode = this.isEditMode
|
||||
? this.constructor.SHEET_MODES.PLAY
|
||||
: this.constructor.SHEET_MODES.EDIT
|
||||
this.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incrementing PV
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onIncrementPV(event, target) {
|
||||
const currentPV = this.document.system.caracsecondaire.pv.value || 0
|
||||
const maxPV = this.document.system.caracsecondaire.pv.max || 0
|
||||
const newPV = Math.min(currentPV + 1, maxPV)
|
||||
await this.document.update({ "system.caracsecondaire.pv.value": newPV })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle decrementing PV
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onDecrementPV(event, target) {
|
||||
const currentPV = this.document.system.caracsecondaire.pv.value || 0
|
||||
const newPV = Math.max(currentPV - 1, 0)
|
||||
await this.document.update({ "system.caracsecondaire.pv.value": newPV })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle competence niveau update
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The select element
|
||||
*/
|
||||
static async #onUpdateCompetence(event, target) {
|
||||
const itemId = target.dataset.itemId
|
||||
const item = this.document.items.get(itemId)
|
||||
if (!item) return
|
||||
const newNiveau = parseInt(target.value)
|
||||
await item.update({ "system.niveau": newNiveau })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle sort roll
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onRollSort(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
const sortType = target.dataset.sortType || "sejdr"
|
||||
this.document.rollSort(itemId, sortType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle prouesse roll
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onRollProuesse(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
this.document.rollProuesse(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle damage roll
|
||||
* @this {YggdrasillActorSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static #onRollDamage(event, target) {
|
||||
const itemId = target.closest("[data-item-id]").dataset.itemId
|
||||
const weapon = this.document.items.get(itemId)
|
||||
if (weapon) {
|
||||
this.document.rollDamage(weapon, 'damage')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle beginning of a drag operation
|
||||
* @param {DragEvent} event - The originating drag event
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {
|
||||
const li = event.currentTarget
|
||||
const itemId = li.dataset.itemId
|
||||
const item = this.document.items.get(itemId)
|
||||
if (!item) return
|
||||
|
||||
const dragData = item.toDragData()
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a drop event
|
||||
* @param {DragEvent} event - The originating drop event
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
const data = TextEditor.getDragEventData(event)
|
||||
const actor = this.document
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
case "Item":
|
||||
return this._onDropItem(event, data)
|
||||
case "ActiveEffect":
|
||||
return this._onDropActiveEffect(event, data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an Item on the sheet
|
||||
* @param {DragEvent} event - The originating drop event
|
||||
* @param {object} data - The dropped data
|
||||
* @protected
|
||||
*/
|
||||
async _onDropItem(event, data) {
|
||||
if (!this.isEditable) return false
|
||||
const item = await Item.implementation.fromDropData(data)
|
||||
const itemData = item.toObject()
|
||||
|
||||
// Handle item from same actor
|
||||
if (this.document.uuid === item.parent?.uuid) return this._onSortItem(event, itemData)
|
||||
|
||||
// Create the item
|
||||
return this._onDropItemCreate(itemData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle creating an owned item from drop data
|
||||
* @param {object} itemData - The item data to create
|
||||
* @protected
|
||||
*/
|
||||
async _onDropItemCreate(itemData) {
|
||||
itemData = itemData instanceof Array ? itemData : [itemData]
|
||||
return this.document.createEmbeddedDocuments("Item", itemData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle sorting items
|
||||
* @param {DragEvent} event - The originating drop event
|
||||
* @param {object} itemData - The item data being sorted
|
||||
* @protected
|
||||
*/
|
||||
_onSortItem(event, itemData) {
|
||||
// Implement sorting logic if needed
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an ActiveEffect on the sheet
|
||||
* @param {DragEvent} event - The originating drop event
|
||||
* @param {object} data - The dropped data
|
||||
* @protected
|
||||
*/
|
||||
async _onDropActiveEffect(event, data) {
|
||||
const effect = await ActiveEffect.implementation.fromDropData(data)
|
||||
if (!this.isEditable || !effect) return false
|
||||
|
||||
if (this.document.uuid === effect.parent?.uuid) return false
|
||||
return ActiveEffect.create(effect.toObject(), { parent: this.document })
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class YggdrasillItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-yggdrasill", "item"],
|
||||
position: {
|
||||
width: 620,
|
||||
height: 600,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
tabs: [
|
||||
{
|
||||
navSelector: 'nav[data-group="primary"]',
|
||||
contentSelector: "section.sheet-body",
|
||||
initial: "description",
|
||||
},
|
||||
],
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: YggdrasillItemSheet.#onEditImage,
|
||||
postItem: YggdrasillItemSheet.#onPostItem,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
*/
|
||||
tabGroups = { primary: "description" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
// Import config
|
||||
const YGGDRASILL_CONFIG = game.system.yggdrasill?.config || game.system.config || {};
|
||||
|
||||
// Create options for niveau 0-5
|
||||
const optionsNiveaux4 = {};
|
||||
for (let i = 0; i <= 5; i++) {
|
||||
optionsNiveaux4[`${i}`] = `${i}`;
|
||||
}
|
||||
|
||||
// Create options for base (0-20)
|
||||
const optionsBase = {};
|
||||
for (let i = 0; i <= 20; i++) {
|
||||
optionsBase[`${i}`] = `${i}`;
|
||||
}
|
||||
|
||||
const context = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
item: this.document,
|
||||
system: this.document.system,
|
||||
data: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description || "", { async: true }),
|
||||
enrichedEffet: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.effet || "", { async: true }),
|
||||
isEditMode: true,
|
||||
isEditable: this.isEditable,
|
||||
editable: this.isEditable,
|
||||
isGM: game.user.isGM,
|
||||
config: YGGDRASILL_CONFIG,
|
||||
optionsBase: optionsBase,
|
||||
optionsNiveaux4: optionsNiveaux4,
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
|
||||
// Activate tab navigation manually
|
||||
const nav = this.element.querySelector('nav.tabs[data-group]')
|
||||
if (nav) {
|
||||
const group = nav.dataset.group
|
||||
// Activate the current tab
|
||||
const activeTab = this.tabGroups[group] || "description"
|
||||
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||
const tab = link.dataset.tab
|
||||
link.classList.toggle('active', tab === activeTab)
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
this.tabGroups[group] = tab
|
||||
this.render()
|
||||
})
|
||||
})
|
||||
// Show/hide tab content
|
||||
const body = this.element.querySelector('section.sheet-body')
|
||||
if (body) {
|
||||
body.querySelectorAll('[data-tab]').forEach(content => {
|
||||
const tab = content.dataset.tab
|
||||
content.style.display = tab === activeTab ? 'block' : 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates drag-and-drop handlers for this application
|
||||
* @returns {DragDrop[]} An array of DragDrop handlers
|
||||
* @private
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle changing a Document's image
|
||||
* @this {YggdrasillItemSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onEditImage(event, target) {
|
||||
const attr = target.dataset.edit || "img"
|
||||
const current = foundry.utils.getProperty(this.document, attr)
|
||||
const fp = new FilePicker({
|
||||
current,
|
||||
type: "image",
|
||||
callback: (path) => {
|
||||
this.document.update({ [attr]: path })
|
||||
},
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posting item to chat
|
||||
* @this {YggdrasillItemSheet}
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onPostItem(event, target) {
|
||||
const item = this.document
|
||||
const chatData = {
|
||||
user: game.user.id,
|
||||
speaker: ChatMessage.getSpeaker(),
|
||||
content: await foundry.applications.handlebars.renderTemplate("systems/fvtt-yggdrasill/templates/chat-item-card.hbs", {
|
||||
item: item,
|
||||
system: item.system,
|
||||
description: await TextEditor.enrichHTML(item.system.description || "", { async: true })
|
||||
})
|
||||
}
|
||||
ChatMessage.create(chatData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle beginning of a drag operation
|
||||
* @param {DragEvent} event - The originating drag event
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {
|
||||
const dragData = this.document.toDragData()
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a drop event
|
||||
* @param {DragEvent} event - The originating drop event
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
// Items generally don't handle drops, but method exists for extensibility
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Liste des types d'items restants à créer
|
||||
items=(
|
||||
"poison:Poison"
|
||||
"prouesse:Prouesse"
|
||||
"sortsejdr:Sortsejdr"
|
||||
"sortgaldr:Sortgaldr"
|
||||
"rune:Rune"
|
||||
"armecc:Armecc"
|
||||
"armedist:Armedist"
|
||||
"armure:Armure"
|
||||
"bouclier:Bouclier"
|
||||
"equipement:Equipement"
|
||||
"monnaie:Monnaie"
|
||||
"effetmagique:Effetmagique"
|
||||
)
|
||||
|
||||
for item in "${items[@]}"; do
|
||||
type="${item%%:*}"
|
||||
class="${item##*:}"
|
||||
|
||||
cat > "yggdrasill-${type}-sheet.mjs" << EOF
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class Yggdrasill${class}Sheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "${type}"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-${type}-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
EOF
|
||||
done
|
||||
|
||||
echo "Created all item sheets"
|
||||
ls -1 yggdrasill-*-sheet.mjs | wc -l
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillArmeccSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "armecc"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-armecc-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillArmedistSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "armedist"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-armedist-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillArmureSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "armure"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-armure-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillBlessureSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "blessure"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-blessure-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillBouclierSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "bouclier"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-bouclier-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillCompetenceSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "competence"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-competence-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "details",
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillDonSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "don"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-don-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillEffetmagiqueSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "effetmagique"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-effetmagique-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillEquipementSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "equipement"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-equipement-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillFaiblesseSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "faiblesse"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-faiblesse-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import YggdrasillActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class YggdrasillFigurantSheet extends YggdrasillActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "figurant"],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "Feuille de Figurant",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-yggdrasill/templates/actor-figurant-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "principal",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// System fields for formInput helpers
|
||||
context.systemFields = actor.system.schema.fields
|
||||
|
||||
// Enrich HTML fields
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true })
|
||||
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.notes || "", { async: true })
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillMaladieSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "maladie"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-maladie-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillMonnaieSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "monnaie"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-monnaie-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import YggdrasillActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class YggdrasillPersonnageSheet extends YggdrasillActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "personnage"],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "Feuille de Personnage",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-yggdrasill/templates/actor-personnage-sheet-new.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "principal",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Prepare items by type
|
||||
context.competencesGenerales = actor.items.filter(i => i.type === 'competence' && i.system.categorie === 'generale')
|
||||
context.competencesMartiales = actor.items.filter(i => i.type === 'competence' && i.system.categorie === 'martiale')
|
||||
context.competencesMagiques = actor.items.filter(i => i.type === 'competence' && i.system.categorie === 'magique')
|
||||
context.dons = actor.items.filter(i => i.type === 'don')
|
||||
context.faiblesses = actor.items.filter(i => i.type === 'faiblesse')
|
||||
context.blessures = actor.items.filter(i => i.type === 'blessure')
|
||||
context.maladies = actor.items.filter(i => i.type === 'maladie')
|
||||
context.poisons = actor.items.filter(i => i.type === 'poison')
|
||||
context.prouesses = actor.items.filter(i => i.type === 'prouesse')
|
||||
context.sortsSejdr = actor.items.filter(i => i.type === 'sortsejdr')
|
||||
context.sortsGaldr = actor.items.filter(i => i.type === 'sortgaldr')
|
||||
context.runes = actor.items.filter(i => i.type === 'rune')
|
||||
context.armesCC = actor.items.filter(i => i.type === 'armecc')
|
||||
context.armesDist = actor.items.filter(i => i.type === 'armedist')
|
||||
context.armures = actor.items.filter(i => i.type === 'armure')
|
||||
context.boucliers = actor.items.filter(i => i.type === 'bouclier')
|
||||
context.equipements = actor.items.filter(i => i.type === 'equipement')
|
||||
context.monnaies = actor.items.filter(i => i.type === 'monnaie')
|
||||
context.effetsMagiques = actor.items.filter(i => i.type === 'effetmagique')
|
||||
|
||||
// Prepare equipped items
|
||||
context.armesEquipees = actor.items.filter(i => (i.type === 'armecc' || i.type === 'armedist') && i.system.equipe)
|
||||
context.armureEquipee = actor.items.find(i => i.type === 'armure' && i.system.equipe)
|
||||
context.bouclierEquipe = actor.items.find(i => i.type === 'bouclier' && i.system.equipe)
|
||||
|
||||
// Calculate total protection from equipped armors
|
||||
context.protectionTotal = context.armures
|
||||
.filter(a => a.system.equipe)
|
||||
.reduce((sum, a) => sum + (parseInt(a.system.protection) || 0), 0)
|
||||
|
||||
// Calculate shield defense bonus from equipped shield
|
||||
context.dpBouclier = context.boucliers
|
||||
.filter(b => b.system.equipe)
|
||||
.reduce((sum, b) => sum + (parseInt(b.system.defensebonus) || 0), 0)
|
||||
|
||||
// Calculate total encumbrance from equipements
|
||||
context.encTotal = context.equipements
|
||||
.reduce((sum, e) => sum + ((parseInt(e.system.quantite) || 0) * (parseInt(e.system.enc) || 0)), 0)
|
||||
|
||||
// Options for selects
|
||||
context.optionsCarac = {}
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
context.optionsCarac[i] = i.toString()
|
||||
}
|
||||
|
||||
context.optionsBase = {}
|
||||
for (let i = 0; i <= 5; i++) {
|
||||
context.optionsBase[i] = i.toString()
|
||||
}
|
||||
|
||||
// Options for bonus/malus (-10 to +10)
|
||||
context.optionsDMDP = []
|
||||
for (let i = -10; i <= 10; i++) {
|
||||
context.optionsDMDP.push({ value: i, text: i >= 0 ? `+${i}` : i.toString() })
|
||||
}
|
||||
|
||||
// System fields for formInput helpers
|
||||
context.systemFields = actor.system.schema.fields
|
||||
|
||||
// Enrich HTML fields
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true })
|
||||
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.notes || "", { async: true })
|
||||
context.enrichedGMNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.gmnotes || "", { async: true })
|
||||
context.enrichedTirageRunes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.tiragerunes || "", { async: true })
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillPoisonSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "poison"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-poison-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillProuesseSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "prouesse"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-prouesse-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillRuneSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "rune"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-rune-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillSortgaldrSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "sortgaldr"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-sortgaldr-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import YggdrasillItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class YggdrasillSortsejdrSheet extends YggdrasillItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "sortsejdr"],
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-sortsejdr-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
import { YggdrasillUtility } from "../yggdrasill-utility.js"
|
||||
|
||||
const dureeGaldrSD = { "1d5a": 3, "1d10t": 6, "1d10m": 9, "1d10h": 12, "1d5j": 15}
|
||||
const ciblesGaldrSD = { "1": 3, "2_4": 6, "5_9": 9, "10_49": 12, "50plus": 15}
|
||||
const zonesciblesGaldrSD = { "INS10cm3": 3, "INS50cm3": 6, "INS1m3": 9, "INS5m3": 12, "INS10m3": 15}
|
||||
|
||||
/**
|
||||
* Dialogue de jet de dé pour Yggdrasill - Version DialogV2
|
||||
*/
|
||||
export class YggdrasillRollDialog {
|
||||
|
||||
/**
|
||||
* Create and display the roll dialog
|
||||
* @param {YggdrasillActor} actor - The actor making the roll
|
||||
* @param {Object} rollData - Data for the roll
|
||||
* @returns {Promise}
|
||||
*/
|
||||
static async create(actor, rollData) {
|
||||
// Initialiser attackData pour les armes si nécessaire
|
||||
if ((rollData.mode === "armecc" || rollData.mode === "armetir" || rollData.mode === "armedist") && rollData.attackDef) {
|
||||
// Les données sont déjà calculées dans attackDef par getAttaqueData/getTirData
|
||||
// On les copie simplement dans attackData pour le template
|
||||
rollData.attackData = { ...rollData.attackDef }
|
||||
}
|
||||
|
||||
// Calculer srTotal pour les sorts
|
||||
if (rollData.mode === "galdr") {
|
||||
this._updateGaldrSD(rollData)
|
||||
rollData.srTotal = 14 + (rollData.sdGaldr || 0)
|
||||
} else if (rollData.mode === "sejdr") {
|
||||
rollData.srTotal = 14 + (rollData.bonusdefense || 0)
|
||||
} else if (rollData.mode === "rune") {
|
||||
this._updateRuneData(rollData, actor)
|
||||
}
|
||||
|
||||
// Préparer le contexte pour le template
|
||||
const context = {
|
||||
...rollData,
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
config: game.system.yggdrasill.config,
|
||||
}
|
||||
|
||||
// Titre selon le mode
|
||||
let title = "Test"
|
||||
if (rollData.mode === "competence") title = "Test de Compétence"
|
||||
else if (rollData.mode === "carac") title = "Test de Caractéristique"
|
||||
else if (rollData.mode === "attribut") title = "Test d'Attribut"
|
||||
else if (rollData.mode === "armecc") title = "Attaque au Corps à Corps"
|
||||
else if (rollData.mode === "armetir" || rollData.mode === "armedist") title = "Attaque à Distance"
|
||||
else if (rollData.mode === "sejdr") title = "Sort Sejdr"
|
||||
else if (rollData.mode === "galdr") title = "Sort Galdr"
|
||||
else if (rollData.mode === "rune") title = "Rune"
|
||||
|
||||
// Rendre le template en HTML
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-yggdrasill/templates/roll-dialog-generic-new.hbs",
|
||||
context
|
||||
)
|
||||
|
||||
// Utiliser DialogV2.wait avec le HTML rendu
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: {
|
||||
title: title,
|
||||
icon: "fa-solid fa-dice-d20"
|
||||
},
|
||||
classes: ["yggdrasill-roll-dialog"],
|
||||
position: { width: 600 },
|
||||
modal: false,
|
||||
content,
|
||||
buttons: [
|
||||
{
|
||||
action: "roll",
|
||||
label: "Lancer le Test",
|
||||
icon: "fa-solid fa-dice",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
this._performRoll(rollData)
|
||||
}
|
||||
},
|
||||
],
|
||||
actions: {},
|
||||
render: (event, dialog) => {
|
||||
// Pour Galdr: recalculer srTotal quand durée, cibles ou zone changent
|
||||
if (rollData.mode === "galdr") {
|
||||
$("#dureeGaldr, #nbCibles, #zoneGaldr").on("change", () => {
|
||||
rollData.dureeGaldr = $("#dureeGaldr").val()
|
||||
rollData.nbCibles = $("#nbCibles").val()
|
||||
rollData.zoneGaldr = $("#zoneGaldr").val()
|
||||
this._updateGaldrSD(rollData)
|
||||
rollData.srTotal = 14 + (rollData.sdGaldr || 0)
|
||||
$("#srTotal").text(rollData.srTotal)
|
||||
})
|
||||
}
|
||||
|
||||
// Pour Sejdr: recalculer srTotal quand DM change
|
||||
if (rollData.mode === "sejdr") {
|
||||
$("#bonusdefense").on("change", () => {
|
||||
rollData.bonusdefense = parseInt($("#bonusdefense").val()) || 0
|
||||
rollData.srTotal = 14 + rollData.bonusdefense
|
||||
$("#srTotal").text(rollData.srTotal)
|
||||
})
|
||||
}
|
||||
|
||||
// Pour Rune: recalculer srTotal quand support ou puissance changent
|
||||
if (rollData.mode === "rune") {
|
||||
$("#supportRune, #puissanceRune").on("change", () => {
|
||||
rollData.supportRune = $("#supportRune").val()
|
||||
rollData.puissanceRune = parseInt($("#puissanceRune").val()) || 1
|
||||
this._updateRuneData(rollData, actor)
|
||||
$("#runeDuree").text(rollData.runeDuree)
|
||||
$("#runeDureeVie").text(rollData.runeDureeVie)
|
||||
$("#srTotal").text(rollData.srTotal)
|
||||
})
|
||||
}
|
||||
},
|
||||
rejectClose: false,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the roll based on mode
|
||||
* @param {Object} rollData - The roll data
|
||||
* @private
|
||||
*/
|
||||
static _performRoll(rollData) {
|
||||
if (rollData.mode === "attribut") {
|
||||
YggdrasillUtility.rollAttribute(rollData)
|
||||
} else {
|
||||
YggdrasillUtility.rollYggdrasill(rollData)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre à jour rollData avec les valeurs du formulaire
|
||||
* @param {Object} rollData - L'objet rollData à mettre à jour
|
||||
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
|
||||
* @param {YggdrasillActor} actor - L'acteur pour récupérer les données
|
||||
* @private
|
||||
*/
|
||||
static _updateRollDataFromForm(rollData, formElements, actor) {
|
||||
// Caractéristique (pour compétences)
|
||||
if (formElements.caracName) {
|
||||
const caracKey = formElements.caracName.value
|
||||
rollData.caracName = caracKey
|
||||
rollData.selectedCarac = this._findCaracByKey(actor, caracKey)
|
||||
}
|
||||
|
||||
// Type d'attaque (pour armes)
|
||||
if (formElements.typeAttack) {
|
||||
rollData.attackDef = rollData.attackDef || {}
|
||||
rollData.attackDef.typeAttack = formElements.typeAttack.value
|
||||
this._updateAttackData(rollData, actor)
|
||||
}
|
||||
|
||||
// Bonus/Malus
|
||||
if (formElements.bonusMalus) {
|
||||
rollData.bonusMalus = parseInt(formElements.bonusMalus.value) || 0
|
||||
}
|
||||
|
||||
// Furor
|
||||
if (formElements.furorUsage) {
|
||||
rollData.furorUsage = parseInt(formElements.furorUsage.value) || 0
|
||||
}
|
||||
|
||||
// Seuil de Réussite
|
||||
if (formElements.sr) {
|
||||
rollData.sr = parseInt(formElements.sr.value) || 9
|
||||
}
|
||||
|
||||
// Galdr options
|
||||
if (formElements.dureeGaldr) {
|
||||
rollData.dureeGaldr = formElements.dureeGaldr.value
|
||||
}
|
||||
if (formElements.nbCibles) {
|
||||
rollData.nbCibles = formElements.nbCibles.value
|
||||
}
|
||||
if (formElements.zoneGaldr) {
|
||||
rollData.zoneGaldr = formElements.zoneGaldr.value
|
||||
}
|
||||
if (rollData.mode === "galdr") {
|
||||
this._updateGaldrSD(rollData)
|
||||
rollData.srTotal = 14 + (rollData.sdGaldr || 0)
|
||||
}
|
||||
|
||||
// Sejdr options
|
||||
if (formElements.bonusdefense) {
|
||||
rollData.bonusdefense = parseInt(formElements.bonusdefense.value) || 0
|
||||
}
|
||||
if (rollData.mode === "sejdr") {
|
||||
rollData.srTotal = 14 + (rollData.bonusdefense || 0)
|
||||
}
|
||||
|
||||
// Rune options
|
||||
if (formElements.runeDuree) {
|
||||
rollData.runeDuree = formElements.runeDuree.value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find characteristic by key in actor
|
||||
* @param {YggdrasillActor} actor
|
||||
* @param {String} caracKey
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
static _findCaracByKey(actor, caracKey) {
|
||||
for (let [categKey, categ] of Object.entries(actor.system.carac)) {
|
||||
for (let [key, carac] of Object.entries(categ.carac)) {
|
||||
if (key === caracKey) {
|
||||
return { ...carac, categName: categKey, caracName: key }
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Update attack data based on attack type
|
||||
* @param {Object} rollData
|
||||
* @param {YggdrasillActor} actor
|
||||
* @private
|
||||
*/
|
||||
static _updateAttackData(rollData, actor) {
|
||||
const config = game.system.yggdrasill.config
|
||||
const attackType = rollData.attackDef.typeAttack
|
||||
const attackMode = config.attackMode?.[attackType]
|
||||
|
||||
if (attackMode) {
|
||||
rollData.attackData = rollData.attackData || {}
|
||||
rollData.attackData.categName = attackMode.categName
|
||||
rollData.attackData.caracName = attackMode.caracName
|
||||
rollData.attackData.malus = this._computeValue(attackMode.malus, actor)
|
||||
rollData.attackData.bonusdegats = this._computeValue(attackMode.bonusdegats, actor)
|
||||
rollData.attackData.protection = this._computeValue(attackMode.protection, actor)
|
||||
rollData.attackData.label = attackMode.label
|
||||
rollData.attackData.description = attackMode.description
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute value from string formula like "puissance;3"
|
||||
* @param {String|Number} value
|
||||
* @param {YggdrasillActor} actor
|
||||
* @returns {Number}
|
||||
* @private
|
||||
*/
|
||||
static _computeValue(value, actor) {
|
||||
if (typeof value === 'number') return value
|
||||
if (!value || value === "0") return 0
|
||||
|
||||
const parts = String(value).split(';')
|
||||
if (parts.length === 2) {
|
||||
const caracName = parts[0]
|
||||
const multiplier = parseInt(parts[1]) || 1
|
||||
const caracValue = this._getCaracValue(actor, caracName)
|
||||
return caracValue * multiplier
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Get characteristic value by name
|
||||
* @param {YggdrasillActor} actor
|
||||
* @param {String} caracName
|
||||
* @returns {Number}
|
||||
* @private
|
||||
*/
|
||||
static _getCaracValue(actor, caracName) {
|
||||
for (let categ of Object.values(actor.system.carac)) {
|
||||
if (categ.carac && categ.carac[caracName]) {
|
||||
return categ.carac[caracName].value || 0
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Update rune data based on support and power
|
||||
* @param {Object} rollData
|
||||
* @param {YggdrasillActor} actor
|
||||
* @private
|
||||
*/
|
||||
static _updateRuneData(rollData, actor) {
|
||||
let support = 0
|
||||
|
||||
rollData.dureeRune = 6 - (rollData.agiliteCarac?.value || 0)
|
||||
|
||||
if (rollData.supportRune === "peau") {
|
||||
support = 3
|
||||
rollData.echelleDuree = "Actions"
|
||||
rollData.echelleDureeVie = "Heures"
|
||||
} else if (rollData.supportRune === "tissu") {
|
||||
support = 6
|
||||
rollData.echelleDuree = "Tours"
|
||||
rollData.echelleDureeVie = "Jours"
|
||||
} else if (rollData.supportRune === "cuir") {
|
||||
support = 9
|
||||
rollData.echelleDuree = "Minutes"
|
||||
rollData.echelleDureeVie = "Semaines"
|
||||
} else if (rollData.supportRune === "bois") {
|
||||
support = 12
|
||||
rollData.echelleDuree = "Heures"
|
||||
rollData.echelleDureeVie = "Mois"
|
||||
} else if (rollData.supportRune === "pierremetal") {
|
||||
support = 15
|
||||
rollData.echelleDuree = "Jours"
|
||||
rollData.echelleDureeVie = "Années"
|
||||
}
|
||||
|
||||
rollData.runeDuree = `${rollData.dureeRune} ${rollData.echelleDuree}`
|
||||
rollData.runeDureeVie = `${rollData.competence?.system.niveau || 1} ${rollData.echelleDureeVie}`
|
||||
rollData.srTotal = (rollData.puissanceRune || 1) + (Number(rollData.sort?.system.niveau || 0) * 3) + support
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Galdr SD based on duration and targets
|
||||
* @param {Object} rollData
|
||||
* @private
|
||||
*/
|
||||
static _updateGaldrSD(rollData) {
|
||||
let sdDuree = Number(dureeGaldrSD[rollData.dureeGaldr]) || 0
|
||||
let sdVar = 0
|
||||
|
||||
if (rollData.sort?.system.voie === "illusion") {
|
||||
sdVar = Number(zonesciblesGaldrSD[rollData.zoneGaldr]) || 0
|
||||
} else {
|
||||
sdVar = Number(ciblesGaldrSD[rollData.nbCibles]) || 0
|
||||
}
|
||||
|
||||
rollData.sdGaldr = sdDuree + sdVar
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Data model pour les armes de corps à corps
|
||||
*/
|
||||
export default class ArmeccDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
equipe: new fields.BooleanField({ initial: false }),
|
||||
degat: new fields.NumberField({ initial: 0, integer: true }),
|
||||
solidite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
enc: new fields.NumberField({ initial: 0, integer: true }),
|
||||
valeur: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Data model pour les armes à distance
|
||||
*/
|
||||
export default class ArmedistDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
equipe: new fields.BooleanField({ initial: false }),
|
||||
degat: new fields.NumberField({ initial: 0, integer: true }),
|
||||
solidite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
enc: new fields.NumberField({ initial: 0, integer: true }),
|
||||
portee: new fields.StringField({ initial: "" }),
|
||||
valeur: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Data model pour les armures
|
||||
*/
|
||||
export default class ArmureDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
equipe: new fields.BooleanField({ initial: false }),
|
||||
protection: new fields.StringField({ initial: "" }),
|
||||
enc: new fields.NumberField({ initial: 0, integer: true }),
|
||||
valeur: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Data model pour les blessures
|
||||
*/
|
||||
export default class BlessureDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Data model pour les boucliers
|
||||
*/
|
||||
export default class BouclierDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
equipe: new fields.BooleanField({ initial: false }),
|
||||
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
enc: new fields.NumberField({ initial: 0, integer: true }),
|
||||
enccomb: new fields.NumberField({ initial: 0, integer: true }),
|
||||
solidite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
valeur: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Data model pour les compétences
|
||||
*/
|
||||
export default class CompetenceDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
isspecialisation: new fields.BooleanField({ initial: false }),
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
specialisation: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
niveauunrequis: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Data model pour les dons
|
||||
*/
|
||||
export default class DonDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Data model pour les effets magiques
|
||||
*/
|
||||
export default class EffetmagiqueDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
origine: new fields.StringField({ initial: "" }),
|
||||
effet: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Data model pour l'équipement
|
||||
*/
|
||||
export default class EquipementDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
equipe: new fields.BooleanField({ initial: false }),
|
||||
enc: new fields.NumberField({ initial: 0, integer: true }),
|
||||
valeur: new fields.NumberField({ initial: 0, integer: true }),
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Data model pour les faiblesses
|
||||
*/
|
||||
export default class FaiblesseDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Data model pour les figurants
|
||||
*/
|
||||
export default class FigurantDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
biodata: new fields.SchemaField({
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
taille: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
poids: new fields.NumberField({ initial: 0, integer: true }),
|
||||
notes: new fields.HTMLField({ initial: "" })
|
||||
}),
|
||||
attributs: new fields.SchemaField({
|
||||
conflit: new fields.SchemaField({
|
||||
values: new fields.SchemaField({
|
||||
offensif: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Offensif" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
degats: new fields.BooleanField({ initial: true })
|
||||
}),
|
||||
defensif: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Défensif" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
rollable: new fields.BooleanField({ initial: false }),
|
||||
label: new fields.StringField({ initial: "Conflit" })
|
||||
}),
|
||||
relationnel: new fields.SchemaField({
|
||||
values: new fields.SchemaField({
|
||||
defaut: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
rollable: new fields.BooleanField({ initial: true }),
|
||||
label: new fields.StringField({ initial: "Relationnel" })
|
||||
}),
|
||||
physique: new fields.SchemaField({
|
||||
values: new fields.SchemaField({
|
||||
defaut: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
rollable: new fields.BooleanField({ initial: true }),
|
||||
label: new fields.StringField({ initial: "Physique" })
|
||||
}),
|
||||
mental: new fields.SchemaField({
|
||||
values: new fields.SchemaField({
|
||||
defaut: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
rollable: new fields.BooleanField({ initial: true }),
|
||||
label: new fields.StringField({ initial: "Mental" })
|
||||
}),
|
||||
mystique: new fields.SchemaField({
|
||||
values: new fields.SchemaField({
|
||||
actif: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Actif" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
passif: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Passif" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
rollable: new fields.BooleanField({ initial: false }),
|
||||
label: new fields.StringField({ initial: "Mystique" })
|
||||
}),
|
||||
vitalite: new fields.SchemaField({
|
||||
values: new fields.SchemaField({
|
||||
defaut: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
rollable: new fields.BooleanField({ initial: false }),
|
||||
label: new fields.StringField({ initial: "Vitalité" })
|
||||
})
|
||||
}),
|
||||
etat: new fields.SchemaField({
|
||||
etat: new fields.StringField({ initial: "fringant" })
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Index des DataModels pour Yggdrasill
|
||||
* Ce fichier centralise tous les exports des modèles de données
|
||||
*/
|
||||
|
||||
// Modèles d'acteurs
|
||||
export { default as PersonnageDataModel } from './personnage.mjs';
|
||||
export { default as FigurantDataModel } from './figurant.mjs';
|
||||
|
||||
// Modèles d'items
|
||||
export { default as CompetenceDataModel } from './competence.mjs';
|
||||
export { default as DonDataModel } from './don.mjs';
|
||||
export { default as FaiblesseDataModel } from './faiblesse.mjs';
|
||||
export { default as BlessureDataModel } from './blessure.mjs';
|
||||
export { default as MaladieDataModel } from './maladie.mjs';
|
||||
export { default as PoisonDataModel } from './poison.mjs';
|
||||
export { default as ProuesseDataModel } from './prouesse.mjs';
|
||||
export { default as SortsejdrDataModel } from './sortsejdr.mjs';
|
||||
export { default as SortgaldrDataModel } from './sortgaldr.mjs';
|
||||
export { default as RuneDataModel } from './rune.mjs';
|
||||
export { default as ArmeccDataModel } from './armecc.mjs';
|
||||
export { default as ArmedistDataModel } from './armedist.mjs';
|
||||
export { default as ArmureDataModel } from './armure.mjs';
|
||||
export { default as BouclierDataModel } from './bouclier.mjs';
|
||||
export { default as EquipementDataModel } from './equipement.mjs';
|
||||
export { default as MonnaieDataModel } from './monnaie.mjs';
|
||||
export { default as EffetmagiqueDataModel } from './effetmagique.mjs';
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Data model pour les maladies
|
||||
*/
|
||||
export default class MaladieDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
periode: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Data model pour la monnaie
|
||||
*/
|
||||
export default class MonnaieDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
enc: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
* Data model pour les personnages
|
||||
*/
|
||||
export default class PersonnageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
biodata: new fields.SchemaField({
|
||||
nom: new fields.StringField({ initial: "" }),
|
||||
archetype: new fields.StringField({ initial: "" }),
|
||||
profession: new fields.StringField({ initial: "" }),
|
||||
royaume: new fields.StringField({ initial: "" }),
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
taille: new fields.NumberField({ initial: 0, integer: true }),
|
||||
poids: new fields.NumberField({ initial: 0, integer: true }),
|
||||
don: new fields.StringField({ initial: "" }),
|
||||
faiblesse: new fields.StringField({ initial: "" }),
|
||||
pointlegende: new fields.NumberField({ initial: 0, integer: true }),
|
||||
renomee: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
notes: new fields.HTMLField({ initial: "" }),
|
||||
tiragerunes: new fields.StringField({ initial: "" }),
|
||||
gmnotes: new fields.HTMLField({ initial: "" })
|
||||
}),
|
||||
carac: new fields.SchemaField({
|
||||
corps: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Corps" }),
|
||||
carac: new fields.SchemaField({
|
||||
puissance: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Puissance" }),
|
||||
categorie: new fields.StringField({ initial: "corps" }),
|
||||
abbrev: new fields.StringField({ initial: "pui" })
|
||||
}),
|
||||
vigueur: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Vigueur" }),
|
||||
categorie: new fields.StringField({ initial: "corps" }),
|
||||
abbrev: new fields.StringField({ initial: "vig" })
|
||||
}),
|
||||
agilite: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Agilité" }),
|
||||
categorie: new fields.StringField({ initial: "corps" }),
|
||||
abbrev: new fields.StringField({ initial: "agi" })
|
||||
})
|
||||
})
|
||||
}),
|
||||
esprit: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Esprit" }),
|
||||
carac: new fields.SchemaField({
|
||||
intellect: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Intellect" }),
|
||||
categorie: new fields.StringField({ initial: "esprit" }),
|
||||
abbrev: new fields.StringField({ initial: "int" })
|
||||
}),
|
||||
perception: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Perception" }),
|
||||
categorie: new fields.StringField({ initial: "esprit" }),
|
||||
abbrev: new fields.StringField({ initial: "per" })
|
||||
}),
|
||||
tenacite: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Tenacité" }),
|
||||
categorie: new fields.StringField({ initial: "esprit" }),
|
||||
abbrev: new fields.StringField({ initial: "ten" })
|
||||
})
|
||||
})
|
||||
}),
|
||||
ame: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Ame" }),
|
||||
carac: new fields.SchemaField({
|
||||
charisme: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Charisme" }),
|
||||
categorie: new fields.StringField({ initial: "ame" }),
|
||||
abbrev: new fields.StringField({ initial: "cha" })
|
||||
}),
|
||||
communication: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Communication" }),
|
||||
categorie: new fields.StringField({ initial: "ame" }),
|
||||
abbrev: new fields.StringField({ initial: "com" })
|
||||
}),
|
||||
instinct: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Instinct" }),
|
||||
categorie: new fields.StringField({ initial: "ame" }),
|
||||
abbrev: new fields.StringField({ initial: "ins" })
|
||||
})
|
||||
})
|
||||
})
|
||||
}),
|
||||
furor: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true }),
|
||||
label: new fields.StringField({ initial: "Furor" })
|
||||
}),
|
||||
xp: new fields.SchemaField({
|
||||
total: new fields.NumberField({ initial: 1, integer: true }),
|
||||
current: new fields.NumberField({ initial: 1, integer: true }),
|
||||
label: new fields.StringField({ initial: "XP" })
|
||||
}),
|
||||
renommee: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
label: new fields.StringField({ initial: "Renommée" })
|
||||
}),
|
||||
status: new fields.SchemaField({
|
||||
epuise: new fields.BooleanField({ initial: false }),
|
||||
blesse: new fields.BooleanField({ initial: false }),
|
||||
meurtri: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
caracsecondaire: new fields.SchemaField({
|
||||
reaction: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Réaction" }),
|
||||
abbrev: new fields.StringField({ initial: "rea" })
|
||||
}),
|
||||
defensephy: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusmalus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Défense Physique" }),
|
||||
abbrev: new fields.StringField({ initial: "dp" })
|
||||
}),
|
||||
defensemen: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusmalus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Défense Mentale" }),
|
||||
abbrev: new fields.StringField({ initial: "dm" })
|
||||
}),
|
||||
deplacement: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Déplacement" }),
|
||||
abbrev: new fields.StringField({ initial: "dep" })
|
||||
}),
|
||||
capaenc: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Capacité d'Encombrement" }),
|
||||
abbrev: new fields.StringField({ initial: "cpe" })
|
||||
}),
|
||||
pv: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 10, integer: true }),
|
||||
max: new fields.NumberField({ initial: 10, integer: true }),
|
||||
min: new fields.NumberField({ initial: 0, integer: true }),
|
||||
label: new fields.StringField({ initial: "Points de Vie" }),
|
||||
abbrev: new fields.StringField({ initial: "pv" })
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Data model pour les poisons
|
||||
*/
|
||||
export default class PoisonDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
type: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Data model pour les prouesses
|
||||
*/
|
||||
export default class ProuesseDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
armes: new fields.StringField({ initial: "" }),
|
||||
prerequis: new fields.StringField({ initial: "" }),
|
||||
modificateur: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Data model pour les runes
|
||||
*/
|
||||
export default class RuneDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Data model pour les sorts Galdr
|
||||
*/
|
||||
export default class SortgaldrDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
voie: new fields.StringField({ initial: "" }),
|
||||
sd: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Data model pour les sorts Sejdr
|
||||
*/
|
||||
export default class SortsejdrDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
forme: new fields.StringField({ initial: "" }),
|
||||
preparation: new fields.StringField({ initial: "" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
malus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
duree: new fields.StringField({ initial: "" }),
|
||||
zone: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,16 @@
|
||||
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class YggdrasillActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
export class YggdrasillActorSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["yggdrasill", "sheet", "actor"],
|
||||
template: "systems/fvtt-yggdrasill/templates/actor-personnage-sheet.hbs",
|
||||
width: 680,
|
||||
height: 740,
|
||||
template: "systems/fvtt-yggdrasill/templates/actor-sheet.html",
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||
editScore: false
|
||||
@@ -23,9 +23,9 @@ export class YggdrasillActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = foundry.utils.duplicate(this.object)
|
||||
|
||||
getData() {
|
||||
const objectData = YggdrasillUtility.data(this.object);
|
||||
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: objectData.id,
|
||||
@@ -34,7 +34,7 @@ export class YggdrasillActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
name: objectData.name,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
data: foundry.utils.deepClone(objectData.system),
|
||||
data: foundry.utils.deepClone(YggdrasillUtility.templateData(this.object)),
|
||||
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
|
||||
limited: this.object.limited,
|
||||
isEpuise: this.actor.isEpuise(),
|
||||
@@ -48,31 +48,23 @@ export class YggdrasillActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
blessures: this.actor.getBlessures(),
|
||||
armes: this.actor.getArmes(),
|
||||
armures: this.actor.getArmures(),
|
||||
boucliers: this.actor.getBoucliers(),
|
||||
prouessesMartiales: this.actor.getProuessesMartiales(),
|
||||
equipements: this.actor.getToutEquipements(),
|
||||
effetsmagiques: this.actor.getEffetsMagiques(),
|
||||
effetsRunes: this.actor.getEffetsDeRunes(),
|
||||
encTotal: this.actor.getEncTotal(),
|
||||
protectionTotal: this.actor.getProtectionTotal(),
|
||||
dpBouclier: this.actor.getDpBouclier(),
|
||||
monnaies: this.actor.getMonnaies(),
|
||||
sortsSejdr:this.actor.getSortsSejdr(),
|
||||
sortsGaldr:this.actor.getSortsGaldr(),
|
||||
runes: this.actor.getRunes(),
|
||||
optionsCarac: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||
optionsDMDP: YggdrasillUtility.createDirectSortedOptionList(-10, +10),
|
||||
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||
optionsFuror: YggdrasillUtility.createDirectOptionList(0, 15),
|
||||
tiragerunes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.tiragesrunes, {async: true}),
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.description, {async: true}),
|
||||
notes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.notes, {async: true}),
|
||||
gmnotes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.gmnotes, {async: true}),
|
||||
optionsDMDP: YggdrasillUtility.createDirectSortedOptionList(-10, +10),
|
||||
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||
optionsFuror: YggdrasillUtility.createDirectOptionList(0, 15),
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
editScore: this.options.editScore,
|
||||
isGM: game.user.isGM,
|
||||
config: game.system.config
|
||||
isGM: game.user.isGM
|
||||
}
|
||||
// Dynamic update some fields
|
||||
this.updateDM(formData.data);
|
||||
@@ -88,10 +80,10 @@ export class YggdrasillActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
dm.total = dm.max + Number(dm.bonusmalus);
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
updateDP( data ) {
|
||||
updateDP( data ) {
|
||||
let dp = data.caracsecondaire.defensephy;
|
||||
dp.total = dp.max + Number(dp.bonusmalus);
|
||||
dp.total += this.actor.getDpBouclier();
|
||||
dp.total += (dp.bouclierequipe) ? 3 : 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -105,7 +97,7 @@ updateDP( data ) {
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
const item = this.actor.items.get(li.data("item-id"));
|
||||
const item = this.actor.getOwnedItem(li.data("item-id"));
|
||||
item.sheet.render(true);
|
||||
});
|
||||
// Delete Inventory Item
|
||||
@@ -113,19 +105,19 @@ updateDP( data ) {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
YggdrasillUtility.confirmDelete(this, li);
|
||||
});
|
||||
|
||||
|
||||
html.find('#isEpuise').click(event => {
|
||||
this.actor.toggleEpuise( );
|
||||
} );
|
||||
|
||||
|
||||
html.find('.munition-moins').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const item = this.actor.items.get(li.data("item-id"));
|
||||
const item = this.actor.getOwnedItem(li.data("item-id"));
|
||||
this.actor.decrementeMunition( item );
|
||||
} );
|
||||
html.find('.munition-plus').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const item = this.actor.items.get(li.data("item-id"));
|
||||
const item = this.actor.getOwnedItem(li.data("item-id"));
|
||||
this.actor.incrementeMunition( item );
|
||||
} );
|
||||
html.find('.equipement-moins').click(event => {
|
||||
@@ -159,32 +151,32 @@ updateDP( data ) {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const sortId = li.data("item-id");
|
||||
this.actor.rollSort(sortId, "sejdr");
|
||||
});
|
||||
});
|
||||
html.find('.sort-galdr').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const sortId = li.data("item-id");
|
||||
this.actor.rollSort(sortId, "galdr");
|
||||
});
|
||||
});
|
||||
html.find('.sort-rune').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const sortId = li.data("item-id");
|
||||
this.actor.rollSort(sortId, "rune");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
html.find('.arme-label a').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const armeId = li.data("arme-id");
|
||||
this.actor.rollArme(armeId);
|
||||
});
|
||||
});
|
||||
html.find('.carac-roll').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
let categ = li.data("carac-categ");
|
||||
let carac = li.data("carac-key");
|
||||
this.actor.rollCarac(categ, carac);
|
||||
});
|
||||
});
|
||||
html.find('.weapon-damage').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const weapon = this.actor.items.get(li.data("item-id"));
|
||||
const weapon = this.actor.getOwnedItem(li.data("item-id"));
|
||||
this.actor.rollDamage(weapon, 'damage');
|
||||
});
|
||||
html.find('.competence-base').change((event) => {
|
||||
@@ -195,12 +187,12 @@ updateDP( data ) {
|
||||
html.find('.lock-unlock-sheet').click((event) => {
|
||||
this.options.editScore = !this.options.editScore;
|
||||
this.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-link a').click((event) => {
|
||||
const itemId = $(event.currentTarget).data("item-id");
|
||||
const item = this.actor.items.get(itemId);
|
||||
const item = this.actor.getOwnedItem(itemId);
|
||||
item.sheet.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-equip').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.equiperObject( li.data("item-id") );
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -------------------------------------------- */
|
||||
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||
import { YggdrasillRollDialog } from "./applications/yggdrasill-roll-dialog.mjs";
|
||||
import { YggdrasillRoll } from "./yggdrasill-roll-dialog.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const statusEffects = [
|
||||
@@ -175,15 +175,15 @@ export class YggdrasillActor extends Actor {
|
||||
async prepareData() {
|
||||
if ( this.type == "personnage") {
|
||||
this.computeCaracSecondaire();
|
||||
if (this.system.furor.value == 0)
|
||||
if (this.data.data.furor.value == 0)
|
||||
await this.setEpuise();
|
||||
else
|
||||
await this.cleanEpuise();
|
||||
if ( this.system.caracsecondaire.pv.value < (this.system.caracsecondaire.pv.max/4) )
|
||||
if ( this.data.data.caracsecondaire.pv.value < (this.data.data.caracsecondaire.pv.max/4) )
|
||||
await this.setMeurtri();
|
||||
else
|
||||
await this.cleanMeurtri();
|
||||
if ( this.system.caracsecondaire.pv.value < (this.system.caracsecondaire.pv.max/2) )
|
||||
if ( this.data.data.caracsecondaire.pv.value < (this.data.data.caracsecondaire.pv.max/2) )
|
||||
await this.setBlesse();
|
||||
else
|
||||
await this.cleanBlesse();
|
||||
@@ -193,24 +193,23 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_preUpdate(changed, options, user) {
|
||||
if ( changed.system?.caracsecondaire?.pv?.value ) {
|
||||
if ( changed.system.caracsecondaire.pv.value < 0 )
|
||||
changed.system.caracsecondaire.pv.value = 0;
|
||||
if ( changed.system.caracsecondaire.pv.value > this.system.caracsecondaire.pv.max )
|
||||
changed.system.caracsecondaire.pv.value = this.system.caracsecondaire.pv.max;
|
||||
if ( changed.data?.caracsecondaire?.pv?.value ) {
|
||||
if ( changed.data.caracsecondaire.pv.value < 0 )
|
||||
changed.data.caracsecondaire.pv.value = 0;
|
||||
if ( changed.data.caracsecondaire.pv.value > this.data.data.caracsecondaire.pv.max )
|
||||
changed.data.caracsecondaire.pv.value = this.data.data.caracsecondaire.pv.max;
|
||||
}
|
||||
|
||||
if ( changed.system?.furor?.value ) {
|
||||
if ( changed.system.furor.value < 0 )
|
||||
changed.system.furor.value = 0;
|
||||
if ( changed.system.furor.value > this.system.furor.max )
|
||||
changed.system.furor.value = this.system.furor.max;
|
||||
if ( changed.data?.furor?.value ) {
|
||||
if ( changed.data.furor.value < 0 )
|
||||
changed.data.furor.value = 0;
|
||||
if ( changed.data.furor.value > this.data.data.furor.max )
|
||||
changed.data.furor.value = this.data.data.furor.max;
|
||||
}
|
||||
super._preUpdate(changed, options, user);
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getCompetences() {
|
||||
let comp = this.items.filter( item => item.type == 'competence');
|
||||
let comp = this.data.items.filter( item => item.type == 'competence');
|
||||
return comp;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
@@ -225,97 +224,87 @@ export class YggdrasillActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getInitiativeScore() {
|
||||
if ( this.type == 'personnage') {
|
||||
return this.system.caracsecondaire.reaction.max;
|
||||
} else {
|
||||
return this.system.attributs.physique.values.defaut.value;
|
||||
}
|
||||
return this.data.data.caracsecondaire.reaction.max;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCompetencesGenerales() {
|
||||
let comp = this.items.filter( item => item.type == 'competence' && item.system.categorie == 'generale');
|
||||
let comp = this.data.items.filter( item => item.type == 'competence' && item.data.data.categorie == 'generale');
|
||||
return comp.sort( this.compareName );
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getCompetencesMartiales() {
|
||||
let comp = this.items.filter( item => item.type == 'competence' && item.system.categorie == 'martiale');
|
||||
let comp = this.data.items.filter( item => item.type == 'competence' && item.data.data.categorie == 'martiale');
|
||||
return comp.sort( this.compareName );
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getCompetencesMagiques() {
|
||||
let comp = this.items.filter( item => item.type == 'competence' && item.system.categorie == 'magique');
|
||||
let comp = this.data.items.filter( item => item.type == 'competence' && item.data.data.categorie == 'magique');
|
||||
return comp.sort( this.compareName );
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getDons( ) {
|
||||
let dons = this.items.filter( item => item.type == 'don');
|
||||
let dons = this.data.items.filter( item => item.type == 'don');
|
||||
return dons.sort( this.compareName );
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getEffetsMagiques( ) {
|
||||
let effets = this.items.filter( item => item.type == 'effetmagique');
|
||||
let effets = this.data.items.filter( item => item.type == 'effetmagique');
|
||||
return effets.sort( this.compareName );
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getEffetsDeRunes( ) {
|
||||
let effets = this.items.filter( item => item.type == 'effetderune');
|
||||
let effets = this.data.items.filter( item => item.type == 'effetderune');
|
||||
return effets.sort( this.compareName );
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getMonnaies( ) {
|
||||
let monnaies = this.items.filter( item => item.type == 'monnaie');
|
||||
let monnaies = this.data.items.filter( item => item.type == 'monnaie');
|
||||
return monnaies.sort( this.compareName );
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getFaiblesses( ) {
|
||||
let faib = this.items.filter( item => item.type == 'faiblesse');
|
||||
let faib = this.data.items.filter( item => item.type == 'faiblesse');
|
||||
return faib.sort( this.compareName );
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getBlessures( ) {
|
||||
return this.items.filter( item => item.type == 'blessure');
|
||||
return this.data.items.filter( item => item.type == 'blessure');
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getToutEquipements() {
|
||||
return this.items.filter( item => item.type == 'equipement' || item.type == 'armure' || item.type == 'armecc' || item.type == 'armedist' || item.type == 'bouclier');
|
||||
return this.data.items.filter( item => item.type == 'equipement' || item.type == 'armure' || item.type == 'armecc' || item.type == 'armedist');
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getArmes() {
|
||||
return this.items.filter( item => (item.type == 'armecc' || item.type == 'armedist') && item.system.equipe );
|
||||
return this.data.items.filter( item => (item.type == 'armecc' || item.type == 'armedist') && item.data.data.equipe );
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getArmures() {
|
||||
return this.items.filter( item => item.type == 'armure' && item.system.equipe );
|
||||
}
|
||||
getBoucliers() {
|
||||
return this.items.filter( item => item.type == 'bouclier' && item.system.equipe );
|
||||
return this.data.items.filter( item => item.type == 'armure' && item.data.data.equipe );
|
||||
}
|
||||
getProuessesMartiales() {
|
||||
let prouesse = this.items.filter( item => item.type == 'prouesse' );
|
||||
let prouesse = this.data.items.filter( item => item.type == 'prouesse' );
|
||||
return prouesse.sort( this.compareName );
|
||||
}
|
||||
getSortsSejdr() {
|
||||
let sort = this.items.filter( item => item.type == 'sortsejdr' );
|
||||
let sort = this.data.items.filter( item => item.type == 'sortsejdr' );
|
||||
return sort.sort( this.compareName );
|
||||
}
|
||||
getSortsGaldr() {
|
||||
let sort = this.items.filter( item => item.type == 'sortgaldr' );
|
||||
let sort = this.data.items.filter( item => item.type == 'sortgaldr' );
|
||||
return sort.sort( this.compareName );
|
||||
}
|
||||
getRunes() {
|
||||
let sort = this.items.filter( item => item.type == 'rune' );
|
||||
let sort = this.data.items.filter( item => item.type == 'rune' );
|
||||
return sort.sort( this.compareName );
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async setEpuise( ) {
|
||||
if (!this.system.status.epuise) {
|
||||
await this.update({ 'system.status.epuise': true});
|
||||
this.system.status.epuise = true;
|
||||
}
|
||||
await this.update({ 'data.status.epuise': true});
|
||||
this.data.data.status.epuise = true;
|
||||
/*let effect = this.getEffectByLabel('Epuisé');
|
||||
if ( !effect ) {
|
||||
let effect = statusEffects.find( ef => ef.id == 'epuise');
|
||||
@@ -324,10 +313,8 @@ export class YggdrasillActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async cleanEpuise() {
|
||||
if (this.system.status.epuise) {
|
||||
await this.update({ 'system.status.epuise': false});
|
||||
this.system.status.epuise = false;
|
||||
}
|
||||
await this.update({ 'data.status.epuise': false});
|
||||
this.data.data.status.epuise = false;
|
||||
/*let effect = this.getEffectByLabel('Epuisé');
|
||||
if ( effect ) {
|
||||
await this.deleteEmbeddedDocuments("ActiveEffect", [ effect.id ]);
|
||||
@@ -335,7 +322,7 @@ export class YggdrasillActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async toggleEpuise( ) {
|
||||
if ( this.system.status.epuise ) {
|
||||
if ( this.data.data.status.epuise ) {
|
||||
await this.cleanEpuise();
|
||||
} else {
|
||||
await this.setEpuise();
|
||||
@@ -343,15 +330,14 @@ export class YggdrasillActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
isEpuise() {
|
||||
return this.system.status.epuise;
|
||||
return this.data.data.status.epuise;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async setBlesse( ) {
|
||||
if (!this.system.status.blesse) {
|
||||
await this.update({ 'system.status.blesse': true} );
|
||||
this.system.status.blesse = true;
|
||||
}
|
||||
await this.update({ 'data.status.blesse': true} );
|
||||
this.data.data.status.blesse = true;
|
||||
console.log("BLESSSE !!!!");
|
||||
/*let effect = this.getEffectByLabel('Blessé');
|
||||
if ( !effect ) {
|
||||
let effect = statusEffects.find( ef => ef.id == 'blesse');
|
||||
@@ -360,10 +346,8 @@ export class YggdrasillActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async cleanBlesse() {
|
||||
if (this.system.status.blesse) {
|
||||
await this.update({ 'system.status.blesse': false} );
|
||||
this.system.status.blesse = false;
|
||||
}
|
||||
await this.update({ 'data.status.blesse': false} );
|
||||
this.data.data.status.blesse = false;
|
||||
/*let effect = this.getEffectByLabel('Blessé');
|
||||
if ( effect ) {
|
||||
await this.deleteEmbeddedDocuments("ActiveEffect", [ effect.id ]);
|
||||
@@ -372,46 +356,43 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isBlesse() {
|
||||
return this.system.status.blesse;
|
||||
return this.data.data.status.blesse;
|
||||
//return this.getEffectByLabel('Blessé');
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async setMeurtri( ) {
|
||||
await this.setBlesse();
|
||||
if (!this.system.status.meurtri) {
|
||||
await this.update({ 'system.status.meurtri': true});
|
||||
this.system.status.meurtri = true;
|
||||
}
|
||||
await this.update({ 'data.status.meurtri': true});
|
||||
this.data.data.status.meurtri = true;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async cleanMeurtri() {
|
||||
if (this.system.status.meurtri) {
|
||||
await this.update({ 'system.status.meurtri': false});
|
||||
this.system.status.meurtri = false;
|
||||
}
|
||||
await this.update({ 'data.status.meurtri': false});
|
||||
this.data.data.status.meurtri = false;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
isMeurtri() {
|
||||
return this.system.status.meurtri;
|
||||
return this.data.data.status.meurtri;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async decrementFuror( nbFuror) {
|
||||
await this.update( { 'system.furor.value': this.system.furor.value - nbFuror } );
|
||||
await this.update( { 'data.furor.value': this.data.data.furor.value - nbFuror } );
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCurrentFuror() {
|
||||
return this.system.furor.value;
|
||||
return this.data.data.furor.value;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getActiveEffects(matching = it => true) {
|
||||
let array = Array.from(this.getEmbeddedCollection("ActiveEffect").values());
|
||||
return Array.from(this.getEmbeddedCollection("ActiveEffect").values()).filter(it => matching(it));
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getEffectByLabel(label) {
|
||||
return this.getActiveEffects().find(it => it.label == label);
|
||||
return this.getActiveEffects().find(it => it.data.label == label);
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getEffectById(id) {
|
||||
@@ -420,11 +401,11 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCarac( caracName ) {
|
||||
for( let key in this.system.carac) {
|
||||
let categ = this.system.carac[key];
|
||||
for( let key in this.data.data.carac) {
|
||||
let categ = this.data.data.carac[key];
|
||||
for( let carac in categ.carac) {
|
||||
if (carac.toLowerCase() == caracName.toLowerCase() ) {
|
||||
return foundry.utils.deepClone(categ.carac[carac]);
|
||||
return deepClone(categ.carac[carac]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,64 +414,50 @@ export class YggdrasillActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
computeCaracSecondaire( ) {
|
||||
if ( this.type == "personnage") {
|
||||
let basecorps = this.system.carac.corps.carac;
|
||||
let basecorps = this.data.data.carac.corps.carac;
|
||||
let sumcorps = basecorps.puissance.value + basecorps.agilite.value + basecorps.vigueur.value
|
||||
let baseesprit = this.system.carac.esprit.carac;
|
||||
let baseesprit = this.data.data.carac.esprit.carac;
|
||||
let sumesprit = baseesprit.intellect.value + baseesprit.perception.value + baseesprit.tenacite.value
|
||||
let baseame = this.system.carac.ame.carac;
|
||||
let baseame = this.data.data.carac.ame.carac;
|
||||
let sumame = baseame.charisme.value + baseame.communication.value + baseame.instinct.value
|
||||
|
||||
let newPV = (sumcorps*3) + (sumesprit *2) + sumame;
|
||||
this.system.caracsecondaire.pv.max = newPV;
|
||||
|
||||
this.system.caracsecondaire.reaction.value = baseesprit.intellect.value + baseesprit.perception.value + baseame.instinct.value;
|
||||
let newReac = baseesprit.intellect.value + baseesprit.perception.value + baseame.instinct.value;
|
||||
this.system.caracsecondaire.reaction.max = newReac
|
||||
|
||||
this.system.caracsecondaire.defensephy.value = basecorps.agilite.value + basecorps.vigueur.value + baseame.instinct.value;
|
||||
let newDef = basecorps.agilite.value + basecorps.vigueur.value + baseame.instinct.value;
|
||||
this.system.caracsecondaire.defensephy.max = newDef
|
||||
// Initialize bonusmalus if not set
|
||||
if (this.system.caracsecondaire.defensephy.bonusmalus === undefined) {
|
||||
this.system.caracsecondaire.defensephy.bonusmalus = 0
|
||||
if ( newPV != this.data.data.caracsecondaire.pv.max) {
|
||||
this.data.data.caracsecondaire.pv.max = newPV;
|
||||
this.update( { 'data.caracsecondaire.pv.max': newPV });
|
||||
}
|
||||
this.system.caracsecondaire.defensephy.total = newDef + this.system.caracsecondaire.defensephy.bonusmalus
|
||||
|
||||
this.system.caracsecondaire.defensemen.value = baseesprit.tenacite.value + baseame.instinct.value + baseesprit.intellect.value;
|
||||
newDef = baseesprit.tenacite.value + baseame.instinct.value + baseesprit.intellect.value;
|
||||
this.system.caracsecondaire.defensemen.max = newDef
|
||||
// Initialize bonusmalus if not set
|
||||
if (this.system.caracsecondaire.defensemen.bonusmalus === undefined) {
|
||||
this.system.caracsecondaire.defensemen.bonusmalus = 0
|
||||
}
|
||||
this.system.caracsecondaire.defensemen.total = newDef + this.system.caracsecondaire.defensemen.bonusmalus
|
||||
this.data.data.caracsecondaire.reaction.value = baseesprit.intellect.value + baseesprit.perception.value + baseame.instinct.value;
|
||||
this.data.data.caracsecondaire.reaction.max = baseesprit.intellect.value + baseesprit.perception.value + baseame.instinct.value;
|
||||
|
||||
this.system.caracsecondaire.deplacement.value = basecorps.agilite.value + basecorps.vigueur.value;
|
||||
let depl = basecorps.agilite.value + basecorps.vigueur.value;
|
||||
this.system.caracsecondaire.deplacement.max = depl
|
||||
this.data.data.caracsecondaire.defensephy.value = basecorps.agilite.value + basecorps.vigueur.value + baseame.instinct.value;
|
||||
this.data.data.caracsecondaire.defensephy.max = basecorps.agilite.value + basecorps.vigueur.value + baseame.instinct.value;
|
||||
|
||||
this.system.caracsecondaire.capaenc.value = (basecorps.puissance.value * 2) + basecorps.vigueur.value;
|
||||
let enc = (basecorps.puissance.value * 2) + basecorps.vigueur.value;
|
||||
this.system.caracsecondaire.capaenc.max = enc
|
||||
this.data.data.caracsecondaire.defensemen.value = baseesprit.tenacite.value + baseame.instinct.value + baseesprit.intellect.value;
|
||||
this.data.data.caracsecondaire.defensemen.max = baseesprit.tenacite.value + baseame.instinct.value + baseesprit.intellect.value;
|
||||
|
||||
//console.log("CARAC SEC", this.system.caracsecondaire)
|
||||
this.data.data.caracsecondaire.deplacement.value = basecorps.agilite.value + basecorps.vigueur.value;
|
||||
this.data.data.caracsecondaire.deplacement.max = basecorps.agilite.value + basecorps.vigueur.value;
|
||||
|
||||
this.data.data.caracsecondaire.capaenc.value = (basecorps.puissance.value * 2) + basecorps.vigueur.value;
|
||||
this.data.data.caracsecondaire.capaenc.max = (basecorps.puissance.value * 2) + basecorps.vigueur.value;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async equiperObject( equipementId ) {
|
||||
let item = this.items.find( item => item.id == equipementId );
|
||||
if (item && item.system) {
|
||||
let update = { _id: item.id, "system.equipe": !item.system.equipe };
|
||||
let item = this.data.items.find( item => item.id == equipementId );
|
||||
if (item && item.data.data) {
|
||||
let update = { _id: item.id, "data.equipe": !item.data.data.equipe };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async updateCompetence( compId, niveau) {
|
||||
let comp = this.items.find( item => item.type == 'competence' && item.id == compId);
|
||||
let comp = this.data.items.find( item => item.type == 'competence' && item.id == compId);
|
||||
console.log("Comp updated!!!!", compId, niveau);
|
||||
if (comp) {
|
||||
const update = { _id: comp.id, 'system.niveau': niveau };
|
||||
const update = { _id: comp.id, 'data.niveau': niveau };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
} else {
|
||||
ui.notifications.warn("Compétence inconnue", compId)
|
||||
@@ -504,9 +471,9 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollAttribute( attrkey, subAttrKey = 'defaut') {
|
||||
let attr = foundry.utils.duplicate(this.system.attributs[attrkey]);
|
||||
console.log("ATTR : ", attr, attrkey, subAttrKey);
|
||||
let subAttr = foundry.utils.duplicate(this.system.attributs[attrkey].values[subAttrKey] );
|
||||
let attr = duplicate(this.data.data.attributs[attrkey]);
|
||||
let subAttr = duplicate(this.data.data.attributs[attrkey].values[subAttrKey] );
|
||||
console.log("ATTR : ", attr, subAttr);
|
||||
if ( attr ) {
|
||||
subAttr.label = subAttr.label || "";
|
||||
let title = `Attribut : ${attr.label} ${subAttr.label} : ${subAttr.value}`;
|
||||
@@ -516,35 +483,28 @@ export class YggdrasillActor extends Actor {
|
||||
actorImg: this.img,
|
||||
actorId: this.id,
|
||||
attr: attr,
|
||||
valuePhysique: this.system.attributs["physique"].values["defaut"].value,
|
||||
valuePhysique: this.data.data.attributs["physique"].values["defaut"].value,
|
||||
subAttr: subAttr,
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
title: title,
|
||||
isBlesse: this.system.etat.etat == "blesse",
|
||||
isBlesse: this.data.data.etat.etat == "blesse",
|
||||
optionsBonusMalus: YggdrasillUtility.buildListOptions(-6, +6),
|
||||
bonusMalus: 0,
|
||||
optionsSR: YggdrasillUtility.buildSROptions( ),
|
||||
sr: 0
|
||||
}
|
||||
this.addDefaultRoll(rollData)
|
||||
await YggdrasillRollDialog.create( this, rollData);
|
||||
let rollDialog = await YggdrasillRoll.create( this, rollData);
|
||||
console.log(rollDialog);
|
||||
rollDialog.render( true );
|
||||
} else {
|
||||
ui.notifications.warn("Attribut non trouvée");
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
addDefaultRoll(rollData) {
|
||||
rollData.optionsBonusMalus= YggdrasillUtility.createOptions(-15, 15)
|
||||
rollData.bonusMalus= 0
|
||||
rollData.optionsFuror= YggdrasillUtility.createOptions(0, this.getCurrentFuror())
|
||||
rollData.furorUsage= 0
|
||||
rollData.optionsBD= YggdrasillUtility.createOptions(0, +15)
|
||||
rollData.sr= 0
|
||||
rollData.puissanceRune = 1
|
||||
rollData.optionsPuissanceRune= YggdrasillUtility.createOptions(1, +15)
|
||||
rollData.supportRune= "peau"
|
||||
|
||||
rollData.config= game.system.config
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollCarac( categName, caracName) {
|
||||
let carac = foundry.utils.duplicate(this.system.carac[categName].carac[caracName]);
|
||||
let carac = duplicate(this.data.data.carac[categName].carac[caracName]);
|
||||
console.log("CARAC : ", carac, this.data.data.carac);
|
||||
if ( carac) {
|
||||
let rollData = {
|
||||
mode: "carac",
|
||||
@@ -558,10 +518,16 @@ export class YggdrasillActor extends Actor {
|
||||
isEpuise: this.isEpuise(),
|
||||
isBlesse: this.isBlesse(),
|
||||
isMeurtri: this.isMeurtri(),
|
||||
optionsBonusMalus: YggdrasillUtility.buildListOptions(-6, +6),
|
||||
bonusMalus: 0,
|
||||
optionsFuror: YggdrasillUtility.buildListOptions(0, this.getCurrentFuror() ),
|
||||
furorUsage: 0,
|
||||
optionsSR: YggdrasillUtility.buildSROptions( ),
|
||||
sr: 0
|
||||
}
|
||||
this.addDefaultRoll(rollData)
|
||||
console.log("CARAC : ", rollData, this.system.carac);
|
||||
await YggdrasillRollDialog.create( this, rollData);
|
||||
let rollDialog = await YggdrasillRoll.create( this, rollData);
|
||||
console.log(rollDialog);
|
||||
rollDialog.render( true );
|
||||
} else {
|
||||
ui.notifications.warn("Caractéristique non trouvée");
|
||||
}
|
||||
@@ -570,7 +536,7 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollCompetence( competenceId ) {
|
||||
let competence = this.items.find( item => item.type == 'competence' && item.id == competenceId);
|
||||
let competence = this.data.items.find( item => item.type == 'competence' && item.id == competenceId);
|
||||
if ( competence) {
|
||||
let rollData = {
|
||||
mode: "competence",
|
||||
@@ -579,14 +545,21 @@ export class YggdrasillActor extends Actor {
|
||||
actorId: this.id,
|
||||
img: competence.img,
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
title: `Compétence ${competence.name} : ${competence.system.niveau}`,
|
||||
competence: foundry.utils.duplicate(competence),
|
||||
title: `Compétence ${competence.name} : ${competence.data.data.niveau}`,
|
||||
competence: duplicate(competence),
|
||||
isEpuise: this.isEpuise(),
|
||||
isBlesse: this.isBlesse(),
|
||||
isMeurtri: this.isMeurtri(),
|
||||
optionsBonusMalus: YggdrasillUtility.buildListOptions(-6, +6),
|
||||
bonusMalus: 0,
|
||||
optionsFuror: YggdrasillUtility.buildListOptions(0, this.getCurrentFuror() ),
|
||||
furorUsage: 0,
|
||||
optionsSR: YggdrasillUtility.buildSROptions( ),
|
||||
sr: 0
|
||||
}
|
||||
this.addDefaultRoll(rollData)
|
||||
await YggdrasillRollDialog.create( this, rollData);
|
||||
let rollDialog = await YggdrasillRoll.create( this, rollData);
|
||||
console.log(rollDialog);
|
||||
rollDialog.render( true );
|
||||
} else {
|
||||
ui.notifications.warn("Compétence non trouvée");
|
||||
}
|
||||
@@ -594,21 +567,21 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getAttaqueData( mode ) {
|
||||
let attackData = foundry.utils.duplicate(attackMode[mode]);
|
||||
let attackData = duplicate(attackMode[mode]);
|
||||
if ( attackData){
|
||||
attackData.mode = mode;
|
||||
attackData.carac = foundry.utils.duplicate(this.system.carac[attackData.categName].carac[attackData.caracName]);
|
||||
attackData.carac = duplicate(this.data.data.carac[attackData.categName].carac[attackData.caracName]);
|
||||
if ( attackData.malus != 0) {
|
||||
let malusTab = attackData.malus.split(';');
|
||||
attackData.malus = this.system.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
attackData.malus = this.data.data.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
}
|
||||
if ( attackData.protection != 0) {
|
||||
let malusTab = attackData.protection.split(';');
|
||||
attackData.protection = this.system.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
attackData.protection = this.data.data.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
}
|
||||
if ( attackData.bonusdegats != 0) {
|
||||
let malusTab = attackData.bonusdegats.split(';');
|
||||
attackData.bonusdegats = this.system.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
attackData.bonusdegats = this.data.data.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
}
|
||||
}
|
||||
return attackData;
|
||||
@@ -616,21 +589,21 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getTirData( mode) {
|
||||
let attackData = foundry.utils.duplicate( tirMode[mode] );
|
||||
let attackData = duplicate( tirMode[mode] );
|
||||
if ( attackData){
|
||||
attackData.mode = mode;
|
||||
attackData.carac = foundry.utils.duplicate(this.system.carac[attackData.categName].carac[attackData.caracName]);
|
||||
attackData.carac = duplicate(this.data.data.carac[attackData.categName].carac[attackData.caracName]);
|
||||
if ( attackData.malus != 0) {
|
||||
let malusTab = attackData.malus.split(';');
|
||||
attackData.malus = this.system.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
attackData.malus = this.data.data.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
}
|
||||
if ( attackData.protection != 0) {
|
||||
let malusTab = attackData.protection.split(';');
|
||||
attackData.protection = this.system.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
attackData.protection = this.data.data.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
}
|
||||
if ( attackData.bonusdegats != 0) {
|
||||
let malusTab = attackData.bonusdegats.split(';');
|
||||
attackData.bonusdegats = this.system.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
attackData.bonusdegats = this.data.data.carac[attackData.categName].carac[malusTab[0]].value * Number(malusTab[1])
|
||||
}
|
||||
}
|
||||
return attackData;
|
||||
@@ -638,24 +611,23 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollSort( sortId, magie) {
|
||||
let sort = this.items.find( item => item.id == sortId);
|
||||
let competence = this.items.find( item => item.type == 'competence' && item.name.toLowerCase().includes(magie));
|
||||
let sort = this.data.items.find( item => item.id == sortId);
|
||||
let competence = this.data.items.find( item => item.type == 'competence' && item.name.toLowerCase().includes(magie));
|
||||
console.log("SORT :", sortId, sort, competence );
|
||||
|
||||
let carac;
|
||||
if ( magie == "sejdr") {
|
||||
carac = foundry.utils.duplicate(this.system.carac.ame.carac.instinct);
|
||||
carac = duplicate(this.data.data.carac.ame.carac.instinct);
|
||||
} else if ( magie == "rune") {
|
||||
carac = foundry.utils.duplicate(this.system.carac.ame.carac.communication);
|
||||
carac = duplicate(this.data.data.carac.ame.carac.communication);
|
||||
} else {
|
||||
carac = foundry.utils.duplicate(this.system.carac.ame.carac.charisme);
|
||||
carac = duplicate(this.data.data.carac.ame.carac.charisme);
|
||||
}
|
||||
|
||||
if ( sort && competence) {
|
||||
|
||||
let rollData = {
|
||||
mode: magie,
|
||||
isMagie: true,
|
||||
alias: this.name,
|
||||
actorImg: this.img,
|
||||
actorId: this.id,
|
||||
@@ -663,10 +635,10 @@ export class YggdrasillActor extends Actor {
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
title: magie + " - " + sort.name,
|
||||
selectedCarac: carac,
|
||||
agiliteCarac: foundry.utils.duplicate(this.system.carac.corps.carac.agilite),
|
||||
instinctCarac: foundry.utils.duplicate(this.system.carac.ame.carac.instinct),
|
||||
sort: foundry.utils.duplicate(sort),
|
||||
competence: foundry.utils.duplicate(competence),
|
||||
agiliteCarac: duplicate(this.data.data.carac.corps.carac.agilite),
|
||||
instinctCarac: duplicate(this.data.data.carac.ame.carac.instinct),
|
||||
sort: duplicate(sort),
|
||||
competence: duplicate(competence),
|
||||
dureeGaldr: "1d5a",
|
||||
nbCibles: "1",
|
||||
zoneGaldr: "INS10cm3",
|
||||
@@ -674,10 +646,20 @@ export class YggdrasillActor extends Actor {
|
||||
isEpuise: this.isEpuise(),
|
||||
isBlesse: this.isBlesse(),
|
||||
isMeurtri: this.isMeurtri(),
|
||||
optionsBonusMalus: YggdrasillUtility.buildListOptions(-6, +6),
|
||||
optionsBD: YggdrasillUtility.buildListOptions(0, +6),
|
||||
bonusMalus: 0,
|
||||
optionsFuror: YggdrasillUtility.buildListOptions(0, this.getCurrentFuror() ),
|
||||
furorUsage: 0,
|
||||
optionsSR: YggdrasillUtility.buildSROptions( ),
|
||||
sr: 14,
|
||||
puissanceRune: 1,
|
||||
optionsPuissanceRune: YggdrasillUtility.buildListOptions(1, 15),
|
||||
supportRune: "peau",
|
||||
}
|
||||
this.addDefaultRoll(rollData)
|
||||
rollData.sr = 14
|
||||
await YggdrasillRollDialog.create( this, rollData);
|
||||
let rollDialog = await YggdrasillRoll.create( this, rollData);
|
||||
console.log(rollDialog);
|
||||
rollDialog.render( true );
|
||||
} else {
|
||||
ui.notifications.warn("Sortilège ou Compétence non trouvée !", sort, compName);
|
||||
}
|
||||
@@ -685,9 +667,9 @@ export class YggdrasillActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollArme( armeId ) {
|
||||
let arme = this.items.find( item => item.id == armeId);
|
||||
let compName = armeCategorieToCompetence[arme.system.categorie];
|
||||
let competence = this.items.find( item => item.type == 'competence' && item.name == compName);
|
||||
let arme = this.data.items.find( item => item.id == armeId);
|
||||
let compName = armeCategorieToCompetence[arme.data.data.categorie];
|
||||
let competence = this.data.items.find( item => item.type == 'competence' && item.name == compName);
|
||||
console.log("ARME :", armeId, arme, competence );
|
||||
|
||||
if ( arme && competence) {
|
||||
@@ -708,17 +690,24 @@ export class YggdrasillActor extends Actor {
|
||||
img: competence.img,
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
title: "Attaque !",
|
||||
selectedCarac: foundry.utils.duplicate(this.system.carac.corps.carac.agilite),
|
||||
arme: foundry.utils.duplicate(arme),
|
||||
competence: foundry.utils.duplicate(competence),
|
||||
selectedCarac: duplicate(this.data.data.carac.corps.carac.agilite),
|
||||
arme: duplicate(arme),
|
||||
competence: duplicate(competence),
|
||||
bonusdefense: 0,
|
||||
isEpuise: this.isEpuise(),
|
||||
isBlesse: this.isBlesse(),
|
||||
isMeurtri: this.isMeurtri()
|
||||
isMeurtri: this.isMeurtri(),
|
||||
optionsBonusMalus: YggdrasillUtility.buildListOptions(-6, +6),
|
||||
optionsBD: YggdrasillUtility.buildListOptions(0, +6),
|
||||
bonusMalus: 0,
|
||||
optionsFuror: YggdrasillUtility.buildListOptions(0, this.getCurrentFuror() ),
|
||||
furorUsage: 0,
|
||||
optionsSR: YggdrasillUtility.buildSROptions( ),
|
||||
sr: 14
|
||||
}
|
||||
this.addDefaultRoll(rollData)
|
||||
rollData.sr = 14
|
||||
await YggdrasillRollDialog.create( this, rollData);
|
||||
let rollDialog = await YggdrasillRoll.create( this, rollData);
|
||||
console.log(rollDialog);
|
||||
rollDialog.render( true );
|
||||
} else {
|
||||
ui.notifications.warn("Arme ou Compétence Martiale non trouvée !", arme, compName);
|
||||
}
|
||||
@@ -727,58 +716,42 @@ export class YggdrasillActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
getEncTotal( ) {
|
||||
let encTotal = 0;
|
||||
for( let item of this.items) {
|
||||
if (item.type == "equipement" || item.type == "armecc"
|
||||
|| item.type == "armedist" || item.type == "armure" || item.type == "monnaie" || item.type == "bouclier") {
|
||||
encTotal += (item.system.enc * item.system.quantite);
|
||||
}
|
||||
}
|
||||
for( let item of this.items) {
|
||||
if (item.type == "bouclier" && item.system.equipe) {
|
||||
encTotal -= (item.system.enc * item.system.quantite);
|
||||
encTotal += (item.system.enccomb * item.system.quantite);
|
||||
for( let item of this.data.items) {
|
||||
if (item.type == "equipement" || item.type == "armecc"
|
||||
|| item.type == "armedist" || item.type == "armure" || item.type == "monnaie") {
|
||||
encTotal += item.data.data.enc;
|
||||
}
|
||||
}
|
||||
return encTotal;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getProtectionTotal( ) {
|
||||
let protectionTotal = 0;
|
||||
for( let item of this.items) {
|
||||
if (item.type == "armure" && item.system.equipe) {
|
||||
protectionTotal += Number(item.system.protection);
|
||||
for( let item of this.data.items) {
|
||||
if (item.type == "armure" && item.data.data.equipe) {
|
||||
protectionTotal += Number(item.data.data.protection);
|
||||
}
|
||||
}
|
||||
return protectionTotal;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getDpBouclier( ) {
|
||||
let dpBouclier = 0;
|
||||
for( let item of this.items) {
|
||||
if (item.type == "bouclier" && item.system.equipe) {
|
||||
dpBouclier += Number(item.system.defensebonus);
|
||||
}
|
||||
}
|
||||
return dpBouclier;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async incrementeQuantite( objetId ) {
|
||||
let objetQ = this.items.find( item => item.id == objetId );
|
||||
let objetQ = this.data.items.find( item => item.id == objetId );
|
||||
if (objetQ) {
|
||||
let newQ = objetQ.system.quantite + 1;
|
||||
const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'system.quantite': newQ }]); // pdates one EmbeddedEntity
|
||||
let newQ = objetQ.data.data.quantite + 1;
|
||||
const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'data.quantite': newQ }]); // pdates one EmbeddedEntity
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async decrementeQuantite( objetId ) {
|
||||
let objetQ = this.items.find( item => item.id == objetId );
|
||||
let objetQ = this.data.items.find( item => item.id == objetId );
|
||||
if (objetQ) {
|
||||
let newQ = objetQ.system.quantite - 1;
|
||||
let newQ = objetQ.data.data.quantite - 1;
|
||||
newQ = (newQ <= 0) ? 0 : newQ;
|
||||
const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'system.quantite': newQ }]); // pdates one EmbeddedEntity
|
||||
const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'data.quantite': newQ }]); // pdates one EmbeddedEntity
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export class YggdrasillCombat extends Combat {
|
||||
|
||||
// Send a chat message
|
||||
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
|
||||
let messageData = foundry.utils.mergeObject(
|
||||
let messageData = mergeObject(
|
||||
{
|
||||
speaker: {
|
||||
scene: canvas.scene._id,
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
|
||||
export const YGGDRASILL_CONFIG = {
|
||||
|
||||
optionsEtat: [
|
||||
{ key: "fringant", label: "Fringant" },
|
||||
{ key: "blesse", label: "Blessé" },
|
||||
{ key: "mort", label: "Mort" }
|
||||
],
|
||||
|
||||
optionsArme: [
|
||||
{ key: "lutte", label: "Lutte" },
|
||||
{ key: "improvisee", label: "Improvisée" },
|
||||
{ key: "courte", label: "Courte" },
|
||||
{ key: "longue", label: "Longue" },
|
||||
{ key: "deuxmains", label: "A Deux Mains" },
|
||||
{ key: "hast", label: "Hast" }
|
||||
],
|
||||
optionsArmeTir: [
|
||||
{ key: "jet", label: "Jet" },
|
||||
{ key: "tir", label: "Tir" }
|
||||
],
|
||||
optionsArmure: [
|
||||
{ key: "armure", label: "Armure" },
|
||||
{ key: "piecearmure", label: "Pièce d'Armure" }
|
||||
],
|
||||
optionsBouclier: [
|
||||
{ key: "bouclier", label: "Bouclier" }
|
||||
],
|
||||
optionsCompetence: [
|
||||
{ key: "generale", label: "Générale" },
|
||||
{ key: "magique", label: "Magique" },
|
||||
{ key: "martiale", label: "Martiale" }
|
||||
],
|
||||
optionsMaladie: [
|
||||
{ key: "mineure", label: "Mineure" },
|
||||
{ key: "moderee", label: "Modérée" },
|
||||
{ key: "majeure", label: "Majeure" }
|
||||
],
|
||||
optionsProuesse: [
|
||||
{ key: "attaque", label: "Attaque" },
|
||||
{ key: "defensive", label: "Défensive" },
|
||||
{ key: "utilitaire", label: "Utilitaire" }
|
||||
]
|
||||
,
|
||||
optionsGaldr: [
|
||||
{ key:"malediction", label:"Malédictions" },
|
||||
{ key:"illusion", label:"Illusions" },
|
||||
{ key:"charme", label:"Charme" }
|
||||
],
|
||||
optionsAttaque: [
|
||||
{ key:"classique", label:"Attaque classique" },
|
||||
{ key:"force", label:"Attaque en force" },
|
||||
{ key:"devastatrice", label:"Attaque dévastatrice" },
|
||||
{ key:"precise", label:"Attaque Précise" },
|
||||
{ key:"visee", label:"Attaque Visée" }
|
||||
],
|
||||
optionsSR : [
|
||||
{key: 0, label: "Aucun"},
|
||||
{key: 5, label: "Très Simple (5)"},
|
||||
{key: 7, label: "Simple (7)"},
|
||||
{key: 10, label: "Aisé (10)"},
|
||||
{key: 14, label: "Moyen (14)"},
|
||||
{key: 19, label: "Difficile (19)"},
|
||||
{key: 25, label: "Très Difficile (25)"},
|
||||
{key: 32, label: "Exceptionnel (32)"},
|
||||
{key: 40, label: "Légendaire (40)"},
|
||||
{key: 49, label: "Divin (49)"}
|
||||
|
||||
],
|
||||
optionsCarac: [
|
||||
{ key: "puissance", label: "Puissance" },
|
||||
{ key: "vigueur", label: "Vigueur" },
|
||||
{ key: "agilite", label: "Agilité" },
|
||||
{ key: "intellect", label: "Intellect" },
|
||||
{ key: "perception", label: "Perception" },
|
||||
{ key: "tenacite", label: "Tenacité" },
|
||||
{ key: "charisme", label: "Charisme" },
|
||||
{ key: "communication", label: "Communication" },
|
||||
{ key: "instinct", label: "Instinct" }
|
||||
],
|
||||
optionsDureeGaldr: [
|
||||
{ key:"1d5a", label:"1d5 Actions" },
|
||||
{ key:"1d10t", label:"1d10 Tours" },
|
||||
{ key:"1d10m", label:"1d10 Minutes" },
|
||||
{ key:"1d10h", label:"1d10 Heures" },
|
||||
{ key:"1d5j", label:"1d5 journées" }
|
||||
],
|
||||
optionsZoneGaldr: [
|
||||
{ key:"INS10cm3", label:"INS x 10 cm3 (chat, balle, épée, ...)" },
|
||||
{ key:"INS50cm3", label:"INS x 50 cm3 (tabouret, enfant, ...)" },
|
||||
{ key:"INS1m3", label:"INS x 1 m3 (homme, 2 enfants, ...)" },
|
||||
{ key:"INS5m3", label:"INS x 5 m3 (charrette, 2 cavaliers, ...)" },
|
||||
{ key:"INS10m3", label:"INS x 10 m3 (maison, kraken, bateau, ...)" }
|
||||
],
|
||||
optionsNbCibles: [
|
||||
{ key: "1", label: "1" },
|
||||
{ key: "2_4", label: "2 à 4" },
|
||||
{ key: "5_9", label: "5 à 9" },
|
||||
{ key: "10_49", label: "10 à 49" },
|
||||
{ key: "50plus", label: "50 et +" }
|
||||
],
|
||||
optionsSupportRunes: [
|
||||
{ key: "peau", label: "Peau" },
|
||||
{ key: "tissu", label: "Tissu" },
|
||||
{ key: "cuir", label: "Cuir" },
|
||||
{ key: "bois", label: "Bois" },
|
||||
{ key: "pierremetal", label: "Pierre, Métal" }
|
||||
]
|
||||
|
||||
|
||||
}
|
||||
@@ -6,12 +6,12 @@
|
||||
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class YggdrasillFigurantSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
export class YggdrasillFigurantSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["yggdrasill", "sheet", "actor"],
|
||||
template: "systems/fvtt-yggdrasill/templates/figurant-sheet.html",
|
||||
width: 640,
|
||||
@@ -23,9 +23,9 @@ export class YggdrasillFigurantSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = foundry.utils.duplicate(this.object)
|
||||
|
||||
getData() {
|
||||
const objectData = YggdrasillUtility.data(this.object);
|
||||
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: objectData.id,
|
||||
@@ -34,21 +34,18 @@ export class YggdrasillFigurantSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
name: objectData.name,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
data: foundry.utils.deepClone(this.object.system),
|
||||
data: foundry.utils.deepClone(YggdrasillUtility.templateData(this.object)),
|
||||
limited: this.object.limited,
|
||||
equipements: this.actor.getToutEquipements(),
|
||||
effetsmagiques: this.actor.getEffetsMagiques(),
|
||||
encTotal: this.actor.getEncTotal(),
|
||||
monnaies: this.actor.getMonnaies(),
|
||||
optionsAttr: Array.fromRange(41, 1),
|
||||
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.description, {async: true}),
|
||||
notes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.notes, {async: true}),
|
||||
optionsAttr: new Array(21).fill('option'),
|
||||
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
editScore: this.options.editScore,
|
||||
isGM: game.user.isGM,
|
||||
config: game.system.config
|
||||
isGM: game.user.isGM
|
||||
}
|
||||
|
||||
console.log("FIGURANT : ", formData);
|
||||
@@ -66,7 +63,7 @@ export class YggdrasillFigurantSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
const item = this.actor.items.get(li.data("item-id"));
|
||||
const item = this.actor.getOwnedItem(li.data("item-id"));
|
||||
item.sheet.render(true);
|
||||
});
|
||||
// Delete Inventory Item
|
||||
@@ -74,7 +71,7 @@ export class YggdrasillFigurantSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
YggdrasillUtility.confirmDelete(this, li);
|
||||
});
|
||||
|
||||
|
||||
html.find('.equipement-moins').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
this.actor.decrementeQuantite( li.data("item-id") );
|
||||
@@ -89,16 +86,16 @@ export class YggdrasillFigurantSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
let attrKey = li.data("attr-key");
|
||||
let attrSubKey = $(event.currentTarget).data("attr-sub-key");
|
||||
this.actor.rollAttribute(attrKey, attrSubKey);
|
||||
});
|
||||
});
|
||||
html.find('.lock-unlock-sheet').click((event) => {
|
||||
this.options.editScore = !this.options.editScore;
|
||||
this.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-link a').click((event) => {
|
||||
const itemId = $(event.currentTarget).data("item-id");
|
||||
const item = this.actor.items.get(itemId);
|
||||
const item = this.actor.getOwnedItem(itemId);
|
||||
item.sheet.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-equip').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.equiperObject( li.data("item-id") );
|
||||
|
||||
@@ -1,115 +1,101 @@
|
||||
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||
import { YGGDRASILL_CONFIG } from "./yggdrasill-config.js";
|
||||
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
/**
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheetV2}
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class YggdrasillItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this.#dragDrop = this.#createDragDropHandlers();
|
||||
export class YggdrasillItemSheet extends ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-yggdrasill", "sheet", "item"],
|
||||
template: "systems/fvtt-yggdrasill/templates/item-sheet.html",
|
||||
width: 550,
|
||||
height: 550
|
||||
//tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
|
||||
});
|
||||
}
|
||||
|
||||
#dragDrop;
|
||||
/* -------------------------------------------- */
|
||||
_getHeaderButtons() {
|
||||
let buttons = super._getHeaderButtons();
|
||||
// Add "Post to chat" button
|
||||
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
|
||||
buttons.unshift(
|
||||
{
|
||||
class: "post",
|
||||
icon: "fas fa-comment",
|
||||
onclick: ev => {}
|
||||
})
|
||||
return buttons
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-yggdrasill", "item"],
|
||||
position: {
|
||||
width: 550,
|
||||
height: 550,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
actions: {
|
||||
editImage: YggdrasillItemSheet.#onEditImage,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
*/
|
||||
tabGroups = { primary: "description" };
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-yggdrasill/templates/item-{type}-sheet.hbs"
|
||||
}
|
||||
};
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
// Ensure config is always available with fallback to direct import
|
||||
const config = game.system?.config || game.system?.yggdrasill?.config || YGGDRASILL_CONFIG || {};
|
||||
setPosition(options={}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
const bodyHeight = position.height - 192;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = YggdrasillUtility.data(this.object);
|
||||
|
||||
// Create options for niveau 0-5
|
||||
const optionsNiveaux4 = {};
|
||||
for (let i = 0; i <= 5; i++) {
|
||||
optionsNiveaux4[`${i}`] = `${i}`;
|
||||
}
|
||||
|
||||
const optionsBase = YggdrasillUtility.createDirectOptionList(0, 20) || {};
|
||||
|
||||
const context = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
item: this.document,
|
||||
system: this.document.system,
|
||||
data: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description || "", { async: true }),
|
||||
enrichedEffet: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.effet || "", { async: true }),
|
||||
isEditMode: true,
|
||||
isEditable: this.isEditable,
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: objectData.id,
|
||||
type: objectData.type,
|
||||
img: objectData.img,
|
||||
name: objectData.name,
|
||||
editable: this.isEditable,
|
||||
isGM: game.user.isGM,
|
||||
config: config,
|
||||
optionsBase: optionsBase,
|
||||
optionsNiveaux4: optionsNiveaux4,
|
||||
};
|
||||
return context;
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
data: foundry.utils.deepClone(YggdrasillUtility.templateData(this.object)),
|
||||
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||
optionsNiveaux4: YggdrasillUtility.buildListOptions(1, 5),
|
||||
limited: this.object.limited,
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
isGM: game.user.isGM
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options);
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element));
|
||||
}
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// #region Drag-and-Drop Workflow
|
||||
/**
|
||||
* Create drag-and-drop workflow handlers for this Application
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return [];
|
||||
}
|
||||
|
||||
// #region Actions
|
||||
|
||||
/**
|
||||
* Handle editing the item image
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onEditImage(event) {
|
||||
event.preventDefault();
|
||||
const filePicker = new FilePicker({
|
||||
type: "image",
|
||||
current: this.document.img,
|
||||
callback: (path) => {
|
||||
this.document.update({ img: path });
|
||||
},
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
const item = this.object.options.actor.getOwnedItem(li.data("item-id"));
|
||||
item.sheet.render(true);
|
||||
});
|
||||
filePicker.browse();
|
||||
// Update Inventory Item
|
||||
html.find('.item-delete').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.object.options.actor.deleteOwnedItem( li.data("item-id") ).then( this.render(true));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template()
|
||||
{
|
||||
let type = this.item.type;
|
||||
return `systems/fvtt-yggdrasill/templates/item-${type}-sheet.html`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
return this.object.update(formData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,16 +9,11 @@
|
||||
/* -------------------------------------------- */
|
||||
// Import Modules
|
||||
import { YggdrasillActor } from "./yggdrasill-actor.js";
|
||||
import { YggdrasillItemSheet } from "./yggdrasill-item-sheet.js";
|
||||
import { YggdrasillActorSheet } from "./yggdrasill-actor-sheet.js";
|
||||
import { YggdrasillFigurantSheet } from "./yggdrasill-figurant-sheet.js";
|
||||
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||
import { YggdrasillCombat } from "./yggdrasill-combat.js";
|
||||
import { YGGDRASILL_CONFIG } from "./yggdrasill-config.js";
|
||||
import { ClassCounter} from "https://www.uberwald.me/fvtt_appcount/count-class-ready.js"
|
||||
|
||||
// Import DataModels
|
||||
import * as models from "./models/index.mjs";
|
||||
|
||||
// Import AppV2 Sheets
|
||||
import * as sheets from "./applications/sheets/_module.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
@@ -33,14 +28,12 @@ Hooks.once("init", async function () {
|
||||
YggdrasillUtility.preloadHandlebarsTemplates();
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Set an initiative formula for the system
|
||||
// Set an initiative formula for the system
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "1d20",
|
||||
decimals: 0
|
||||
};
|
||||
|
||||
game.system.config = YGGDRASILL_CONFIG
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.socket.on("system.fvtt-yggdrasill", data => {
|
||||
YggdrasillUtility.onSocketMesssage(data);
|
||||
@@ -49,82 +42,33 @@ Hooks.once("init", async function () {
|
||||
/* -------------------------------------------- */
|
||||
// Define custom Entity classes
|
||||
CONFIG.Actor.documentClass = YggdrasillActor;
|
||||
CONFIG.Actor.dataModels = {
|
||||
personnage: models.PersonnageDataModel,
|
||||
figurant: models.FigurantDataModel
|
||||
};
|
||||
|
||||
CONFIG.Combat.documentClass = YggdrasillCombat;
|
||||
|
||||
CONFIG.Item.dataModels = {
|
||||
competence: models.CompetenceDataModel,
|
||||
don: models.DonDataModel,
|
||||
faiblesse: models.FaiblesseDataModel,
|
||||
blessure: models.BlessureDataModel,
|
||||
maladie: models.MaladieDataModel,
|
||||
poison: models.PoisonDataModel,
|
||||
prouesse: models.ProuesseDataModel,
|
||||
sortsejdr: models.SortsejdrDataModel,
|
||||
sortgaldr: models.SortgaldrDataModel,
|
||||
rune: models.RuneDataModel,
|
||||
armecc: models.ArmeccDataModel,
|
||||
armedist: models.ArmedistDataModel,
|
||||
armure: models.ArmureDataModel,
|
||||
bouclier: models.BouclierDataModel,
|
||||
equipement: models.EquipementDataModel,
|
||||
monnaie: models.MonnaieDataModel,
|
||||
effetmagique: models.EffetmagiqueDataModel
|
||||
};
|
||||
|
||||
CONFIG.Yggdrasill = {
|
||||
}
|
||||
|
||||
game.system.yggdrasill = {
|
||||
config: YGGDRASILL_CONFIG,
|
||||
models,
|
||||
sheets
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("fvtt-yggdrasill", YggdrasillActorSheet, { types: ["personnage"], makeDefault: true });
|
||||
Actors.registerSheet("fvtt-yggdrasill", YggdrasillFigurantSheet, { types: ["figurant"], makeDefault: false });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("fvtt-yggdrasill", YggdrasillItemSheet, { makeDefault: true });
|
||||
|
||||
// Init/registers
|
||||
Hooks.on('renderChatLog', (log, html, data) => {
|
||||
//YggdrasillUtility.registerChatCallbacks(html);
|
||||
});
|
||||
|
||||
// Register AppV2 Actor Sheets
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-yggdrasill", sheets.YggdrasillPersonnageSheet, { types: ["personnage"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-yggdrasill", sheets.YggdrasillFigurantSheet, { types: ["figurant"], makeDefault: true });
|
||||
|
||||
// Register AppV2 Item Sheets
|
||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillCompetenceSheet, { types: ["competence"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillDonSheet, { types: ["don"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillFaiblesseSheet, { types: ["faiblesse"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillBlessureSheet, { types: ["blessure"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillMaladieSheet, { types: ["maladie"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillPoisonSheet, { types: ["poison"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillProuesseSheet, { types: ["prouesse"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillSortsejdrSheet, { types: ["sortsejdr"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillSortgaldrSheet, { types: ["sortgaldr"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillRuneSheet, { types: ["rune"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillArmeccSheet, { types: ["armecc"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillArmedistSheet, { types: ["armedist"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillArmureSheet, { types: ["armure"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillBouclierSheet, { types: ["bouclier"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillEquipementSheet, { types: ["equipement"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillMonnaieSheet, { types: ["monnaie"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-yggdrasill", sheets.YggdrasillEffetmagiqueSheet, { types: ["effetmagique"], makeDefault: true });
|
||||
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async function welcomeMessage() {
|
||||
const templateData = {};
|
||||
const html = await foundry.applications.handlebars.renderTemplate("systems/fvtt-yggdrasill/templates/chat-welcome-message.hbs", templateData);
|
||||
|
||||
function welcomeMessage() {
|
||||
//ChatUtility.removeMyChatMessageContaining('<div id="welcome-message-sos">');
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: [game.user.id],
|
||||
content: html
|
||||
});
|
||||
content: `<div id="welcome-message-yggdrasill"><span class="rdd-roll-part">Bienvenue !</div>
|
||||
` });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -140,9 +84,7 @@ Hooks.once("ready", function () {
|
||||
user: game.user._id
|
||||
});
|
||||
}
|
||||
|
||||
ClassCounter.registerUsageCount()
|
||||
welcomeMessage()
|
||||
welcomeMessage();
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -156,28 +98,3 @@ Hooks.on("chatMessage", (html, content, msg) => {
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Chat Message Rendering */
|
||||
/* -------------------------------------------- */
|
||||
Hooks.on("renderChatMessageHTML", (message, html, data) => {
|
||||
// Handle collapsible magic details
|
||||
html.querySelector('.magic-header.collapsible')?.addEventListener('click', function() {
|
||||
const header = this;
|
||||
const content = header.parentElement.querySelector('.magic-content');
|
||||
|
||||
// Toggle collapsed state
|
||||
content?.classList.toggle('collapsed');
|
||||
header.classList.toggle('expanded');
|
||||
});
|
||||
|
||||
// Handle collapsible weapon details
|
||||
html.querySelector('.weapon-header.collapsible')?.addEventListener('click', function() {
|
||||
const header = this;
|
||||
const content = header.parentElement.querySelector('.weapon-content');
|
||||
|
||||
// Toggle collapsed state
|
||||
content?.classList.toggle('collapsed');
|
||||
header.classList.toggle('expanded');
|
||||
});
|
||||
});
|
||||
|
||||
207
modules/yggdrasill-roll-dialog.js
Normal file
207
modules/yggdrasill-roll-dialog.js
Normal file
@@ -0,0 +1,207 @@
|
||||
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||
const dureeGaldrSD = { "1d5a": 3, "1d10t": 6, "1d10m": 9, "1d10h": 12, "1d5j": 15};
|
||||
const ciblesGaldrSD = { "1": 3, "2_4": 6, "5_9": 9, "10_49": 12, "50plus": 15};
|
||||
const zonesciblesGaldrSD = { "INS10cm3": 3, "INS50cm3": 6, "INS1m3": 9, "INS5m3": 12, "INS10m3": 15};
|
||||
|
||||
export class YggdrasillRoll extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData ) {
|
||||
|
||||
let html
|
||||
let h = 440;
|
||||
if ( rollData.mode == "competence") {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-competence.html', rollData);
|
||||
h = 340;
|
||||
} else if (rollData.mode == "carac") {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-carac.html', rollData);
|
||||
h = 320;
|
||||
} else if (rollData.mode == "attribut") {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-attribut.html', rollData);
|
||||
h = 320;
|
||||
} else if (rollData.mode == "armecc") {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-armecc.html', rollData);
|
||||
} else if (rollData.mode == "sejdr") {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-sejdr.html', rollData);
|
||||
} else if (rollData.mode == "rune") {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-rune.html', rollData);
|
||||
} else if (rollData.mode == "galdr") {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-galdr.html', rollData);
|
||||
} else {
|
||||
html = await renderTemplate('systems/fvtt-yggdrasill/templates/roll-dialog-armetir.html', rollData);
|
||||
}
|
||||
let options = { classes: ["yggdrasilldialog"], width: 600, height: h, 'z-index': 99999 };
|
||||
return new YggdrasillRoll(actor, rollData, html, options );
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: (rollData.mode == "competence") ? "Compétence" : "Caractéristique",
|
||||
content: html,
|
||||
buttons: {
|
||||
roll: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Lancer le Test",
|
||||
callback: () => { this.roll() }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Annuler",
|
||||
callback: () => { this.close() }
|
||||
} },
|
||||
default: "Roll",
|
||||
close: close
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
roll () {
|
||||
if ( this.rollData.mode == "attribut") {
|
||||
YggdrasillUtility.rollAttribute(this.rollData)
|
||||
} else {
|
||||
YggdrasillUtility.rollYggdrasill( this.rollData )
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateGaldrSR( ) {
|
||||
let sdDuree = Number(dureeGaldrSD[this.rollData.dureeGaldr]);
|
||||
let sdVar = 0;
|
||||
if ( this.rollData.sort.data.voie == "illusion") {
|
||||
sdVar = Number(zonesciblesGaldrSD[this.rollData.zoneGaldr]);
|
||||
} else {
|
||||
sdVar = Number(ciblesGaldrSD[this.rollData.nbCibles]);
|
||||
}
|
||||
let SR = Number(this.rollData.sort.data.sd) + sdDuree + sdVar;
|
||||
$("#srTotal").text(SR);
|
||||
this.rollData.sr = SR;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateRuneSR() {
|
||||
let support = 0;
|
||||
|
||||
this.rollData.dureeRune = 6 - this.rollData.agiliteCarac.value;
|
||||
if ( this.rollData.supportRune == "peau") {
|
||||
support = 3;
|
||||
this.rollData.echelleDuree = "Actions";
|
||||
}
|
||||
if ( this.rollData.supportRune == "tissu") {
|
||||
support = 6;
|
||||
this.rollData.echelleDuree = "Tours";
|
||||
}
|
||||
if ( this.rollData.supportRune == "cuir") {
|
||||
support = 9;
|
||||
this.rollData.echelleDuree = "Minutes";
|
||||
}
|
||||
if ( this.rollData.supportRune == "bois") {
|
||||
support = 12;
|
||||
this.rollData.echelleDuree = "Heures";
|
||||
}
|
||||
if ( this.rollData.supportRune == "pierremetal") {
|
||||
support = 15;
|
||||
this.rollData.echelleDuree = "Jours";
|
||||
}
|
||||
let SR = this.rollData.puissanceRune + (Number(this.rollData.sort.data.niveau)*3) + support;
|
||||
$("#srTotal").text(SR);
|
||||
$("#runeDuree").text( this.rollData.dureeRune + " " + this.rollData.echelleDuree);
|
||||
$("#runeDureeVie").text( this.rollData.puissanceRune + " " + this.rollData.echelleDuree);
|
||||
this.rollData.sr = SR;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
var dialog = this;
|
||||
function onLoad() {
|
||||
if (dialog.rollData.mode == "competence") {
|
||||
let carac = dialog.actor.getCarac( "Puissance" );
|
||||
dialog.rollData.selectedCarac = carac;
|
||||
} else if (dialog.rollData.mode == "armecc" || dialog.rollData.mode == "armedist" ) {
|
||||
$("#caracName").text(dialog.rollData.selectedCarac.label);
|
||||
$("#attackDescr").text(dialog.rollData.attackDef.description);
|
||||
} else if ( dialog.rollData.mode == "sejdr" || dialog.rollData.mode == "rune" || dialog.rollData.mode == "galdr" ) {
|
||||
$("#caracName").text(dialog.rollData.selectedCarac.label);
|
||||
}
|
||||
if (dialog.rollData.mode == "rune" ) {
|
||||
dialog.updateRuneSR();
|
||||
}
|
||||
if (dialog.rollData.mode == "galdr" ) {
|
||||
dialog.updateGaldrSR();
|
||||
}
|
||||
if (dialog.rollData.mode == "attribut") {
|
||||
$("#attrValue").text("2d10+"+dialog.rollData.subAttr.value);
|
||||
} else {
|
||||
$("#caracValue").text(dialog.rollData.selectedCarac.value+"d10");
|
||||
}
|
||||
}
|
||||
$(function () { onLoad(); });
|
||||
|
||||
html.find('#caracName').change((event) => {
|
||||
let caracKey = event.currentTarget.value;
|
||||
let carac = this.actor.getCarac( caracKey );
|
||||
this.rollData.selectedCarac = carac;
|
||||
$("#caracValue").text(carac.value+"d10");
|
||||
});
|
||||
|
||||
html.find('#typeAttack').change((event) => {
|
||||
let attackType = event.currentTarget.value;
|
||||
let attackDef
|
||||
if ( this.rollData.mode == 'armecc')
|
||||
attackDef = this.actor.getAttaqueData( attackType);
|
||||
else
|
||||
attackDef = this.actor.getTirData( attackType);
|
||||
this.rollData.attackDef = attackDef;
|
||||
this.rollData.selectedCarac = attackDef.carac;
|
||||
$("#caracValue").text(attackDef.carac.value+"d10");
|
||||
$("#caracName").text(attackDef.carac.label);
|
||||
$("#attackDescr").text(attackDef.description);
|
||||
$("#malus").text(attackDef.malus);
|
||||
});
|
||||
|
||||
html.find('#supportRune').change((event) => {
|
||||
this.rollData.supportRune = event.currentTarget.value;
|
||||
this.updateRuneSR();
|
||||
});
|
||||
html.find('#puissanceRune').change((event) => {
|
||||
this.rollData.puissanceRune = Number(event.currentTarget.value);
|
||||
this.updateRuneSR();
|
||||
});
|
||||
|
||||
html.find('#dureeGaldr').change((event) => {
|
||||
this.rollData.dureeGaldr = event.currentTarget.value;
|
||||
this.updateGaldrSR();
|
||||
});
|
||||
html.find('#nbCibles').change((event) => {
|
||||
this.rollData.nbCibles = event.currentTarget.value;
|
||||
this.updateGaldrSR();
|
||||
});
|
||||
html.find('#zoneGaldr').change((event) => {
|
||||
this.rollData.zoneGaldr = event.currentTarget.value;
|
||||
this.updateGaldrSR();
|
||||
});
|
||||
|
||||
|
||||
html.find('#bonusMalus').change((event) => {
|
||||
this.rollData.bonusMalus = Number(event.currentTarget.value);
|
||||
});
|
||||
html.find('#furorUsage').change((event) => {
|
||||
this.rollData.furorUsage = Number(event.currentTarget.value);
|
||||
});
|
||||
html.find('#sr').change((event) => {
|
||||
this.rollData.sr = Number(event.currentTarget.value);
|
||||
});
|
||||
html.find('#bonusdefense').change((event) => {
|
||||
this.rollData.bonusdefense = Number(event.currentTarget.value);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +1,47 @@
|
||||
/* -------------------------------------------- */
|
||||
/* -------------------------------------------- */
|
||||
//import { YggdrasillCombat } from "./yggdrasill-combat.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* -------------------------------------------- */
|
||||
const dureeGaldrText = { "1d5a": "Actions", "1d10t": "Tours", "1d10m": "Minutes", "1d10h": "Heures", "1d5j": "Jours"};
|
||||
const ciblesGaldrText = { "1": "1", "2_4": "2 à 4", "5_9": "5 à 9", "10_49": "10 à 49", "50plus": "50 et plus"};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* -------------------------------------------- */
|
||||
export class YggdrasillUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async preloadHandlebarsTemplates() {
|
||||
|
||||
const templatePaths = [
|
||||
'systems/fvtt-yggdrasill/templates/actor-sheet.html',
|
||||
'systems/fvtt-yggdrasill/templates/editor-notes-gm.html',
|
||||
'systems/fvtt-yggdrasill/templates/hud-actor-attaque.html',
|
||||
'systems/fvtt-yggdrasill/templates/hud-actor-sort.html'
|
||||
]
|
||||
return loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async preloadHandlebarsTemplates() {
|
||||
static templateData(it) {
|
||||
return YggdrasillUtility.data(it)?.data ?? {}
|
||||
}
|
||||
|
||||
const templatePaths = [
|
||||
'systems/fvtt-yggdrasill/templates/actor-personnage-sheet.hbs',
|
||||
'systems/fvtt-yggdrasill/templates/editor-notes-gm.html'
|
||||
]
|
||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||
/* -------------------------------------------- */
|
||||
static data(it) {
|
||||
if (it instanceof Actor || it instanceof Item || it instanceof Combatant) {
|
||||
return it.data;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static createDirectSortedOptionList( min, max) {
|
||||
let options = [];
|
||||
for(let i=min; i<=max; i++) {
|
||||
for(let i=min; i<=max; i++) {
|
||||
options.push( {value:i, text: `${i}` } );
|
||||
}
|
||||
return options;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static createOptions( min, max) {
|
||||
let options = [];
|
||||
for(let i=min; i<=max; i++) {
|
||||
options.push( {key:i, label: `${i}` } );
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static createDirectOptionList( min, max) {
|
||||
let options = {};
|
||||
@@ -50,6 +59,23 @@ export class YggdrasillUtility {
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildSROptions( ) {
|
||||
let options = ""
|
||||
options += `<option value="0">Aucun</option>`
|
||||
options += `<option value="5">Très Simple (5)</option>`
|
||||
options += `<option value="7">Simple (7)</option>`
|
||||
options += `<option value="10">Aisé (10)</option>`
|
||||
options += `<option value="14">Moyen (14)</option>`
|
||||
options += `<option value="19">Difficile (19)</option>`
|
||||
options += `<option value="25">Trés Difficile (25)</option>`
|
||||
options += `<option value="32">Exceptionnel (32)</option>`
|
||||
options += `<option value="40">Légendaire (40)</option>`
|
||||
options += `<option value="49">Divin (49)</option>`
|
||||
return options;
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onSocketMesssage( msg ) {
|
||||
@@ -72,78 +98,41 @@ export class YggdrasillUtility {
|
||||
return compendiumData.filter(filter);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async specificYggRoll( nbDice, isFurorUsage = false) {
|
||||
let rawDices = []
|
||||
let rolls = []
|
||||
let maxTab = []
|
||||
let maxTabMaxIndex = isFurorUsage ? nbDice : 2;
|
||||
|
||||
for (let i=0; i<nbDice; i++) {
|
||||
rolls[i] = await new Roll("1d10x10").roll( ) //+sumDice+"+"+rollData.furorUsage+"d10+"+niveauCompetence+"+"+rollData.finalBM).roll( { async: false} );
|
||||
if ( i == nbDice-1 ) {
|
||||
await this.showDiceSoNice(rolls[i], game.settings.get("core", "rollMode") );
|
||||
} else {
|
||||
this.showDiceSoNice(rolls[i], game.settings.get("core", "rollMode") );
|
||||
}
|
||||
rawDices.push({ 'result': rolls[i].total});
|
||||
}
|
||||
|
||||
rolls.sort((a,b) => a.total-b.total);
|
||||
rolls.reverse();
|
||||
|
||||
for (let i=0; i<maxTabMaxIndex; i++) {
|
||||
maxTab[i] = {idx: 0, value: 0};
|
||||
if (rolls[i]?.total != undefined) maxTab[i].value = rolls[i].total;
|
||||
}
|
||||
|
||||
return { rawDices: rawDices, maxTab: maxTab, rolls: rolls }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rollAttribute( rollData ) {
|
||||
// Init stuff
|
||||
let isCritical = false;
|
||||
let isFailure = false;
|
||||
let isSuccess = false;
|
||||
let marge = 0;
|
||||
let marge = 0;
|
||||
let niveau = rollData.subAttr.value;
|
||||
|
||||
// Bonus/Malus total
|
||||
rollData.finalBM = Number(rollData.bonusMalus);
|
||||
rollData.finalBM = rollData.bonusMalus;
|
||||
// Gestion cas blessé (malus de -3)
|
||||
if ( rollData.isBlesse) { // Cas blesse : malus de -3
|
||||
rollData.finalBM -= 3;
|
||||
}
|
||||
|
||||
let results = await this.specificYggRoll( 2 )
|
||||
rollData.rawDices = results.rawDices
|
||||
rollData.maxTab = results.maxTab
|
||||
rollData.rolls = results.rolls
|
||||
rollData.bonus = niveau + Number(rollData.finalBM)
|
||||
|
||||
rollData.finalTotal = Number(rollData.maxTab[0].value) + Number(rollData.maxTab[1].value);
|
||||
rollData.finalTotal += Number(rollData.bonus)
|
||||
|
||||
let myRoll = new Roll("2d10+"+niveau+"+"+rollData.finalBM).roll( { async: false} );
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode") );
|
||||
|
||||
// Compute total SR
|
||||
rollData.srFinal = Number(rollData.sr);
|
||||
if ( rollData.bonusdefense ) {
|
||||
rollData.srFinal += Number(rollData.bonusdefense);
|
||||
}
|
||||
if ( rollData.srFinal > 0 ) {
|
||||
isCritical = rollData.finalTotal >= rollData.srFinal*2;
|
||||
isSuccess = rollData.finalTotal >= rollData.srFinal;
|
||||
marge = rollData.finalTotal - rollData.srFinal;
|
||||
rollData.srFinal = rollData.sr;
|
||||
if ( rollData.srFinal > 0 ) {
|
||||
isCritical = myRoll.total >= rollData.srFinal*2;
|
||||
isSuccess = myRoll.total >= rollData.srFinal;
|
||||
marge = myRoll.total - rollData.srFinal;
|
||||
}
|
||||
|
||||
if (rollData.rolls[0].dice[0].results[0].result == 1 && rollData.rolls[1].dice[0].results[0].result == 1) {
|
||||
if (myRoll.dice[0].results[0].result == 1 && myRoll.dice[0].results[1].result == 1) {
|
||||
isFailure = true;
|
||||
}
|
||||
// Dégats
|
||||
if ( isSuccess && rollData.subAttr.degats ) {
|
||||
rollData.degatsExplain = `Marge(${marge}) + Physique(${rollData.valuePhysique}) + 1d10`;
|
||||
rollData.rollDegats = await new Roll("1d10+"+marge+"+"+rollData.valuePhysique).roll( );
|
||||
await this.showDiceSoNice(rollData.rollDegats, game.settings.get("core", "rollMode") );
|
||||
rollData.rollDegats = new Roll("1d10+"+marge+"+"+rollData.valuePhysique).roll( { async: false} );
|
||||
await this.showDiceSoNice(rollData.rollDegats, game.settings.get("core", "rollMode") );
|
||||
rollData.degats = rollData.rollDegats.total;
|
||||
}
|
||||
|
||||
@@ -152,106 +141,83 @@ export class YggdrasillUtility {
|
||||
rollData.isSuccess = isSuccess;
|
||||
rollData.isCritical = isCritical;
|
||||
rollData.marge = marge;
|
||||
rollData.roll = myRoll
|
||||
|
||||
console.log("ROLLLL ATTR!!!!", rollData);
|
||||
|
||||
this.createChatWithRollMode( rollData.alias, {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result-new.hbs`, rollData)
|
||||
content: await renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result.html`, rollData)
|
||||
});
|
||||
//myRoll.toMessage();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rollYggdrasill( rollData ) {
|
||||
let sumDice = ( rollData.isEpuise | rollData.isMeurtri) ? 1 : 2;
|
||||
|
||||
let sumDice = ( rollData.isEpuise | rollData.isMeurtri | rollData.isBlesse) ? 1 : 2;
|
||||
|
||||
// Init stuff
|
||||
let isCritical = false;
|
||||
let isFailure = false;
|
||||
let isSuccess = false;
|
||||
let marge = 0;
|
||||
let marge = 0;
|
||||
let nbDice = rollData.selectedCarac.value;
|
||||
let niveauCompetence = 0;
|
||||
|
||||
|
||||
// Select niveau de competence/arme/carac
|
||||
if ( rollData.mode != "carac" ) {
|
||||
niveauCompetence = rollData.competence.system.niveau;
|
||||
niveauCompetence = rollData.competence.data.niveau;
|
||||
} else {
|
||||
niveauCompetence = rollData.selectedCarac.value;
|
||||
}
|
||||
|
||||
// Bonus/Malus total
|
||||
rollData.finalBM = Number(rollData.bonusMalus);
|
||||
rollData.finalBM = rollData.bonusMalus;
|
||||
if ( rollData.attackDef) {
|
||||
rollData.finalBM -= rollData.attackDef.malus;
|
||||
}
|
||||
if ( rollData?.sort?.system?.malus ) {
|
||||
rollData.finalBM += rollData.sort.system.malus;
|
||||
if ( rollData.sort && rollData.sort.data.malus ) {
|
||||
rollData.finalBM += rollData.sort.data.malus;
|
||||
}
|
||||
// Gestion cas blessé (malus de -3)
|
||||
if ( rollData.isBlesse) { // Cas blesse : malus de -3
|
||||
rollData.finalBM -= 3;
|
||||
}
|
||||
|
||||
|
||||
if (sumDice > nbDice) sumDice = nbDice;
|
||||
let results = await this.specificYggRoll( nbDice )
|
||||
rollData.rawDices = results.rawDices
|
||||
rollData.maxTab = results.maxTab
|
||||
rollData.rolls = results.rolls
|
||||
console.log("RES", results, nbDice, sumDice)
|
||||
let myRoll = new Roll(nbDice+"d10x10kh"+sumDice+"+"+rollData.furorUsage+"d10+"+niveauCompetence+"+"+rollData.finalBM).roll( { async: false} );
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode") );
|
||||
|
||||
// Compute total SR
|
||||
rollData.srFinal = rollData.sr;
|
||||
if ( rollData.bonusdefense ) {
|
||||
rollData.srFinal += rollData.bonusdefense;
|
||||
}
|
||||
if ( rollData.srFinal > 0 ) {
|
||||
isCritical = myRoll.total >= rollData.srFinal*2;
|
||||
isSuccess = myRoll.total >= rollData.srFinal;
|
||||
marge = myRoll.total - rollData.srFinal;
|
||||
}
|
||||
|
||||
rollData.rawDices = duplicate(myRoll.dice[0].results);
|
||||
if (nbDice == 1 && myRoll.dice[0].results[0].result == 1) {
|
||||
isFailure = true;
|
||||
}
|
||||
if (nbDice == 2 && myRoll.dice[0].results[0].result == 1 && myRoll.dice[0].results[1].result == 1) {
|
||||
isFailure = true;
|
||||
}
|
||||
if (nbDice >= 3 ) {
|
||||
let nbOnes = myRoll.dice[0].results.filter( dice => dice.result == 1);
|
||||
isFailure = nbOnes.length >= 3;
|
||||
}
|
||||
if ( rollData.furorUsage > 0 ) {
|
||||
results = await this.specificYggRoll( rollData.furorUsage, true )
|
||||
rollData.furorRawDices = results.rawDices
|
||||
rollData.furorMaxTab = results.maxTab
|
||||
rollData.furorRolls = results.rolls
|
||||
let actor = game.actors.get(rollData.actorId);
|
||||
actor.decrementFuror( rollData.furorUsage);
|
||||
}
|
||||
|
||||
rollData.bonusTotal = niveauCompetence + rollData.finalBM
|
||||
rollData.finalTotal = (sumDice ==1) ? rollData.maxTab[0].value : rollData.maxTab[0].value + rollData.maxTab[1].value;
|
||||
rollData.furorResult = 0
|
||||
for (let i=0; i<rollData.furorUsage; i++) {
|
||||
rollData.furorResult += rollData.furorMaxTab[i].value
|
||||
}
|
||||
rollData.finalTotal += Number(rollData.furorResult) + Number(rollData.bonusTotal);
|
||||
rollData.niveauCompetence = niveauCompetence
|
||||
|
||||
// Compute total SR
|
||||
// Pour les sorts, utiliser srTotal si calculé, sinon sr + bonusdefense
|
||||
if (rollData.srTotal !== undefined) {
|
||||
rollData.srFinal = rollData.srTotal
|
||||
} else {
|
||||
rollData.srFinal = rollData.sr
|
||||
if (rollData.bonusdefense) {
|
||||
rollData.srFinal += rollData.bonusdefense
|
||||
}
|
||||
}
|
||||
|
||||
if ( rollData.srFinal > 0 ) {
|
||||
isCritical = rollData.finalTotal >= rollData.srFinal*2;
|
||||
isSuccess = rollData.finalTotal >= rollData.srFinal;
|
||||
marge = rollData.finalTotal - rollData.srFinal;
|
||||
}
|
||||
|
||||
if (nbDice == 1 && rollData.rolls[0].dice[0].results[0].result == 1) {
|
||||
isFailure = true;
|
||||
}
|
||||
if (nbDice == 2 && rollData.rolls[0].dice[0].results[0].result == 1 && rollData.rolls[1].dice[0].results[0].result == 1) {
|
||||
isFailure = true;
|
||||
}
|
||||
if (nbDice >= 3 ) {
|
||||
let nbOnes = 0
|
||||
for (let roll of rollData.rolls) {
|
||||
if (roll.dice[0].results[0].result == 1 ) nbOnes++;
|
||||
}
|
||||
isFailure = nbOnes >= 3;
|
||||
}
|
||||
|
||||
// Dégats
|
||||
if ( isSuccess && (rollData.mode == "armecc" || rollData.mode == "armedist") ) {
|
||||
rollData.degatsExplain = `Marge(${marge}) + Degats Arme(${rollData.arme.system.degat}) + Bonus Attaque(${rollData.attackDef.bonusdegats})`;
|
||||
rollData.degats = marge + rollData.arme.system.degat + rollData.attackDef.bonusdegats;
|
||||
rollData.degatsExplain = `Marge(${marge}) + Degats Arme(${rollData.arme.data.degat}) + Bonus Attaque(${rollData.attackDef.bonusdegats})`;
|
||||
rollData.degats = marge + rollData.arme.data.degat + rollData.attackDef.bonusdegats;
|
||||
}
|
||||
|
||||
// Stockage resultats
|
||||
@@ -260,13 +226,14 @@ export class YggdrasillUtility {
|
||||
rollData.isSuccess = isSuccess;
|
||||
rollData.isCritical = isCritical;
|
||||
rollData.marge = marge;
|
||||
rollData.roll = myRoll
|
||||
|
||||
// Specific GALDR
|
||||
if ( rollData.sort?.type == "sortgaldr" && rollData.isSuccess) {
|
||||
let galdrRoll = await new Roll( rollData.dureeGaldr.substring(0, rollData.dureeGaldr.length - 1) ).roll( );
|
||||
let galdrRoll = new Roll( rollData.dureeGaldr.substring(0, rollData.dureeGaldr.length - 1) ).roll( { async: false} );
|
||||
await this.showDiceSoNice(galdrRoll, game.settings.get("core", "rollMode") );
|
||||
rollData.dureeGaldrText = galdrRoll.total + " " + dureeGaldrText[rollData.dureeGaldr];
|
||||
if ( rollData.sort.system.voie == "illusion") {
|
||||
if ( rollData.sort.data.voie == "illusion") {
|
||||
let volume = rollData.zoneGaldr.substring(3, rollData.zoneGaldr.length);
|
||||
rollData.zoneGaldrText = rollData.instinctCarac.value + " x " + volume;
|
||||
} else {
|
||||
@@ -277,13 +244,14 @@ export class YggdrasillUtility {
|
||||
console.log("ROLLLL!!!!", rollData);
|
||||
|
||||
this.createChatWithRollMode( rollData.alias, {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result-new.hbs`, rollData)
|
||||
content: await renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result.html`, rollData)
|
||||
});
|
||||
//myRoll.toMessage();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getUsers(filter) {
|
||||
return game.users.filter(filter).map(user => user.system._id);
|
||||
return game.users.filter(filter).map(user => user.data._id);
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipients(rollMode, name) {
|
||||
@@ -303,7 +271,7 @@ export class YggdrasillUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static blindMessageToGM(chatOptions) {
|
||||
let chatGM = foundry.utils.duplicate(chatOptions);
|
||||
let chatGM = duplicate(chatOptions);
|
||||
chatGM.whisper = this.getUsers(user => user.isGM);
|
||||
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content;
|
||||
console.log("blindMessageToGM", chatGM);
|
||||
@@ -336,7 +304,7 @@ export class YggdrasillUtility {
|
||||
static createChatWithRollMode(name, chatOptions) {
|
||||
this.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async confirmDelete(actorSheet, li) {
|
||||
let itemId = li.data("item-id");
|
||||
@@ -365,7 +333,7 @@ export class YggdrasillUtility {
|
||||
d.render(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async showDiceSoNice(roll, rollMode) {
|
||||
if (game.modules.get("dice-so-nice")?.active) {
|
||||
|
||||
4971
package-lock.json
generated
4971
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "fvtt-yggdrasill",
|
||||
"version": "12.0.0",
|
||||
"description": "Yggdrasill RPG for FoundryVTT - French",
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"watch": "gulp watch"
|
||||
},
|
||||
"author": "Uberwald/LeRatierBretonnien",
|
||||
"license": "SEE LICENSE IN LICENCE.txt",
|
||||
"devDependencies": {
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-less": "^5.0.0",
|
||||
"gulp-sourcemaps": "^3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
[Dolphin]
|
||||
HeaderColumnWidths=544,73,106,72
|
||||
SortOrder=1
|
||||
SortRole=modificationtime
|
||||
Timestamp=2022,2,5,12,44,17.076
|
||||
Timestamp=2021,9,21,17,43,45.19
|
||||
Version=4
|
||||
ViewMode=1
|
||||
VisibleRoles=Details_text,Details_size,Details_modificationtime,Details_creationtime,CustomizedDetails
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
{"name":"Lance cc","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"hast","equipe":false,"degat":10,"solidite":11,"enc":2,"valeur":4,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"xMRAVbweHG0aMBNR":3},"flags":{"core":{"sourceId":"Item.KPPt0lyDyEac7SPi"}},"_id":"3VBHojfjdD504ibv"}
|
||||
{"name":"Casque","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":3,"enc":2,"valeur":2,"description":"<p>Le modèle le plus fréquent comporte un nasal et des « lunettes » qui protègent les yeux. Sur une base de bol en métal, des lamelles de renforts sont rivetées afin d’assurer la rigidité de l’ensemble. L’intérieur est doublé de cuir et de tissu afin d’amortir les chocs.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"8MoqC7EIc3SXtdsN"}
|
||||
{"_id":"8aaaIqx6uT1sJ0RO","name":"Lance","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"jet","equipe":false,"degat":8,"solidite":11,"enc":4,"portee":"5/10/15/30","valeur":4,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Cuir lamellé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":6,"enc":3,"valeur":2,"description":"<p>Des lamelles de cuir plus rigides sont collées et cousues sur la version précédente. La poitrine, le ventre, les omoplates et les coudes sont particulièrement renforcés. Des pièces semi-rigides, bombées, enserrent parfois les épaules.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"B2yc8LDKTRl0Hjxt"}
|
||||
{"name":"Hache de guerre","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"longue","equipe":false,"degat":9,"solidite":10,"enc":2,"valeur":1,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"BwmkCCiJWME4CpB0"}
|
||||
{"name":"Poignard cc","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"courte","equipe":false,"degat":3,"solidite":9,"enc":0,"valeur":0.5,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"xMRAVbweHG0aMBNR":3},"flags":{"core":{"sourceId":"Item.jLtQv1SAt8pkMGqa"}},"_id":"CwrTGdva6vQVz0aQ"}
|
||||
{"name":"Epaullières de fourrure","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":2,"enc":1,"valeur":0.6,"description":"<p>Il s’agit d’un grand morceau de peau encerclant les épaules et le cou. En général, cette fourrure est fixée sur une cape. En plus de la protection qu’elle apporte, sa nature (loup, ours, vison, etc.. ) donne une indication sur le statut du guerrier.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"C2mzwxiCPJWoY8kc"}
|
||||
{"name":"Epée courte","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"longue","equipe":false,"degat":5,"solidite":11,"enc":0,"valeur":2,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"FGIja8vhUOeGNC4x"}
|
||||
{"name":"Longue hache","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"deuxmains","equipe":false,"degat":14,"solidite":12,"enc":3,"valeur":3,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"GqAbMhROpATanmH3"}
|
||||
{"name":"Hache de jet","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"jet","equipe":false,"degat":4,"solidite":8,"enc":0,"portee":"3/6/9/15","valeur":0.3,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"IZRpi8jq9erpiyoy"}
|
||||
{"_id":"MkEW9Ma5m9nlE0nr","name":"Poignard","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"jet","equipe":false,"degat":3,"solidite":9,"enc":0,"portee":"3/6/9/12","valeur":0.5,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"_id":"MkEW9Ma5m9nlE0nr","name":"Poignard","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"jet","equipe":false,"degat":3,"solidite":9,"enc":2,"portee":"3/6/9/12","valeur":0.4,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":4,"enc":1,"valeur":1,"description":"<p>La veste devient plus épaisse et doublée de tissu. Des pièces de métal, des rivets plats en cuivre, en bronze ou en fer apportent une protection supplémentaire aux zones les plus exposées. Le col monte parfois jusque sous le menton.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"P6dSkefY97UqdDj9"}
|
||||
{"name":"Arc de chasse","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"tir","equipe":false,"degat":6,"solidite":8,"enc":2,"portee":"10/20/40/80","valeur":1,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"PsqO2GFVTFIeyCmQ"}
|
||||
{"name":"Bracelets de cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":1,"enc":0,"valeur":0.3,"description":"<p>Ils protègent l’avant-bras, du dessus de la main jusqu’au coude. Souvent gravés de motifs décoratifs, ils se composent de lamelles de cuir rigidifiées et nouées à l’aide de gros lacets.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"RgYAFOOAh7GGzBaF"}
|
||||
{"name":"Jambières de cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":2,"enc":1,"valeur":0.4,"description":"<p>Nouées autour des cuisses ou des mollets, elles protègent le combattant des coups visant ses jambes. Ici aussi, les artisans essaient souvent d’orner ces pièces d’armure de décorations ciselées dans la matière.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"SpTt7wfW9qBKJDxX"}
|
||||
{"name":"Veste de cuir","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":2,"enc":0,"valeur":0.3,"description":"<p>Il s’agit autant d’un vêtement courant que d’une armure. La veste recouvre le torse, le ventre et les hanches. Certaines possèdent des manches, courtes ou longues. Le cuir souple et fin ne restreint guère la liberté de mouvement.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"WrJ7Q4e556LDolbu"}
|
||||
{"name":"Hachette","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"courte","equipe":false,"degat":4,"solidite":8,"enc":0,"valeur":0.3,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"fjIHt6jNRAM25L9q"}
|
||||
{"name":"Arc de guerre","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"tir","equipe":false,"degat":7,"solidite":10,"enc":2,"portee":"10/30/50/100","valeur":2,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"jSrZnzjI0QVWuXw8"}
|
||||
{"name":"Javeline","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"jet","equipe":false,"degat":6,"solidite":7,"enc":2,"portee":"5/10/20/40","valeur":0.4,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"m6PjnSO3ACnzU0ie"}
|
||||
{"name":"Cotte de mailles","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":9,"enc":5,"valeur":8,"description":"<p>Composée de centaines d’anneaux de fer rivetés, la cotte de mailles protège les mêmes parties du corps qu’une veste. Elle ne descend jamais sur les jambes car cela restreint trop la mobilité des combattants. Ceux-ci enfilent dessous une chemise molletonnée ou une fine veste de cuir.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"n9eKutLHJZoBYFAD"}
|
||||
{"name":"Epée à deux mains","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"deuxmains","equipe":false,"degat":12,"solidite":14,"enc":3,"valeur":5,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"ptcBNQhYLwWkBkc0"}
|
||||
{"name":"Epée longue","type":"armecc","img":"icons/svg/item-bag.svg","data":{"categorie":"longue","equipe":false,"degat":7,"solidite":11,"enc":1,"valeur":4,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"rpY7aUxJelvsozvh"}
|
||||
{"name":"Fronde","type":"armedist","img":"icons/svg/item-bag.svg","data":{"categorie":"tir","equipe":false,"degat":4,"solidite":12,"enc":0,"portee":"10/20/30/40","valeur":0.1,"description":""},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"x3aMYeKa73GxJ1Ge"}
|
||||
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
MANIFEST-000053
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:42:43.362261 7fd478fff6c0 Recovering log #51
|
||||
2026/01/11-22:42:43.390767 7fd478fff6c0 Delete type=0 #51
|
||||
2026/01/11-22:42:43.398607 7fd478fff6c0 Delete type=3 #49
|
||||
2026/01/11-22:44:34.484930 7fd4627fc6c0 Level-0 table #56: started
|
||||
2026/01/11-22:44:34.484958 7fd4627fc6c0 Level-0 table #56: 0 bytes OK
|
||||
2026/01/11-22:44:34.491990 7fd4627fc6c0 Delete type=0 #54
|
||||
2026/01/11-22:44:34.498603 7fd4627fc6c0 Manual compaction at level-0 from '!items!3VBHojfjdD504ibv' @ 72057594037927935 : 1 .. '!items!x3aMYeKa73GxJ1Ge' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:44:34.498641 7fd4627fc6c0 Manual compaction at level-1 from '!items!3VBHojfjdD504ibv' @ 72057594037927935 : 1 .. '!items!x3aMYeKa73GxJ1Ge' @ 0 : 0; will stop at (end)
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:38:18.324856 7fd4637fe6c0 Recovering log #47
|
||||
2026/01/11-22:38:18.334440 7fd4637fe6c0 Delete type=3 #45
|
||||
2026/01/11-22:38:18.334494 7fd4637fe6c0 Delete type=0 #47
|
||||
2026/01/11-22:39:21.508921 7fd4627fc6c0 Level-0 table #52: started
|
||||
2026/01/11-22:39:21.508963 7fd4627fc6c0 Level-0 table #52: 0 bytes OK
|
||||
2026/01/11-22:39:21.514976 7fd4627fc6c0 Delete type=0 #50
|
||||
2026/01/11-22:39:21.515163 7fd4627fc6c0 Manual compaction at level-0 from '!items!3VBHojfjdD504ibv' @ 72057594037927935 : 1 .. '!items!x3aMYeKa73GxJ1Ge' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:39:21.515223 7fd4627fc6c0 Manual compaction at level-1 from '!items!3VBHojfjdD504ibv' @ 72057594037927935 : 1 .. '!items!x3aMYeKa73GxJ1Ge' @ 0 : 0; will stop at (end)
|
||||
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
{"_id":"4YGPuZ813BWQaNbq","name":"Bracelets de cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"piecearmure","equipe":false,"protection":1,"enc":0,"valeur":0.3,"description":"<p>Ils protègent l’avant-bras, du dessus de la main jusqu’au coude. Souvent gravés de motifs décoratifs, ils se composent de lamelles de cuir rigidifiées et nouées à l’aide de gros lacets.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Bracelets de cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":1,"enc":0,"valeur":0.3,"description":"<p>Ils protègent l’avant-bras, du dessus de la main jusqu’au coude. Souvent gravés de motifs décoratifs, ils se composent de lamelles de cuir rigidifiées et nouées à l’aide de gros lacets.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"4YGPuZ813BWQaNbq"}
|
||||
{"name":"Cuir lamellé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":6,"enc":3,"valeur":2,"description":"<p>Des lamelles de cuir plus rigides sont collées et cousues sur la version précédente. La poitrine, le ventre, les omoplates et les coudes sont particulièrement renforcés. Des pièces semi-rigides, bombées, enserrent parfois les épaules.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"9WReqm0CdcCGnsNc"}
|
||||
{"name":"Veste de cuir","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":2,"enc":0,"valeur":0.3,"description":"<p>Il s’agit autant d’un vêtement courant que d’une armure. La veste recouvre le torse, le ventre et les hanches. Certaines possèdent des manches, courtes ou longues. Le cuir souple et fin ne restreint guère la liberté de mouvement.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"JP6OeUflKfg4WiyJ"}
|
||||
{"name":"Cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":4,"enc":1,"valeur":1,"description":"<p>La veste devient plus épaisse et doublée de tissu. Des pièces de métal, des rivets plats en cuivre, en bronze ou en fer apportent une protection supplémentaire aux zones les plus exposées. Le col monte parfois jusque sous le menton.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"MFH09YNp4uGL8eCE"}
|
||||
{"_id":"NK7IF0Cr4oOPCZVq","name":"Epaulières de fourrure","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"piecearmure","equipe":false,"protection":2,"enc":1,"valeur":0.6,"description":"<p>Il s’agit d’un grand morceau de peau encerclant les épaules et le cou. En général, cette fourrure est fixée sur une cape. En plus de la protection qu’elle apporte, sa nature (loup, ours, vison, etc.. ) donne une indication sur le statut du guerrier.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"_id":"WergjG9QE8SxlAGr","name":"Jambières de cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"piecearmure","equipe":false,"protection":2,"enc":1,"valeur":0.4,"description":"<p>Nouées autour des cuisses ou des mollets, elles protègent le combattant des coups visant ses jambes. Ici aussi, les artisans essaient souvent d’orner ces pièces d’armure de décorations ciselées dans la matière.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"_id":"ozRBKdYJtbnk87gO","name":"Casque","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"piecearmure","equipe":false,"protection":3,"enc":2,"valeur":2,"description":"<p>Le modèle le plus fréquent comporte un nasal et des « lunettes » qui protègent les yeux. Sur une base de bol en métal, des lamelles de renforts sont rivetées afin d’assurer la rigidité de l’ensemble. L’intérieur est doublé de cuir et de tissu afin d’amortir les chocs.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Epaullières de fourrure","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":2,"enc":1,"valeur":0.6,"description":"<p>Il s’agit d’un grand morceau de peau encerclant les épaules et le cou. En général, cette fourrure est fixée sur une cape. En plus de la protection qu’elle apporte, sa nature (loup, ours, vison, etc.. ) donne une indication sur le statut du guerrier.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"NK7IF0Cr4oOPCZVq"}
|
||||
{"name":"Jambières de cuir renforcé","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":2,"enc":1,"valeur":0.4,"description":"<p>Nouées autour des cuisses ou des mollets, elles protègent le combattant des coups visant ses jambes. Ici aussi, les artisans essaient souvent d’orner ces pièces d’armure de décorations ciselées dans la matière.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"WergjG9QE8SxlAGr"}
|
||||
{"name":"Casque","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":3,"enc":2,"valeur":2,"description":"<p>Le modèle le plus fréquent comporte un nasal et des « lunettes » qui protègent les yeux. Sur une base de bol en métal, des lamelles de renforts sont rivetées afin d’assurer la rigidité de l’ensemble. L’intérieur est doublé de cuir et de tissu afin d’amortir les chocs.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"ozRBKdYJtbnk87gO"}
|
||||
{"name":"Cotte de mailles","type":"armure","img":"icons/svg/item-bag.svg","data":{"categorie":"armure","equipe":false,"protection":9,"enc":5,"valeur":8,"description":"<p>Composée de centaines d’anneaux de fer rivetés, la cotte de mailles protège les mêmes parties du corps qu’une veste. Elle ne descend jamais sur les jambes car cela restreint trop la mobilité des combattants. Ceux-ci enfilent dessous une chemise molletonnée ou une fine veste de cuir.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"qUXBrstsh5Oo8FEx"}
|
||||
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
MANIFEST-000053
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:42:43.415431 7fd4637fe6c0 Recovering log #51
|
||||
2026/01/11-22:42:43.448752 7fd4637fe6c0 Delete type=0 #51
|
||||
2026/01/11-22:42:43.448972 7fd4637fe6c0 Delete type=3 #49
|
||||
2026/01/11-22:44:34.511453 7fd4627fc6c0 Level-0 table #56: started
|
||||
2026/01/11-22:44:34.511476 7fd4627fc6c0 Level-0 table #56: 0 bytes OK
|
||||
2026/01/11-22:44:34.517400 7fd4627fc6c0 Delete type=0 #54
|
||||
2026/01/11-22:44:34.523930 7fd4627fc6c0 Manual compaction at level-0 from '!items!4YGPuZ813BWQaNbq' @ 72057594037927935 : 1 .. '!items!qUXBrstsh5Oo8FEx' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:44:34.523965 7fd4627fc6c0 Manual compaction at level-1 from '!items!4YGPuZ813BWQaNbq' @ 72057594037927935 : 1 .. '!items!qUXBrstsh5Oo8FEx' @ 0 : 0; will stop at (end)
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:38:18.336786 7fd462ffd6c0 Recovering log #47
|
||||
2026/01/11-22:38:18.346917 7fd462ffd6c0 Delete type=3 #45
|
||||
2026/01/11-22:38:18.347006 7fd462ffd6c0 Delete type=0 #47
|
||||
2026/01/11-22:39:21.528136 7fd4627fc6c0 Level-0 table #52: started
|
||||
2026/01/11-22:39:21.528192 7fd4627fc6c0 Level-0 table #52: 0 bytes OK
|
||||
2026/01/11-22:39:21.534692 7fd4627fc6c0 Delete type=0 #50
|
||||
2026/01/11-22:39:21.541091 7fd4627fc6c0 Manual compaction at level-0 from '!items!4YGPuZ813BWQaNbq' @ 72057594037927935 : 1 .. '!items!qUXBrstsh5Oo8FEx' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:39:21.541131 7fd4627fc6c0 Manual compaction at level-1 from '!items!4YGPuZ813BWQaNbq' @ 72057594037927935 : 1 .. '!items!qUXBrstsh5Oo8FEx' @ 0 : 0; will stop at (end)
|
||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
MANIFEST-000053
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:42:43.343711 7fd478fff6c0 Recovering log #51
|
||||
2026/01/11-22:42:43.360165 7fd478fff6c0 Delete type=0 #51
|
||||
2026/01/11-22:42:43.360231 7fd478fff6c0 Delete type=3 #49
|
||||
2026/01/11-22:44:34.492077 7fd4627fc6c0 Level-0 table #56: started
|
||||
2026/01/11-22:44:34.492100 7fd4627fc6c0 Level-0 table #56: 0 bytes OK
|
||||
2026/01/11-22:44:34.498484 7fd4627fc6c0 Delete type=0 #54
|
||||
2026/01/11-22:44:34.498613 7fd4627fc6c0 Manual compaction at level-0 from '!items!4rM9IvDuijsjbAhI' @ 72057594037927935 : 1 .. '!items!swTZ43FJRWkqjR75' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:44:34.498635 7fd4627fc6c0 Manual compaction at level-1 from '!items!4rM9IvDuijsjbAhI' @ 72057594037927935 : 1 .. '!items!swTZ43FJRWkqjR75' @ 0 : 0; will stop at (end)
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:38:18.312395 7fd463fff6c0 Recovering log #47
|
||||
2026/01/11-22:38:18.322989 7fd463fff6c0 Delete type=3 #45
|
||||
2026/01/11-22:38:18.323061 7fd463fff6c0 Delete type=0 #47
|
||||
2026/01/11-22:39:21.501777 7fd4627fc6c0 Level-0 table #52: started
|
||||
2026/01/11-22:39:21.501807 7fd4627fc6c0 Level-0 table #52: 0 bytes OK
|
||||
2026/01/11-22:39:21.508771 7fd4627fc6c0 Delete type=0 #50
|
||||
2026/01/11-22:39:21.515149 7fd4627fc6c0 Manual compaction at level-0 from '!items!4rM9IvDuijsjbAhI' @ 72057594037927935 : 1 .. '!items!swTZ43FJRWkqjR75' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:39:21.515211 7fd4627fc6c0 Manual compaction at level-1 from '!items!4rM9IvDuijsjbAhI' @ 72057594037927935 : 1 .. '!items!swTZ43FJRWkqjR75' @ 0 : 0; will stop at (end)
|
||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
{"name":"Superstition","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Le monde regorge de signes divins, de détails naturels qui reflètent le sens caché des choses. Le personnage sait repérer et interpréter ces éléments. Il s’agit en général d’y voir des conditions favorables ou défavorables pour le moment présent, mais aussi des messages d’avertissement envoyés par les dieux. Les habitants de la Scandia sont des gens très superstitieux et ils tendent à voir partout des présages significatifs. Le Meneur de Jeu pourra en profiter pour glisser quelques indices obscurs sur la situation actuelle des héros qui, dans l’idéal, révèleront leur plein sens une fois qu’il sera trop tard.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"26CQEICWZs8Gw4Xi"}
|
||||
{"name":"Intimidation","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Par l’intermédiaire de la menace verbale ou physique, le personnage peut contraindre quelqu’un à lui obéir. Une tentative d’Intimidation nécessite un test en opposition. La cible tente de résister grâce à sa Ténacité et à sa Défense mentale.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"3vspCnDuVMqQDuPe"}
|
||||
{"name":"Négociation","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Il s’agit de la capacité à mener une discussion vers un compromis acceptable par les deux parties. Négociation est une compétence utile aux diplomates de la Scandia, mais aussi aux marchands qui peuvent mener à bien leur marchandage lors de l’achat et de la vente de leurs produits.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"4k4NLNlEG7jZEPK6"}
|
||||
{"_id":"6OMBvnSFqVHqd36u","name":"Jeux","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>le personnage connaît les règles et sait pratiquer la plupart des jeux prisés par les habitants de la Scandia, comme les jeux de dés ou le <em>hnefatafl</em>. Cette compétence s’utilise généralement avec des tests en opposition mettant en concurrence les niveaux de maîtrise respectifs des joueurs. Mais elle permet également de tricher. Dans ce cas, les autres participants peuvent tenter un test en opposition de Perception + Vigilance. Si le tricheur est démasqué, attendezvous à des conséquences… musclées.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Jeu","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>le personnage connaît les règles et sait pratiquer la plupart des jeux prisés par les habitants de la Scandia, comme les jeux de dés ou le <em>hnefatafl</em>. Cette compétence s’utilise généralement avec des tests en opposition mettant en concurrence les niveaux de maîtrise respectifs des joueurs. Mais elle permet également de tricher. Dans ce cas, les autres participants peuvent tenter un test en opposition de Perception + Vigilance. Si le tricheur est démasqué, attendezvous à des conséquences… musclées.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"6OMBvnSFqVHqd36u"}
|
||||
{"name":"Artisanat","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":true,"categorie":"generale","specialisation":"","description":"<p>Cette compétence regroupe l’ensemble des activités manuelles permettant de confectionner les objets du quotidien. La plupart des habitants de la Scandia pratiquent plus ou moins ces techniques et se révèlent autonomes lorsqu’il s’agit de fabriquer ou de réparer des ustensiles basiques. Un niveau Confirmé permet d’exercer son artisanat en professionnel et de gagner sa vie avec cette activité. Les meilleurs artisans bénéficient d’une renommée et d’une considération importantes. L’utilisation de cette compétence correspond en général à un test étendu. Spécialisations possibles : cordonnerie, ferronnerie, chaudronnerie, charpenterie, tissage, tannerie, corderie, taille de pierre, poterie, sellerie, etc…</p>\n<p>Il existe cependant deux spécialisations qui méritent que l’on s’y attarde, tant elles occupent une place importante dans la société des Terres du Nord.</p>\n<p><strong>Construction navale : </strong>cette spécialisation permet de mener à bien la construction des différents types de navires sillonnant les flots de la Scandia. Le personnage maîtrise aussi bien les secrets de l’architecture navale que les techniques de la charpenterie de marine, mais il sait tout autant diriger les artisans qui vont réaliser le bateau selon ses instructions. Les meilleurs dans ce domaine sont très recherchés par tous les jarls et souverains des Royaumes Nordiques.</p>\n<p><strong>Forge : </strong>l’art de la forge nécessite des connaissances spécifiques dont certaines confinent au secret transmis uniquement d’un maître à son disciple. Un personnage Novice sait fabriquer des objets usuels, simples, utiles au quotidien (clous, têtes d’outils, anneaux…) Une fois atteint le niveau Confirmé, il peut commencer à forger des pièces plus complexes (fer pour les chevaux, serrures, ferrures d’ornements, etc…) ainsi que des armes et des armures. Si certains exercent leur profession de manière itinérante, un forgeron doit tout de même disposer d’un atelier et d’outils appropriés afin de pouvoir mettre en oeuvre sa compétence. Un forgeron pratique l’un des métiers les plus respectés parmi les artisans.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"947IgofSqazA1CoD"}
|
||||
{"name":"Survie","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Le personnage se sent à l’aise dans les milieux naturels et sait comment y vivre en harmonie avec la nature. Cette compétence permet de trouver de quoi se nourrir et s’abreuver, un endroit pour s’abriter, de faire du feu et de se protéger des conditions climatiques extrêmes comme le froid d’une nuit d’hiver. La Survie recouvre également la chasse et le pistage, mais aussi le sens de l’orientation et les premiers soins.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"9AHUm9FLajXTkEZJ"}
|
||||
{"name":"Traditions","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Grâce à cette compétence, le personnage se souvient des règles, des coutumes et des lois qui ont cours dans la région, voire la cité, où il se trouve. Si le système juridique reste assez semblable dans toute la Scandia, il existe souvent quelques variations locales dans l’application des peines encourues pour un même crime. De même, les us et coutumes de certains endroits changent subtilement par rapport aux habitudes des héros et peuvent provoquer des situations des plus embarrassantes. Un personnage Expert dans cette compétence peut endosser le rôle de crieur des lois lors d’un thing.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"CIfheBgF5plSgqYT"}
|
||||
@@ -9,10 +9,10 @@
|
||||
{"name":"Esquive","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Le personnage anticipe les attaques portées contre lui et se met hors de portée des coups ou des projectiles qui le visent. Bien qu’elle s’avère surtout utile en combat, cette compétence sert également à éviter une collision qui menace le héros, comme un attelage lancé au galop vers lui, ou un éboulement de gros rochers. Que l’esquive soit réussie ou pas, le personnage se retrouve toujours à terre, à quelques pas de sa position initiale (le joueur choisit la direction).</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"MLCAKgi8wRLwlINc"}
|
||||
{"name":"Commerce","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Il s’agit de la connaissance des lois de l’offre et de la demande. Le négociant sait évaluer les choses lors d’un troc, ou d’une transaction s’il utilise de la monnaie. Il connaît également les points d’approvisionnement pour les différentes marchandises produites dans la Scandia, et les endroits où il a le plus de chance d’en tirer le meilleur profit. Les dates et les lieux où se déroulent les foires annuelles n’ont pas de secret pour lui. Enfin, cette compétence gère tout l’aspect intendance de cette activité.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"OlELPb9hGkbQNnff"}
|
||||
{"name":"Chercher","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Cette compétence entre en jeu lorsque le personnage fouille un endroit particulier. Elle permet de révéler les éléments cachés dans le décor ou les indices dissimulés. Contrairement à la compétence Vigilance, Chercher nécessite une démarche active de la part du héros.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"QysZVyRFax7P0mko"}
|
||||
{"_id":"SEeAKWRSKO0HWt6Q","name":"Médecine*","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Cette compétence correspond à la connaissance de l’ensemble des pratiques médicales de la Scandia. Elle permet d’établir un diagnostic, de soigner les maladies les plus courantes, de traiter les blessures, de réduire une fracture, d’accompagner un accouchement, mais aussi de déterminer les causes probables d’une mort inexpliquée. Les premiers soins sont quant à eux couverts par la compétence Survie, mais un personnage plus compétent en Médecine peut dans ce cas substituer cette discipline à un test de Survie.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Médecine","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Cette compétence correspond à la connaissance de l’ensemble des pratiques médicales de la Scandia. Elle permet d’établir un diagnostic, de soigner les maladies les plus courantes, de traiter les blessures, de réduire une fracture, d’accompagner un accouchement, mais aussi de déterminer les causes probables d’une mort inexpliquée. Les premiers soins sont quant à eux couverts par la compétence Survie, mais un personnage plus compétent en Médecine peut dans ce cas substituer cette discipline à un test de Survie.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"SEeAKWRSKO0HWt6Q"}
|
||||
{"name":"Herboristerie","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Il s’agit de la connaissance des plantes, des herbes et des produits naturels permettant de concocter des remèdes, mais aussi des teintures ou encore des poisons de toutes sortes. Un personnage versé dans cette discipline sait également reconnaître les plantes rencontrées en pleine nature, ainsi que déterminer l’endroit où il a le plus de chance de trouver une espèce spécifique.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"SHnTbcIm0JZN7UqU"}
|
||||
{"name":"Natation","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Cette compétence représente l’aptitude à se mouvoir à la surface de l’eau et à y demeurer en cas de chute depuis un navire. Le Meneur de Jeu peut appliquer un malus au test de Natation égal à la valeur de protection de l’armure portée par l’infortuné. Le nageur peut également se déplacer sous l’eau ou plonger depuis les hauteurs vertigineuses des falaises avec de bonnes chances de réussite.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"VcfHyyT169aId8Td"}
|
||||
{"_id":"ZhIYWUKuDV5hyuUA","name":"Langues*","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":true,"categorie":"generale","specialisation":"","description":"<p>Tous les personnages parlent couramment le norrois (<em>dansk tunga</em>), la langue commune aux différents royaumes de la Scandia. Chaque spécialisation dans cette compétence correspond à une langue particulière et étrangère, ou à un patois local issu d’une autre racine linguistique comme le finnois parlé par les tribus sames. Il est toujours possible de comprendre un dialecte tiré du norrois en réussissant, généralement, un test d’Intellect contre un Seuil de Réussite Moyen (14). Exemples de spécialisation : saxon, finnois, balte, germain…</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Langues","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":true,"categorie":"generale","specialisation":"","description":"<p>Tous les personnages parlent couramment le norrois (<em>dansk tunga</em>), la langue commune aux différents royaumes de la Scandia. Chaque spécialisation dans cette compétence correspond à une langue particulière et étrangère, ou à un patois local issu d’une autre racine linguistique comme le finnois parlé par les tribus sames. Il est toujours possible de comprendre un dialecte tiré du norrois en réussissant, généralement, un test d’Intellect contre un Seuil de Réussite Moyen (14). Exemples de spécialisation : saxon, finnois, balte, germain…</p>","niveau":0,"niveauunrequis":true},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"ZhIYWUKuDV5hyuUA"}
|
||||
{"name":"Discrétion","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Le personnage sait se déplacer en silence, tout en profitant du moindre couvert afin de passer inaperçu. Cette compétence permet également de se cacher efficacement ou de camoufler un objet sur soi ou dans le décor environnant.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"cKowAJGvHnY0GSOZ"}
|
||||
{"name":"Art","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":true,"categorie":"generale","specialisation":"","description":"<p>Choisissez le domaine de prédilection du personnage. Il peut s’agir d’un simple don naturel, d’une activité professionnelle (pour un scalde), d’un loisir… Cette compétence permet de créer une oeuvre d’art originale ou d’en reproduire une existante. Spécialisations possibles : orfèvrerie, chant, musique, danse, gravure, poésie déclamée, flatterie, peinture, etc…</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"fcTMIpIMVc1cQASZ"}
|
||||
{"name":"Larcins","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"generale","specialisation":"","description":"<p>Cette compétence recouvre les activités des filous des terres du Nord. Elle permet de crocheter une serrure, mais aussi de couper une bourse ou de subtiliser discrètement des clefs. Dans ce deuxième cas, Larcins s’emploie dans un test en opposition contre la Perception et la Vigilance de la cible.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"ggoWPfYoTx7QG5ae"}
|
||||
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
MANIFEST-000053
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:42:43.240973 7fd463fff6c0 Recovering log #51
|
||||
2026/01/11-22:42:43.255834 7fd463fff6c0 Delete type=0 #51
|
||||
2026/01/11-22:42:43.255892 7fd463fff6c0 Delete type=3 #49
|
||||
2026/01/11-22:44:34.459907 7fd4627fc6c0 Level-0 table #56: started
|
||||
2026/01/11-22:44:34.459930 7fd4627fc6c0 Level-0 table #56: 0 bytes OK
|
||||
2026/01/11-22:44:34.466013 7fd4627fc6c0 Delete type=0 #54
|
||||
2026/01/11-22:44:34.472607 7fd4627fc6c0 Manual compaction at level-0 from '!items!26CQEICWZs8Gw4Xi' @ 72057594037927935 : 1 .. '!items!ylqZMDyXujUlSorr' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:44:34.472642 7fd4627fc6c0 Manual compaction at level-1 from '!items!26CQEICWZs8Gw4Xi' @ 72057594037927935 : 1 .. '!items!ylqZMDyXujUlSorr' @ 0 : 0; will stop at (end)
|
||||
@@ -1,8 +0,0 @@
|
||||
2026/01/11-22:38:18.238976 7fd4637fe6c0 Recovering log #47
|
||||
2026/01/11-22:38:18.249505 7fd4637fe6c0 Delete type=3 #45
|
||||
2026/01/11-22:38:18.249563 7fd4637fe6c0 Delete type=0 #47
|
||||
2026/01/11-22:39:21.489412 7fd4627fc6c0 Level-0 table #52: started
|
||||
2026/01/11-22:39:21.489449 7fd4627fc6c0 Level-0 table #52: 0 bytes OK
|
||||
2026/01/11-22:39:21.495431 7fd4627fc6c0 Delete type=0 #50
|
||||
2026/01/11-22:39:21.515115 7fd4627fc6c0 Manual compaction at level-0 from '!items!26CQEICWZs8Gw4Xi' @ 72057594037927935 : 1 .. '!items!ylqZMDyXujUlSorr' @ 0 : 0; will stop at (end)
|
||||
2026/01/11-22:39:21.515177 7fd4627fc6c0 Manual compaction at level-1 from '!items!26CQEICWZs8Gw4Xi' @ 72057594037927935 : 1 .. '!items!ylqZMDyXujUlSorr' @ 0 : 0; will stop at (end)
|
||||
Binary file not shown.
@@ -1,3 +1,3 @@
|
||||
{"_id":"RAhkadJOfEnVBLpy","name":"Galdr*","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"magique","specialisation":"","description":"<p>Le <em>galdr</em> utilise la puissance divine de la voix pour la magie. Tout pratiquant de la magie peut l’utiliser. Il n’est pas besoin d’avoir une belle voix ou de chanter juste, mais de lancer des incantations.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"_id":"UoWkSxLdXhZQinnc","name":"Runes*","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"magique","specialisation":"","description":"<p>Cette compétence permet de lire et de connaître le sens de chacune des vingt-quatre runes. Mais surtout elles donnent des indications occultes sur la réalité du monde et permettent de lancer des sorts de protection, malédiction et guérison, à ceux qui savent s’en servir.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"_id":"mIBiTKqfqiiepeyz","name":"Sejdr*","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"magique","specialisation":"","description":"<p>Il s’agit là de l’antique art magique enseigné à Odhinn même, par Freyja, la sorcellerie. Les femmes sont plus nombreuses à en pratiquer certains sorts car ils sont liés à des travaux considérés comme purement féminins (filer de la laine, mettre des vêtements de cérémonie pour les visions, chevaucher un autre personnage). Certains hommes pratiquent le Sejdr sans s’en soucier, d’autres sélectionnent les sorts les moins compromettants et les complètent avec les Runes ou le Galdr.</p>","niveau":0,"niveauunrequis":false},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{}}
|
||||
{"name":"Galdr","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"magique","specialisation":"","description":"<p>Le <em>galdr</em> utilise la puissance divine de la voix pour la magie. Tout pratiquant de la magie peut l’utiliser. Il n’est pas besoin d’avoir une belle voix ou de chanter juste, mais de lancer des incantations.</p>","niveau":0,"niveauunrequis":true},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"RAhkadJOfEnVBLpy"}
|
||||
{"name":"Runes","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"magique","specialisation":"","description":"<p>Cette compétence permet de lire et de connaître le sens de chacune des vingt-quatre runes. Mais surtout elles donnent des indications occultes sur la réalité du monde et permettent de lancer des sorts de protection, malédiction et guérison, à ceux qui savent s’en servir.</p>","niveau":0,"niveauunrequis":true},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"UoWkSxLdXhZQinnc"}
|
||||
{"name":"Sejdr","type":"competence","img":"systems/fvtt-yggdrasill/images/icons/icon_skill.png","data":{"isspecialisation":false,"categorie":"magique","specialisation":"","description":"<p>Il s’agit là de l’antique art magique enseigné à Odhinn même, par Freyja, la sorcellerie. Les femmes sont plus nombreuses à en pratiquer certains sorts car ils sont liés à des travaux considérés comme purement féminins (filer de la laine, mettre des vêtements de cérémonie pour les visions, chevaucher un autre personnage). Certains hommes pratiquent le Sejdr sans s’en soucier, d’autres sélectionnent les sorts les moins compromettants et les complètent avec les Runes ou le Galdr.</p>","niveau":0,"niveauunrequis":true},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"feLeZcbqgHkVzfJP":3},"flags":{},"_id":"mIBiTKqfqiiepeyz"}
|
||||
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user