Compare commits
22 Commits
fvtt-yggdr
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 29213f11ed | |||
| 21f91a52e6 | |||
| a04032e002 | |||
| 896fa512b5 | |||
| e7504d0ecb | |||
| ea6f267f8f | |||
| cfda525f7c | |||
| 1afb1d0769 | |||
| b282427406 | |||
| fc7c51e369 | |||
| 8d3fdbd009 | |||
| bb3a4fc5f7 | |||
| ee7f37878f | |||
| 85e0249822 | |||
| 8f0bf91464 | |||
| 2c79743009 | |||
| ecd164c3e5 | |||
| ecdb85455d | |||
| 8d56fed614 | |||
| 63d1c5847b | |||
| 866a079c69 | |||
| fa0b989c86 |
63
.gitea/workflows/release.yaml
Normal file
63
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
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: '14'
|
||||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.history/
|
||||||
|
node_modules/
|
||||||
|
packs/_source/
|
||||||
|
.github/
|
||||||
28
LICENSE.md
Normal file
28
LICENSE.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# 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.
|
||||||
35
gulpfile.js
Normal file
35
gulpfile.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
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
Normal file
27
lang/fr.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
534
less/yggdrasill-chat-viking.less
Normal file
534
less/yggdrasill-chat-viking.less
Normal file
@@ -0,0 +1,534 @@
|
|||||||
|
/* ========================================
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
less/yggdrasill-chat.less
Normal file
2
less/yggdrasill-chat.less
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/* Chat Message Styles - Viking Theme */
|
||||||
|
@import url("yggdrasill-chat-viking.less");
|
||||||
2700
less/yggdrasill-main.less
Normal file
2700
less/yggdrasill-main.less
Normal file
File diff suppressed because it is too large
Load Diff
4
less/yggdrasill.less
Normal file
4
less/yggdrasill.less
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// Main LESS file for Yggdrasill system
|
||||||
|
// Importing all component styles
|
||||||
|
|
||||||
|
@import "yggdrasill-main";
|
||||||
27
modules/applications/sheets/_module.mjs
Normal file
27
modules/applications/sheets/_module.mjs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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';
|
||||||
449
modules/applications/sheets/base-actor-sheet.mjs
Normal file
449
modules/applications/sheets/base-actor-sheet.mjs
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
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 })
|
||||||
|
}
|
||||||
|
}
|
||||||
178
modules/applications/sheets/base-item-sheet.mjs
Normal file
178
modules/applications/sheets/base-item-sheet.mjs
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
44
modules/applications/sheets/create-sheets.sh
Executable file
44
modules/applications/sheets/create-sheets.sh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/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
|
||||||
16
modules/applications/sheets/yggdrasill-armecc-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-armecc-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-armedist-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-armedist-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-armure-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-armure-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-blessure-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-blessure-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-bouclier-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-bouclier-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
21
modules/applications/sheets/yggdrasill-competence-sheet.mjs
Normal file
21
modules/applications/sheets/yggdrasill-competence-sheet.mjs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
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",
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-don-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-don-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-equipement-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-equipement-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-faiblesse-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-faiblesse-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
40
modules/applications/sheets/yggdrasill-figurant-sheet.mjs
Normal file
40
modules/applications/sheets/yggdrasill-figurant-sheet.mjs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-maladie-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-maladie-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-monnaie-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-monnaie-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
99
modules/applications/sheets/yggdrasill-personnage-sheet.mjs
Normal file
99
modules/applications/sheets/yggdrasill-personnage-sheet.mjs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
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 <= 10; 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
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-poison-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-poison-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-prouesse-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-prouesse-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-rune-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-rune-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-sortgaldr-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-sortgaldr-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/applications/sheets/yggdrasill-sortsejdr-sheet.mjs
Normal file
16
modules/applications/sheets/yggdrasill-sortsejdr-sheet.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
347
modules/applications/yggdrasill-roll-dialog.mjs
Normal file
347
modules/applications/yggdrasill-roll-dialog.mjs
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
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 armes : mettre à jour l'effet affiché quand le type d'attaque change
|
||||||
|
if (rollData.mode === "armecc" || rollData.mode === "armetir" || rollData.mode === "armedist") {
|
||||||
|
$("#typeAttack").on("change", () => {
|
||||||
|
rollData.attackDef = rollData.attackDef || {}
|
||||||
|
rollData.attackDef.typeAttack = $("#typeAttack").val()
|
||||||
|
this._updateAttackData(rollData, actor)
|
||||||
|
$("#attackDescr").text(rollData.attackData.description || "")
|
||||||
|
$("#caracName").text(`${rollData.attackData.categName || ""} / ${rollData.attackData.caracName || ""}`)
|
||||||
|
$("#malus").text(rollData.attackData.malus ?? 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 attackType = rollData.attackDef.typeAttack
|
||||||
|
|
||||||
|
let attackData
|
||||||
|
if (rollData.mode === "armecc") {
|
||||||
|
attackData = actor.getAttaqueData(attackType)
|
||||||
|
} else {
|
||||||
|
attackData = actor.getTirData(attackType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attackData) {
|
||||||
|
rollData.attackDef = { ...rollData.attackDef, ...attackData }
|
||||||
|
rollData.attackData = { ...rollData.attackDef }
|
||||||
|
// Mettre à jour la caractéristique utilisée pour le jet (nbDice)
|
||||||
|
rollData.selectedCarac = attackData.carac
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
17
modules/models/armecc.mjs
Normal file
17
modules/models/armecc.mjs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
18
modules/models/armedist.mjs
Normal file
18
modules/models/armedist.mjs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/models/armure.mjs
Normal file
16
modules/models/armure.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* 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.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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
11
modules/models/blessure.mjs
Normal file
11
modules/models/blessure.mjs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
18
modules/models/bouclier.mjs
Normal file
18
modules/models/bouclier.mjs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/models/competence.mjs
Normal file
16
modules/models/competence.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* 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 })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
11
modules/models/don.mjs
Normal file
11
modules/models/don.mjs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
12
modules/models/effetmagique.mjs
Normal file
12
modules/models/effetmagique.mjs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
15
modules/models/equipement.mjs
Normal file
15
modules/models/equipement.mjs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
11
modules/models/faiblesse.mjs
Normal file
11
modules/models/faiblesse.mjs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
87
modules/models/figurant.mjs
Normal file
87
modules/models/figurant.mjs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* 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" })
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
27
modules/models/index.mjs
Normal file
27
modules/models/index.mjs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* 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';
|
||||||
13
modules/models/maladie.mjs
Normal file
13
modules/models/maladie.mjs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
13
modules/models/monnaie.mjs
Normal file
13
modules/models/monnaie.mjs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
158
modules/models/personnage.mjs
Normal file
158
modules/models/personnage.mjs
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/**
|
||||||
|
* 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" })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
13
modules/models/poison.mjs
Normal file
13
modules/models/poison.mjs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
16
modules/models/prouesse.mjs
Normal file
16
modules/models/prouesse.mjs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
12
modules/models/rune.mjs
Normal file
12
modules/models/rune.mjs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
13
modules/models/sortgaldr.mjs
Normal file
13
modules/models/sortgaldr.mjs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 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: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
17
modules/models/sortsejdr.mjs
Normal file
17
modules/models/sortsejdr.mjs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* 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";
|
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class YggdrasillActorSheet extends ActorSheet {
|
export class YggdrasillActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
|
|
||||||
return mergeObject(super.defaultOptions, {
|
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||||
classes: ["yggdrasill", "sheet", "actor"],
|
classes: ["yggdrasill", "sheet", "actor"],
|
||||||
template: "systems/fvtt-yggdrasill/templates/actor-sheet.html",
|
template: "systems/fvtt-yggdrasill/templates/actor-personnage-sheet.hbs",
|
||||||
width: 640,
|
width: 680,
|
||||||
height: 720,
|
height: 740,
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
|
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
|
||||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||||
editScore: false
|
editScore: false
|
||||||
@@ -23,9 +23,9 @@ export class YggdrasillActorSheet extends ActorSheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
getData() {
|
async getData() {
|
||||||
const objectData = duplicate(this.object)
|
const objectData = foundry.utils.duplicate(this.object)
|
||||||
|
|
||||||
let formData = {
|
let formData = {
|
||||||
title: this.title,
|
title: this.title,
|
||||||
id: objectData.id,
|
id: objectData.id,
|
||||||
@@ -60,14 +60,19 @@ export class YggdrasillActorSheet extends ActorSheet {
|
|||||||
sortsSejdr:this.actor.getSortsSejdr(),
|
sortsSejdr:this.actor.getSortsSejdr(),
|
||||||
sortsGaldr:this.actor.getSortsGaldr(),
|
sortsGaldr:this.actor.getSortsGaldr(),
|
||||||
runes: this.actor.getRunes(),
|
runes: this.actor.getRunes(),
|
||||||
optionsCarac: YggdrasillUtility.createDirectOptionList(0, 20),
|
optionsCarac: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||||
optionsDMDP: YggdrasillUtility.createDirectSortedOptionList(-10, +10),
|
optionsDMDP: YggdrasillUtility.createDirectSortedOptionList(-10, +10),
|
||||||
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
||||||
optionsFuror: YggdrasillUtility.createDirectOptionList(0, 15),
|
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}),
|
||||||
options: this.options,
|
options: this.options,
|
||||||
owner: this.document.isOwner,
|
owner: this.document.isOwner,
|
||||||
editScore: this.options.editScore,
|
editScore: this.options.editScore,
|
||||||
isGM: game.user.isGM
|
isGM: game.user.isGM,
|
||||||
|
config: game.system.config
|
||||||
}
|
}
|
||||||
// Dynamic update some fields
|
// Dynamic update some fields
|
||||||
this.updateDM(formData.data);
|
this.updateDM(formData.data);
|
||||||
@@ -108,11 +113,11 @@ updateDP( data ) {
|
|||||||
const li = $(ev.currentTarget).parents(".item");
|
const li = $(ev.currentTarget).parents(".item");
|
||||||
YggdrasillUtility.confirmDelete(this, li);
|
YggdrasillUtility.confirmDelete(this, li);
|
||||||
});
|
});
|
||||||
|
|
||||||
html.find('#isEpuise').click(event => {
|
html.find('#isEpuise').click(event => {
|
||||||
this.actor.toggleEpuise( );
|
this.actor.toggleEpuise( );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
html.find('.munition-moins').click(event => {
|
html.find('.munition-moins').click(event => {
|
||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
const item = this.actor.items.get(li.data("item-id"));
|
const item = this.actor.items.get(li.data("item-id"));
|
||||||
@@ -154,29 +159,29 @@ updateDP( data ) {
|
|||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
const sortId = li.data("item-id");
|
const sortId = li.data("item-id");
|
||||||
this.actor.rollSort(sortId, "sejdr");
|
this.actor.rollSort(sortId, "sejdr");
|
||||||
});
|
});
|
||||||
html.find('.sort-galdr').click((event) => {
|
html.find('.sort-galdr').click((event) => {
|
||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
const sortId = li.data("item-id");
|
const sortId = li.data("item-id");
|
||||||
this.actor.rollSort(sortId, "galdr");
|
this.actor.rollSort(sortId, "galdr");
|
||||||
});
|
});
|
||||||
html.find('.sort-rune').click((event) => {
|
html.find('.sort-rune').click((event) => {
|
||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
const sortId = li.data("item-id");
|
const sortId = li.data("item-id");
|
||||||
this.actor.rollSort(sortId, "rune");
|
this.actor.rollSort(sortId, "rune");
|
||||||
});
|
});
|
||||||
|
|
||||||
html.find('.arme-label a').click((event) => {
|
html.find('.arme-label a').click((event) => {
|
||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
const armeId = li.data("arme-id");
|
const armeId = li.data("arme-id");
|
||||||
this.actor.rollArme(armeId);
|
this.actor.rollArme(armeId);
|
||||||
});
|
});
|
||||||
html.find('.carac-roll').click((event) => {
|
html.find('.carac-roll').click((event) => {
|
||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
let categ = li.data("carac-categ");
|
let categ = li.data("carac-categ");
|
||||||
let carac = li.data("carac-key");
|
let carac = li.data("carac-key");
|
||||||
this.actor.rollCarac(categ, carac);
|
this.actor.rollCarac(categ, carac);
|
||||||
});
|
});
|
||||||
html.find('.weapon-damage').click((event) => {
|
html.find('.weapon-damage').click((event) => {
|
||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
const weapon = this.actor.items.get(li.data("item-id"));
|
const weapon = this.actor.items.get(li.data("item-id"));
|
||||||
@@ -190,12 +195,12 @@ updateDP( data ) {
|
|||||||
html.find('.lock-unlock-sheet').click((event) => {
|
html.find('.lock-unlock-sheet').click((event) => {
|
||||||
this.options.editScore = !this.options.editScore;
|
this.options.editScore = !this.options.editScore;
|
||||||
this.render(true);
|
this.render(true);
|
||||||
});
|
});
|
||||||
html.find('.item-link a').click((event) => {
|
html.find('.item-link a').click((event) => {
|
||||||
const itemId = $(event.currentTarget).data("item-id");
|
const itemId = $(event.currentTarget).data("item-id");
|
||||||
const item = this.actor.items.get(itemId);
|
const item = this.actor.items.get(itemId);
|
||||||
item.sheet.render(true);
|
item.sheet.render(true);
|
||||||
});
|
});
|
||||||
html.find('.item-equip').click(ev => {
|
html.find('.item-equip').click(ev => {
|
||||||
const li = $(ev.currentTarget).parents(".item");
|
const li = $(ev.currentTarget).parents(".item");
|
||||||
this.actor.equiperObject( li.data("item-id") );
|
this.actor.equiperObject( li.data("item-id") );
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ export class YggdrasillCombat extends Combat {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async rollInitiative(ids, formula = undefined, messageOptions = {} ) {
|
async rollInitiative(ids, formula = undefined, messageOptions = {} ) {
|
||||||
ids = typeof ids === "string" ? [ids] : ids;
|
ids = typeof ids === "string" ? [ids] : ids;
|
||||||
const currentId = this.combatant._id;
|
const currentId = this.combatant?.id;
|
||||||
for (let cId = 0; cId < ids.length; cId++) {
|
for (let cId = 0; cId < ids.length; cId++) {
|
||||||
const c = this.combatants.get(ids[cId]);
|
const c = this.combatants.get(ids[cId]);
|
||||||
let initBonus = c.actor ? c.actor.getInitiativeScore() : 0;
|
let initBonus = c.actor ? c.actor.getInitiativeScore() : 0;
|
||||||
@@ -17,17 +17,17 @@ export class YggdrasillCombat extends Combat {
|
|||||||
}
|
}
|
||||||
if (roll.total <= 0) roll.total = 0;
|
if (roll.total <= 0) roll.total = 0;
|
||||||
//console.log("Compute init for", roll.total);
|
//console.log("Compute init for", roll.total);
|
||||||
let id = c._id || c.id;
|
let id = c.id;
|
||||||
await this.updateEmbeddedDocuments("Combatant", [{ _id: id, initiative: roll.total }]);
|
await this.updateEmbeddedDocuments("Combatant", [{ _id: id, initiative: roll.total }]);
|
||||||
|
|
||||||
// Send a chat message
|
// Send a chat message
|
||||||
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
|
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
|
||||||
let messageData = mergeObject(
|
let messageData = foundry.utils.mergeObject(
|
||||||
{
|
{
|
||||||
speaker: {
|
speaker: {
|
||||||
scene: canvas.scene._id,
|
scene: canvas.scene.id,
|
||||||
actor: c.actor ? c.actor._id : null,
|
actor: c.actor ? c.actor.id : null,
|
||||||
token: c.token._id,
|
token: c.token.id,
|
||||||
alias: c.token.name,
|
alias: c.token.name,
|
||||||
sound: CONFIG.sounds.dice,
|
sound: CONFIG.sounds.dice,
|
||||||
},
|
},
|
||||||
|
|||||||
111
modules/yggdrasill-config.js
Normal file
111
modules/yggdrasill-config.js
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
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";
|
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class YggdrasillFigurantSheet extends ActorSheet {
|
export class YggdrasillFigurantSheet extends foundry.appv1.sheets.ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
|
|
||||||
return mergeObject(super.defaultOptions, {
|
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||||
classes: ["yggdrasill", "sheet", "actor"],
|
classes: ["yggdrasill", "sheet", "actor"],
|
||||||
template: "systems/fvtt-yggdrasill/templates/figurant-sheet.html",
|
template: "systems/fvtt-yggdrasill/templates/figurant-sheet.html",
|
||||||
width: 640,
|
width: 640,
|
||||||
@@ -23,9 +23,9 @@ export class YggdrasillFigurantSheet extends ActorSheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
getData() {
|
async getData() {
|
||||||
const objectData = duplicate(this.object)
|
const objectData = foundry.utils.duplicate(this.object)
|
||||||
|
|
||||||
let formData = {
|
let formData = {
|
||||||
title: this.title,
|
title: this.title,
|
||||||
id: objectData.id,
|
id: objectData.id,
|
||||||
@@ -40,12 +40,15 @@ export class YggdrasillFigurantSheet extends ActorSheet {
|
|||||||
effetsmagiques: this.actor.getEffetsMagiques(),
|
effetsmagiques: this.actor.getEffetsMagiques(),
|
||||||
encTotal: this.actor.getEncTotal(),
|
encTotal: this.actor.getEncTotal(),
|
||||||
monnaies: this.actor.getMonnaies(),
|
monnaies: this.actor.getMonnaies(),
|
||||||
optionsAttr: new Array(41).fill('option'),
|
optionsAttr: Array.fromRange(41, 1),
|
||||||
optionsBase: YggdrasillUtility.createDirectOptionList(0, 20),
|
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}),
|
||||||
options: this.options,
|
options: this.options,
|
||||||
owner: this.document.isOwner,
|
owner: this.document.isOwner,
|
||||||
editScore: this.options.editScore,
|
editScore: this.options.editScore,
|
||||||
isGM: game.user.isGM
|
isGM: game.user.isGM,
|
||||||
|
config: game.system.config
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("FIGURANT : ", formData);
|
console.log("FIGURANT : ", formData);
|
||||||
@@ -71,7 +74,7 @@ export class YggdrasillFigurantSheet extends ActorSheet {
|
|||||||
const li = $(ev.currentTarget).parents(".item");
|
const li = $(ev.currentTarget).parents(".item");
|
||||||
YggdrasillUtility.confirmDelete(this, li);
|
YggdrasillUtility.confirmDelete(this, li);
|
||||||
});
|
});
|
||||||
|
|
||||||
html.find('.equipement-moins').click(event => {
|
html.find('.equipement-moins').click(event => {
|
||||||
const li = $(event.currentTarget).parents(".item");
|
const li = $(event.currentTarget).parents(".item");
|
||||||
this.actor.decrementeQuantite( li.data("item-id") );
|
this.actor.decrementeQuantite( li.data("item-id") );
|
||||||
@@ -86,16 +89,16 @@ export class YggdrasillFigurantSheet extends ActorSheet {
|
|||||||
let attrKey = li.data("attr-key");
|
let attrKey = li.data("attr-key");
|
||||||
let attrSubKey = $(event.currentTarget).data("attr-sub-key");
|
let attrSubKey = $(event.currentTarget).data("attr-sub-key");
|
||||||
this.actor.rollAttribute(attrKey, attrSubKey);
|
this.actor.rollAttribute(attrKey, attrSubKey);
|
||||||
});
|
});
|
||||||
html.find('.lock-unlock-sheet').click((event) => {
|
html.find('.lock-unlock-sheet').click((event) => {
|
||||||
this.options.editScore = !this.options.editScore;
|
this.options.editScore = !this.options.editScore;
|
||||||
this.render(true);
|
this.render(true);
|
||||||
});
|
});
|
||||||
html.find('.item-link a').click((event) => {
|
html.find('.item-link a').click((event) => {
|
||||||
const itemId = $(event.currentTarget).data("item-id");
|
const itemId = $(event.currentTarget).data("item-id");
|
||||||
const item = this.actor.items.get(itemId);
|
const item = this.actor.items.get(itemId);
|
||||||
item.sheet.render(true);
|
item.sheet.render(true);
|
||||||
});
|
});
|
||||||
html.find('.item-equip').click(ev => {
|
html.find('.item-equip').click(ev => {
|
||||||
const li = $(ev.currentTarget).parents(".item");
|
const li = $(ev.currentTarget).parents(".item");
|
||||||
this.actor.equiperObject( li.data("item-id") );
|
this.actor.equiperObject( li.data("item-id") );
|
||||||
|
|||||||
@@ -1,101 +1,115 @@
|
|||||||
import { YggdrasillUtility } from "./yggdrasill-utility.js";
|
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
|
* Extend the basic ItemSheet with some very simple modifications
|
||||||
* @extends {ItemSheet}
|
* @extends {ItemSheetV2}
|
||||||
*/
|
*/
|
||||||
export class YggdrasillItemSheet extends ItemSheet {
|
export class YggdrasillItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||||
|
constructor(options = {}) {
|
||||||
|
super(options);
|
||||||
|
this.#dragDrop = this.#createDragDropHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
#dragDrop;
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static DEFAULT_OPTIONS = {
|
||||||
return mergeObject(super.defaultOptions, {
|
classes: ["fvtt-yggdrasill", "item"],
|
||||||
classes: ["fvtt-yggdrasill", "sheet", "item"],
|
position: {
|
||||||
template: "systems/fvtt-yggdrasill/templates/item-sheet.html",
|
width: 550,
|
||||||
width: 550,
|
height: 550,
|
||||||
height: 550
|
},
|
||||||
//tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
|
form: {
|
||||||
});
|
submitOnChange: true,
|
||||||
}
|
},
|
||||||
|
window: {
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
editImage: YggdrasillItemSheet.#onEditImage,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/**
|
||||||
_getHeaderButtons() {
|
* Tab groups state
|
||||||
let buttons = super._getHeaderButtons();
|
* @type {object}
|
||||||
// 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!
|
tabGroups = { primary: "description" };
|
||||||
buttons.unshift(
|
|
||||||
{
|
|
||||||
class: "post",
|
|
||||||
icon: "fas fa-comment",
|
|
||||||
onclick: ev => {}
|
|
||||||
})
|
|
||||||
return buttons
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
/** @override */
|
||||||
setPosition(options={}) {
|
static PARTS = {
|
||||||
const position = super.setPosition(options);
|
sheet: {
|
||||||
const sheetBody = this.element.find(".sheet-body");
|
template: "systems/fvtt-yggdrasill/templates/item-{type}-sheet.hbs"
|
||||||
const bodyHeight = position.height - 192;
|
|
||||||
sheetBody.css("height", bodyHeight);
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async getData() {
|
|
||||||
const objectData = duplicate(this.object);
|
|
||||||
|
|
||||||
let formData = {
|
|
||||||
title: this.title,
|
|
||||||
id: objectData.id,
|
|
||||||
type: objectData.type,
|
|
||||||
img: objectData.img,
|
|
||||||
name: objectData.name,
|
|
||||||
editable: this.isEditable,
|
|
||||||
cssClass: this.isEditable ? "editable" : "locked",
|
|
||||||
data: foundry.utils.deepClone(this.object.system),
|
|
||||||
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;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
/** @override */
|
||||||
if (!this.options.editable) return;
|
async _prepareContext() {
|
||||||
|
// Ensure config is always available with fallback to direct import
|
||||||
|
const config = game.system?.config || game.system?.yggdrasill?.config || YGGDRASILL_CONFIG || {};
|
||||||
|
|
||||||
// Update Inventory Item
|
// Create options for niveau 0-5
|
||||||
html.find('.item-edit').click(ev => {
|
const optionsNiveaux4 = {};
|
||||||
const li = $(ev.currentTarget).parents(".item");
|
for (let i = 0; i <= 5; i++) {
|
||||||
const item = this.object.options.actor.items.get(li.data("item-id"));
|
optionsNiveaux4[`${i}`] = `${i}`;
|
||||||
item.sheet.render(true);
|
}
|
||||||
});
|
|
||||||
// Update Inventory Item
|
|
||||||
html.find('.item-delete').click(ev => {
|
|
||||||
const li = $(ev.currentTarget).parents(".item");
|
|
||||||
this.object.options.actor.deleteEmbeddedDocuments( "Item", [li.data("item-id") ] ).then( this.render(true));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
editable: this.isEditable,
|
||||||
|
isGM: game.user.isGM,
|
||||||
|
config: config,
|
||||||
|
optionsBase: optionsBase,
|
||||||
|
optionsNiveaux4: optionsNiveaux4,
|
||||||
|
};
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
return context;
|
||||||
/* -------------------------------------------- */
|
|
||||||
get template()
|
|
||||||
{
|
|
||||||
let type = this.item.type;
|
|
||||||
return `systems/fvtt-yggdrasill/templates/item-${type}-sheet.html`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
/** @override */
|
||||||
_updateObject(event, formData) {
|
_onRender(context, options) {
|
||||||
return this.object.update(formData);
|
super._onRender(context, options);
|
||||||
|
this.#dragDrop.forEach((d) => d.bind(this.element));
|
||||||
|
}
|
||||||
|
|
||||||
|
// #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 });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
filePicker.browse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,16 @@
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
// Import Modules
|
// Import Modules
|
||||||
import { YggdrasillActor } from "./yggdrasill-actor.js";
|
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 { YggdrasillUtility } from "./yggdrasill-utility.js";
|
||||||
import { YggdrasillCombat } from "./yggdrasill-combat.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 */
|
/* Foundry VTT Initialization */
|
||||||
@@ -28,12 +33,14 @@ Hooks.once("init", async function () {
|
|||||||
YggdrasillUtility.preloadHandlebarsTemplates();
|
YggdrasillUtility.preloadHandlebarsTemplates();
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
// Set an initiative formula for the system
|
// Set an initiative formula for the system
|
||||||
CONFIG.Combat.initiative = {
|
CONFIG.Combat.initiative = {
|
||||||
formula: "1d20",
|
formula: "1d20",
|
||||||
decimals: 0
|
decimals: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
game.system.config = YGGDRASILL_CONFIG
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
game.socket.on("system.fvtt-yggdrasill", data => {
|
game.socket.on("system.fvtt-yggdrasill", data => {
|
||||||
YggdrasillUtility.onSocketMesssage(data);
|
YggdrasillUtility.onSocketMesssage(data);
|
||||||
@@ -42,59 +49,82 @@ Hooks.once("init", async function () {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
// Define custom Entity classes
|
// Define custom Entity classes
|
||||||
CONFIG.Actor.documentClass = YggdrasillActor;
|
CONFIG.Actor.documentClass = YggdrasillActor;
|
||||||
|
CONFIG.Actor.dataModels = {
|
||||||
|
personnage: models.PersonnageDataModel,
|
||||||
|
figurant: models.FigurantDataModel
|
||||||
|
};
|
||||||
|
|
||||||
CONFIG.Combat.documentClass = YggdrasillCombat;
|
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 = {
|
CONFIG.Yggdrasill = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game.system.yggdrasill = {
|
||||||
|
config: YGGDRASILL_CONFIG,
|
||||||
|
models,
|
||||||
|
sheets
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
// Register sheet application classes
|
// 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 });
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
function welcomeMessage() {
|
async function welcomeMessage() {
|
||||||
//ChatUtility.removeMyChatMessageContaining('<div id="welcome-message-sos">');
|
const templateData = {};
|
||||||
|
const html = await foundry.applications.handlebars.renderTemplate("systems/fvtt-yggdrasill/templates/chat-welcome-message.hbs", templateData);
|
||||||
|
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
whisper: [game.user.id],
|
whisper: [game.user.id],
|
||||||
content: `<div id="welcome-message-yggdrasill"><span class="rdd-roll-part"><strong>Bienvenue à Yggdrasill !</strong>
|
content: html
|
||||||
<p>Yggdrasill est un Jeu de Rôle publié par 7ième Cercle : https://www.7emecercle.com/7C_site/jeux-de-roles/yggdrasill/</p>
|
});
|
||||||
<br>Yggdrasill est une propriété de 7ième Cercle.
|
|
||||||
</div>
|
|
||||||
` });
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
// Register world usage statistics
|
|
||||||
function registerUsageCount( registerKey ) {
|
|
||||||
if ( game.user.isGM ) {
|
|
||||||
game.settings.register(registerKey, "world-key", {
|
|
||||||
name: "Unique world key",
|
|
||||||
scope: "world",
|
|
||||||
config: false,
|
|
||||||
default: "",
|
|
||||||
type: String
|
|
||||||
});
|
|
||||||
|
|
||||||
let worldKey = game.settings.get(registerKey, "world-key")
|
|
||||||
if ( worldKey == undefined || worldKey == "" ) {
|
|
||||||
worldKey = randomID(32)
|
|
||||||
game.settings.set(registerKey, "world-key", worldKey )
|
|
||||||
}
|
|
||||||
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
|
|
||||||
$.ajax(regURL)
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -107,10 +137,11 @@ Hooks.once("ready", function () {
|
|||||||
ui.notifications.info("Attention ! Vous n'est connecté à aucun personnage");
|
ui.notifications.info("Attention ! Vous n'est connecté à aucun personnage");
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
content: "<b>WARNING</b> Le joueur " + game.user.name + " n'est pas connecté à un personnage !",
|
content: "<b>WARNING</b> Le joueur " + game.user.name + " n'est pas connecté à un personnage !",
|
||||||
user: game.user._id
|
user: game.user.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
registerUsageCount("fvtt-yggdrasill")
|
|
||||||
|
ClassCounter.registerUsageCount()
|
||||||
welcomeMessage()
|
welcomeMessage()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -125,3 +156,28 @@ Hooks.on("chatMessage", (html, content, msg) => {
|
|||||||
}
|
}
|
||||||
return true;
|
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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,212 +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};
|
|
||||||
|
|
||||||
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.system.voie == "illusion") {
|
|
||||||
sdVar = Number(zonesciblesGaldrSD[this.rollData.zoneGaldr]);
|
|
||||||
} else {
|
|
||||||
sdVar = Number(ciblesGaldrSD[this.rollData.nbCibles]);
|
|
||||||
}
|
|
||||||
let SR = Number(this.rollData.sort.system.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";
|
|
||||||
this.rollData.echelleDureeVie = "Heures"
|
|
||||||
}
|
|
||||||
if ( this.rollData.supportRune == "tissu") {
|
|
||||||
support = 6;
|
|
||||||
this.rollData.echelleDuree = "Tours";
|
|
||||||
this.rollData.echelleDureeVie = "Jours"
|
|
||||||
}
|
|
||||||
if ( this.rollData.supportRune == "cuir") {
|
|
||||||
support = 9;
|
|
||||||
this.rollData.echelleDuree = "Minutes";
|
|
||||||
this.rollData.echelleDureeVie = "Semaines"
|
|
||||||
}
|
|
||||||
if ( this.rollData.supportRune == "bois") {
|
|
||||||
support = 12;
|
|
||||||
this.rollData.echelleDuree = "Heures";
|
|
||||||
this.rollData.echelleDureeVie = "Mois"
|
|
||||||
}
|
|
||||||
if ( this.rollData.supportRune == "pierremetal") {
|
|
||||||
support = 15;
|
|
||||||
this.rollData.echelleDuree = "Jours";
|
|
||||||
this.rollData.echelleDureeVie = "Années"
|
|
||||||
}
|
|
||||||
let SR = this.rollData.puissanceRune + (Number(this.rollData.sort.system.niveau)*3) + support;
|
|
||||||
$("#srTotal").text(SR);
|
|
||||||
$("#runeDuree").text( this.rollData.dureeRune + " " + this.rollData.echelleDuree);
|
|
||||||
$("#runeDureeVie").text( this.rollData.competence.system.niveau + " " + this.rollData.echelleDureeVie);
|
|
||||||
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,34 +1,38 @@
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
//import { YggdrasillCombat } from "./yggdrasill-combat.js";
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
const dureeGaldrText = { "1d5a": "Actions", "1d10t": "Tours", "1d10m": "Minutes", "1d10h": "Heures", "1d5j": "Jours"};
|
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"};
|
const ciblesGaldrText = { "1": "1", "2_4": "2 à 4", "5_9": "5 à 9", "10_49": "10 à 49", "50plus": "50 et plus"};
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class YggdrasillUtility {
|
export class YggdrasillUtility {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async preloadHandlebarsTemplates() {
|
static async preloadHandlebarsTemplates() {
|
||||||
|
|
||||||
const templatePaths = [
|
const templatePaths = [
|
||||||
'systems/fvtt-yggdrasill/templates/actor-sheet.html',
|
'systems/fvtt-yggdrasill/templates/actor-personnage-sheet.hbs',
|
||||||
'systems/fvtt-yggdrasill/templates/editor-notes-gm.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);
|
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static createDirectSortedOptionList( min, max) {
|
static createDirectSortedOptionList( min, max) {
|
||||||
let options = [];
|
let options = [];
|
||||||
for(let i=min; i<=max; i++) {
|
for(let i=min; i<=max; i++) {
|
||||||
options.push( {value:i, text: `${i}` } );
|
options.push( {value:i, text: `${i}` } );
|
||||||
}
|
}
|
||||||
return options;
|
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) {
|
static createDirectOptionList( min, max) {
|
||||||
let options = {};
|
let options = {};
|
||||||
@@ -46,23 +50,6 @@ export class YggdrasillUtility {
|
|||||||
}
|
}
|
||||||
return options;
|
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 ) {
|
static onSocketMesssage( msg ) {
|
||||||
@@ -86,35 +73,31 @@ export class YggdrasillUtility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async specificYggRoll( nbDice ) {
|
static async specificYggRoll( nbDice, isFurorUsage = false) {
|
||||||
let rawDices = []
|
let rawDices = []
|
||||||
let rolls = []
|
let rolls = []
|
||||||
let maxTab = []
|
let maxTab = []
|
||||||
|
let maxTabMaxIndex = isFurorUsage ? nbDice : 2;
|
||||||
maxTab[0] = {idx: 0, value: 0}
|
|
||||||
maxTab[1] = {idx: 0, value: 0}
|
|
||||||
|
|
||||||
for (let i=0; i<nbDice; i++) {
|
for (let i=0; i<nbDice; i++) {
|
||||||
rolls[i] = new Roll("1d10x10").roll( {async: false}) //+sumDice+"+"+rollData.furorUsage+"d10+"+niveauCompetence+"+"+rollData.finalBM).roll( { async: false} );
|
rolls[i] = await new Roll("1d10x10").roll( ) //+sumDice+"+"+rollData.furorUsage+"d10+"+niveauCompetence+"+"+rollData.finalBM).roll( { async: false} );
|
||||||
if ( i == nbDice-1 ) {
|
if ( i == nbDice-1 ) {
|
||||||
await this.showDiceSoNice(rolls[i], game.settings.get("core", "rollMode") );
|
await this.showDiceSoNice(rolls[i], game.settings.get("core", "rollMode") );
|
||||||
} else {
|
} else {
|
||||||
this.showDiceSoNice(rolls[i], game.settings.get("core", "rollMode") );
|
this.showDiceSoNice(rolls[i], game.settings.get("core", "rollMode") );
|
||||||
}
|
}
|
||||||
rawDices.push({ 'result': rolls[i].total});
|
rawDices.push({ 'result': rolls[i].total});
|
||||||
|
|
||||||
if ( rolls[i].total > maxTab[0].value) {
|
|
||||||
if ( nbDice > 1 && maxTab[0].value > maxTab[1].value) {
|
|
||||||
maxTab[1].value = maxTab[0].value
|
|
||||||
}
|
|
||||||
maxTab[0].value = rolls[i].total
|
|
||||||
} else {
|
|
||||||
if ( nbDice > 1 && rolls[i].total > maxTab[1].value) {
|
|
||||||
maxTab[1].value = rolls[i].total
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return { rawDices: rawDices, maxTab: maxTab, rolls: rolls}
|
|
||||||
|
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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -123,31 +106,31 @@ export class YggdrasillUtility {
|
|||||||
let isCritical = false;
|
let isCritical = false;
|
||||||
let isFailure = false;
|
let isFailure = false;
|
||||||
let isSuccess = false;
|
let isSuccess = false;
|
||||||
let marge = 0;
|
let marge = 0;
|
||||||
let niveau = rollData.subAttr.value;
|
let niveau = rollData.subAttr.value;
|
||||||
|
|
||||||
// Bonus/Malus total
|
// Bonus/Malus total
|
||||||
rollData.finalBM = rollData.bonusMalus;
|
rollData.finalBM = Number(rollData.bonusMalus);
|
||||||
// Gestion cas blessé (malus de -3)
|
// Gestion cas blessé (malus de -3)
|
||||||
if ( rollData.isBlesse) { // Cas blesse : malus de -3
|
if ( rollData.isBlesse) { // Cas blesse : malus de -3
|
||||||
rollData.finalBM -= 3;
|
rollData.finalBM -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = await this.specificYggRoll( 2 )
|
let results = await this.specificYggRoll( 2 )
|
||||||
rollData.rawDices = results.rawDices
|
rollData.rawDices = results.rawDices
|
||||||
rollData.maxTab = results.maxTab
|
rollData.maxTab = results.maxTab
|
||||||
rollData.rolls = results.rolls
|
rollData.rolls = results.rolls
|
||||||
rollData.bonus = niveau + rollData.finalBM
|
rollData.bonus = niveau + Number(rollData.finalBM)
|
||||||
|
|
||||||
|
rollData.finalTotal = Number(rollData.maxTab[0].value) + Number(rollData.maxTab[1].value);
|
||||||
|
rollData.finalTotal += Number(rollData.bonus)
|
||||||
|
|
||||||
rollData.finalTotal = rollData.maxTab[0].value + rollData.maxTab[1].value;
|
|
||||||
rollData.finalTotal += rollData.bonus
|
|
||||||
|
|
||||||
// Compute total SR
|
// Compute total SR
|
||||||
rollData.srFinal = rollData.sr;
|
rollData.srFinal = Number(rollData.sr);
|
||||||
if ( rollData.bonusdefense ) {
|
if ( rollData.bonusdefense ) {
|
||||||
rollData.srFinal += rollData.bonusdefense;
|
rollData.srFinal += Number(rollData.bonusdefense);
|
||||||
}
|
}
|
||||||
if ( rollData.srFinal > 0 ) {
|
if ( rollData.srFinal > 0 ) {
|
||||||
isCritical = rollData.finalTotal >= rollData.srFinal*2;
|
isCritical = rollData.finalTotal >= rollData.srFinal*2;
|
||||||
isSuccess = rollData.finalTotal >= rollData.srFinal;
|
isSuccess = rollData.finalTotal >= rollData.srFinal;
|
||||||
marge = rollData.finalTotal - rollData.srFinal;
|
marge = rollData.finalTotal - rollData.srFinal;
|
||||||
@@ -159,8 +142,8 @@ export class YggdrasillUtility {
|
|||||||
// Dégats
|
// Dégats
|
||||||
if ( isSuccess && rollData.subAttr.degats ) {
|
if ( isSuccess && rollData.subAttr.degats ) {
|
||||||
rollData.degatsExplain = `Marge(${marge}) + Physique(${rollData.valuePhysique}) + 1d10`;
|
rollData.degatsExplain = `Marge(${marge}) + Physique(${rollData.valuePhysique}) + 1d10`;
|
||||||
rollData.rollDegats = new Roll("1d10+"+marge+"+"+rollData.valuePhysique).roll( { async: false} );
|
rollData.rollDegats = await new Roll("1d10+"+marge+"+"+rollData.valuePhysique).roll( );
|
||||||
await this.showDiceSoNice(rollData.rollDegats, game.settings.get("core", "rollMode") );
|
await this.showDiceSoNice(rollData.rollDegats, game.settings.get("core", "rollMode") );
|
||||||
rollData.degats = rollData.rollDegats.total;
|
rollData.degats = rollData.rollDegats.total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,23 +156,22 @@ export class YggdrasillUtility {
|
|||||||
console.log("ROLLLL ATTR!!!!", rollData);
|
console.log("ROLLLL ATTR!!!!", rollData);
|
||||||
|
|
||||||
this.createChatWithRollMode( rollData.alias, {
|
this.createChatWithRollMode( rollData.alias, {
|
||||||
content: await renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result.html`, rollData)
|
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result-new.hbs`, rollData)
|
||||||
});
|
});
|
||||||
//myRoll.toMessage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async rollYggdrasill( rollData ) {
|
static async rollYggdrasill( rollData ) {
|
||||||
let sumDice = ( rollData.isEpuise | rollData.isMeurtri) ? 1 : 2;
|
let sumDice = ( rollData.isEpuise || rollData.isMeurtri) ? 1 : 2;
|
||||||
|
|
||||||
// Init stuff
|
// Init stuff
|
||||||
let isCritical = false;
|
let isCritical = false;
|
||||||
let isFailure = false;
|
let isFailure = false;
|
||||||
let isSuccess = false;
|
let isSuccess = false;
|
||||||
let marge = 0;
|
let marge = 0;
|
||||||
let nbDice = rollData.selectedCarac.value;
|
let nbDice = rollData.selectedCarac.value;
|
||||||
let niveauCompetence = 0;
|
let niveauCompetence = 0;
|
||||||
|
|
||||||
// Select niveau de competence/arme/carac
|
// Select niveau de competence/arme/carac
|
||||||
if ( rollData.mode != "carac" ) {
|
if ( rollData.mode != "carac" ) {
|
||||||
niveauCompetence = rollData.competence.system.niveau;
|
niveauCompetence = rollData.competence.system.niveau;
|
||||||
@@ -198,27 +180,27 @@ export class YggdrasillUtility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bonus/Malus total
|
// Bonus/Malus total
|
||||||
rollData.finalBM = rollData.bonusMalus;
|
rollData.finalBM = Number(rollData.bonusMalus);
|
||||||
if ( rollData.attackDef) {
|
if ( rollData.attackDef) {
|
||||||
rollData.finalBM -= rollData.attackDef.malus;
|
rollData.finalBM -= rollData.attackDef.malus;
|
||||||
}
|
}
|
||||||
if ( rollData.sort && rollData.sort.system.malus ) {
|
if ( rollData?.sort?.system?.malus ) {
|
||||||
rollData.finalBM += rollData.sort.system.malus;
|
rollData.finalBM += rollData.sort.system.malus;
|
||||||
}
|
}
|
||||||
// Gestion cas blessé (malus de -3)
|
// Gestion cas blessé (malus de -3)
|
||||||
if ( rollData.isBlesse) { // Cas blesse : malus de -3
|
if ( rollData.isBlesse) { // Cas blesse : malus de -3
|
||||||
rollData.finalBM -= 3;
|
rollData.finalBM -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sumDice > nbDice) sumDice = nbDice;
|
if (sumDice > nbDice) sumDice = nbDice;
|
||||||
let results = await this.specificYggRoll( nbDice )
|
let results = await this.specificYggRoll( nbDice )
|
||||||
rollData.rawDices = results.rawDices
|
rollData.rawDices = results.rawDices
|
||||||
rollData.maxTab = results.maxTab
|
rollData.maxTab = results.maxTab
|
||||||
rollData.rolls = results.rolls
|
rollData.rolls = results.rolls
|
||||||
console.log("RES", results, nbDice, sumDice)
|
console.log("RES", results, nbDice, sumDice)
|
||||||
|
|
||||||
if ( rollData.furorUsage > 0 ) {
|
if ( rollData.furorUsage > 0 ) {
|
||||||
results = await this.specificYggRoll( rollData.furorUsage )
|
results = await this.specificYggRoll( rollData.furorUsage, true )
|
||||||
rollData.furorRawDices = results.rawDices
|
rollData.furorRawDices = results.rawDices
|
||||||
rollData.furorMaxTab = results.maxTab
|
rollData.furorMaxTab = results.maxTab
|
||||||
rollData.furorRolls = results.rolls
|
rollData.furorRolls = results.rolls
|
||||||
@@ -232,16 +214,21 @@ export class YggdrasillUtility {
|
|||||||
for (let i=0; i<rollData.furorUsage; i++) {
|
for (let i=0; i<rollData.furorUsage; i++) {
|
||||||
rollData.furorResult += rollData.furorMaxTab[i].value
|
rollData.furorResult += rollData.furorMaxTab[i].value
|
||||||
}
|
}
|
||||||
rollData.finalTotal += rollData.furorResult + rollData.bonusTotal;
|
rollData.finalTotal += Number(rollData.furorResult) + Number(rollData.bonusTotal);
|
||||||
rollData.niveauCompetence = niveauCompetence
|
rollData.niveauCompetence = niveauCompetence
|
||||||
|
|
||||||
// Compute total SR
|
// Compute total SR
|
||||||
rollData.srFinal = rollData.sr;
|
// Pour les sorts, utiliser srTotal si calculé, sinon sr + bonusdefense
|
||||||
if ( rollData.bonusdefense ) {
|
if (rollData.srTotal !== undefined) {
|
||||||
rollData.srFinal += rollData.bonusdefense;
|
rollData.srFinal = rollData.srTotal
|
||||||
}
|
} else {
|
||||||
|
rollData.srFinal = rollData.sr
|
||||||
if ( rollData.srFinal > 0 ) {
|
if (rollData.bonusdefense) {
|
||||||
|
rollData.srFinal += rollData.bonusdefense
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( rollData.srFinal > 0 ) {
|
||||||
isCritical = rollData.finalTotal >= rollData.srFinal*2;
|
isCritical = rollData.finalTotal >= rollData.srFinal*2;
|
||||||
isSuccess = rollData.finalTotal >= rollData.srFinal;
|
isSuccess = rollData.finalTotal >= rollData.srFinal;
|
||||||
marge = rollData.finalTotal - rollData.srFinal;
|
marge = rollData.finalTotal - rollData.srFinal;
|
||||||
@@ -255,7 +242,7 @@ export class YggdrasillUtility {
|
|||||||
}
|
}
|
||||||
if (nbDice >= 3 ) {
|
if (nbDice >= 3 ) {
|
||||||
let nbOnes = 0
|
let nbOnes = 0
|
||||||
for (let roll of rollData.rolls) {
|
for (let roll of rollData.rolls) {
|
||||||
if (roll.dice[0].results[0].result == 1 ) nbOnes++;
|
if (roll.dice[0].results[0].result == 1 ) nbOnes++;
|
||||||
}
|
}
|
||||||
isFailure = nbOnes >= 3;
|
isFailure = nbOnes >= 3;
|
||||||
@@ -263,7 +250,7 @@ export class YggdrasillUtility {
|
|||||||
|
|
||||||
// Dégats
|
// Dégats
|
||||||
if ( isSuccess && (rollData.mode == "armecc" || rollData.mode == "armedist") ) {
|
if ( isSuccess && (rollData.mode == "armecc" || rollData.mode == "armedist") ) {
|
||||||
rollData.degatsExplain = `Marge(${marge}) + Degats Arme(${rollData.arme.system.degat}) + Bonus Attaque(${rollData.attackDef.bonusdegats})`;
|
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.degats = marge + rollData.arme.system.degat + rollData.attackDef.bonusdegats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +263,7 @@ export class YggdrasillUtility {
|
|||||||
|
|
||||||
// Specific GALDR
|
// Specific GALDR
|
||||||
if ( rollData.sort?.type == "sortgaldr" && rollData.isSuccess) {
|
if ( rollData.sort?.type == "sortgaldr" && rollData.isSuccess) {
|
||||||
let galdrRoll = new Roll( rollData.dureeGaldr.substring(0, rollData.dureeGaldr.length - 1) ).roll( { async: false} );
|
let galdrRoll = await new Roll( rollData.dureeGaldr.substring(0, rollData.dureeGaldr.length - 1) ).roll( );
|
||||||
await this.showDiceSoNice(galdrRoll, game.settings.get("core", "rollMode") );
|
await this.showDiceSoNice(galdrRoll, game.settings.get("core", "rollMode") );
|
||||||
rollData.dureeGaldrText = galdrRoll.total + " " + dureeGaldrText[rollData.dureeGaldr];
|
rollData.dureeGaldrText = galdrRoll.total + " " + dureeGaldrText[rollData.dureeGaldr];
|
||||||
if ( rollData.sort.system.voie == "illusion") {
|
if ( rollData.sort.system.voie == "illusion") {
|
||||||
@@ -290,14 +277,13 @@ export class YggdrasillUtility {
|
|||||||
console.log("ROLLLL!!!!", rollData);
|
console.log("ROLLLL!!!!", rollData);
|
||||||
|
|
||||||
this.createChatWithRollMode( rollData.alias, {
|
this.createChatWithRollMode( rollData.alias, {
|
||||||
content: await renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result.html`, rollData)
|
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-yggdrasill/templates/chat-generic-result-new.hbs`, rollData)
|
||||||
});
|
});
|
||||||
//myRoll.toMessage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getUsers(filter) {
|
static getUsers(filter) {
|
||||||
return game.users.filter(filter).map(user => user.system._id);
|
return game.users.filter(filter).map(user => user.id);
|
||||||
}
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getWhisperRecipients(rollMode, name) {
|
static getWhisperRecipients(rollMode, name) {
|
||||||
@@ -317,7 +303,7 @@ export class YggdrasillUtility {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static blindMessageToGM(chatOptions) {
|
static blindMessageToGM(chatOptions) {
|
||||||
let chatGM = duplicate(chatOptions);
|
let chatGM = foundry.utils.duplicate(chatOptions);
|
||||||
chatGM.whisper = this.getUsers(user => user.isGM);
|
chatGM.whisper = this.getUsers(user => user.isGM);
|
||||||
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content;
|
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content;
|
||||||
console.log("blindMessageToGM", chatGM);
|
console.log("blindMessageToGM", chatGM);
|
||||||
@@ -350,7 +336,7 @@ export class YggdrasillUtility {
|
|||||||
static createChatWithRollMode(name, chatOptions) {
|
static createChatWithRollMode(name, chatOptions) {
|
||||||
this.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
|
this.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async confirmDelete(actorSheet, li) {
|
static async confirmDelete(actorSheet, li) {
|
||||||
let itemId = li.data("item-id");
|
let itemId = li.data("item-id");
|
||||||
@@ -379,7 +365,7 @@ export class YggdrasillUtility {
|
|||||||
d.render(true);
|
d.render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async showDiceSoNice(roll, rollMode) {
|
static async showDiceSoNice(roll, rollMode) {
|
||||||
if (game.modules.get("dice-so-nice")?.active) {
|
if (game.modules.get("dice-so-nice")?.active) {
|
||||||
|
|||||||
4971
package-lock.json
generated
Normal file
4971
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
16
package.json
Normal file
16
package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
0
packs/armes/000063.log
Normal file
0
packs/armes/000063.log
Normal file
BIN
packs/armes/000065.ldb
Normal file
BIN
packs/armes/000065.ldb
Normal file
Binary file not shown.
1
packs/armes/CURRENT
Normal file
1
packs/armes/CURRENT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000061
|
||||||
0
packs/armes/LOCK
Normal file
0
packs/armes/LOCK
Normal file
11
packs/armes/LOG
Normal file
11
packs/armes/LOG
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
2026/04/01-22:41:42.686682 7fcfbebfe6c0 Delete type=3 #1
|
||||||
|
2026/04/01-22:51:01.547142 7fcfbd3fb6c0 Level-0 table #64: started
|
||||||
|
2026/04/01-22:51:01.547164 7fcfbd3fb6c0 Level-0 table #64: 0 bytes OK
|
||||||
|
2026/04/01-22:51:01.554026 7fcfbd3fb6c0 Delete type=0 #62
|
||||||
|
2026/04/01-22:51:01.577068 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!3VBHojfjdD504ibv' @ 72057594037927935 : 1 .. '!items!x3aMYeKa73GxJ1Ge' @ 0 : 0; will stop at '!items!x3aMYeKa73GxJ1Ge' @ 45 : 1
|
||||||
|
2026/04/01-22:51:01.577076 7fcfbd3fb6c0 Compacting 1@0 + 0@1 files
|
||||||
|
2026/04/01-22:51:01.580113 7fcfbd3fb6c0 Generated table #65@0: 15 keys, 2327 bytes
|
||||||
|
2026/04/01-22:51:01.580125 7fcfbd3fb6c0 Compacted 1@0 + 0@1 files => 2327 bytes
|
||||||
|
2026/04/01-22:51:01.586007 7fcfbd3fb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/04/01-22:51:01.586098 7fcfbd3fb6c0 Delete type=2 #40
|
||||||
|
2026/04/01-22:51:01.606413 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!x3aMYeKa73GxJ1Ge' @ 45 : 1 .. '!items!x3aMYeKa73GxJ1Ge' @ 0 : 0; will stop at (end)
|
||||||
4
packs/armes/LOG.old
Normal file
4
packs/armes/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
2026/04/01-22:41:42.671549 7fcfbebfe6c0 Log #59: 0 ops saved to Table #60 OK
|
||||||
|
2026/04/01-22:41:42.671646 7fcfbebfe6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/armes/000059.log: OK
|
||||||
|
2026/04/01-22:41:42.671700 7fcfbebfe6c0 Table #40: 15 entries OK
|
||||||
|
2026/04/01-22:41:42.674961 7fcfbebfe6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/armes; recovered 1 files; 2327 bytes. Some data may have been lost. ****
|
||||||
BIN
packs/armes/MANIFEST-000061
Normal file
BIN
packs/armes/MANIFEST-000061
Normal file
Binary file not shown.
0
packs/armes/lost/000059.log
Normal file
0
packs/armes/lost/000059.log
Normal file
0
packs/armures/000063.log
Normal file
0
packs/armures/000063.log
Normal file
BIN
packs/armures/000065.ldb
Normal file
BIN
packs/armures/000065.ldb
Normal file
Binary file not shown.
1
packs/armures/CURRENT
Normal file
1
packs/armures/CURRENT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000061
|
||||||
0
packs/armures/LOCK
Normal file
0
packs/armures/LOCK
Normal file
11
packs/armures/LOG
Normal file
11
packs/armures/LOG
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
2026/04/01-22:41:42.704920 7fcfbf3ff6c0 Delete type=3 #1
|
||||||
|
2026/04/01-22:51:01.606510 7fcfbd3fb6c0 Level-0 table #64: started
|
||||||
|
2026/04/01-22:51:01.606535 7fcfbd3fb6c0 Level-0 table #64: 0 bytes OK
|
||||||
|
2026/04/01-22:51:01.613032 7fcfbd3fb6c0 Delete type=0 #62
|
||||||
|
2026/04/01-22:51:01.632412 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!4YGPuZ813BWQaNbq' @ 72057594037927935 : 1 .. '!items!qUXBrstsh5Oo8FEx' @ 0 : 0; will stop at '!items!qUXBrstsh5Oo8FEx' @ 24 : 1
|
||||||
|
2026/04/01-22:51:01.632421 7fcfbd3fb6c0 Compacting 1@0 + 0@1 files
|
||||||
|
2026/04/01-22:51:01.635699 7fcfbd3fb6c0 Generated table #65@0: 8 keys, 3197 bytes
|
||||||
|
2026/04/01-22:51:01.635720 7fcfbd3fb6c0 Compacted 1@0 + 0@1 files => 3197 bytes
|
||||||
|
2026/04/01-22:51:01.641765 7fcfbd3fb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/04/01-22:51:01.641877 7fcfbd3fb6c0 Delete type=2 #40
|
||||||
|
2026/04/01-22:51:01.672309 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!qUXBrstsh5Oo8FEx' @ 24 : 1 .. '!items!qUXBrstsh5Oo8FEx' @ 0 : 0; will stop at (end)
|
||||||
4
packs/armures/LOG.old
Normal file
4
packs/armures/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
2026/04/01-22:41:42.689771 7fcfbf3ff6c0 Log #59: 0 ops saved to Table #60 OK
|
||||||
|
2026/04/01-22:41:42.689873 7fcfbf3ff6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/armures/000059.log: OK
|
||||||
|
2026/04/01-22:41:42.689938 7fcfbf3ff6c0 Table #40: 8 entries OK
|
||||||
|
2026/04/01-22:41:42.693096 7fcfbf3ff6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/armures; recovered 1 files; 3197 bytes. Some data may have been lost. ****
|
||||||
BIN
packs/armures/MANIFEST-000061
Normal file
BIN
packs/armures/MANIFEST-000061
Normal file
Binary file not shown.
0
packs/armures/lost/000059.log
Normal file
0
packs/armures/lost/000059.log
Normal file
0
packs/blessures/000063.log
Normal file
0
packs/blessures/000063.log
Normal file
BIN
packs/blessures/000065.ldb
Normal file
BIN
packs/blessures/000065.ldb
Normal file
Binary file not shown.
1
packs/blessures/CURRENT
Normal file
1
packs/blessures/CURRENT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000061
|
||||||
0
packs/blessures/LOCK
Normal file
0
packs/blessures/LOCK
Normal file
11
packs/blessures/LOG
Normal file
11
packs/blessures/LOG
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
2026/04/01-22:41:42.668433 7fcfbdbfc6c0 Delete type=3 #1
|
||||||
|
2026/04/01-22:51:01.540998 7fcfbd3fb6c0 Level-0 table #64: started
|
||||||
|
2026/04/01-22:51:01.541046 7fcfbd3fb6c0 Level-0 table #64: 0 bytes OK
|
||||||
|
2026/04/01-22:51:01.547060 7fcfbd3fb6c0 Delete type=0 #62
|
||||||
|
2026/04/01-22:51:01.566722 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!4rM9IvDuijsjbAhI' @ 72057594037927935 : 1 .. '!items!swTZ43FJRWkqjR75' @ 0 : 0; will stop at '!items!swTZ43FJRWkqjR75' @ 45 : 1
|
||||||
|
2026/04/01-22:51:01.566735 7fcfbd3fb6c0 Compacting 1@0 + 0@1 files
|
||||||
|
2026/04/01-22:51:01.570029 7fcfbd3fb6c0 Generated table #65@0: 15 keys, 4373 bytes
|
||||||
|
2026/04/01-22:51:01.570048 7fcfbd3fb6c0 Compacted 1@0 + 0@1 files => 4373 bytes
|
||||||
|
2026/04/01-22:51:01.576800 7fcfbd3fb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/04/01-22:51:01.576950 7fcfbd3fb6c0 Delete type=2 #40
|
||||||
|
2026/04/01-22:51:01.606402 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!swTZ43FJRWkqjR75' @ 45 : 1 .. '!items!swTZ43FJRWkqjR75' @ 0 : 0; will stop at (end)
|
||||||
4
packs/blessures/LOG.old
Normal file
4
packs/blessures/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
2026/04/01-22:41:42.652980 7fcfbdbfc6c0 Log #59: 0 ops saved to Table #60 OK
|
||||||
|
2026/04/01-22:41:42.653141 7fcfbdbfc6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/blessures/000059.log: OK
|
||||||
|
2026/04/01-22:41:42.653213 7fcfbdbfc6c0 Table #40: 15 entries OK
|
||||||
|
2026/04/01-22:41:42.656556 7fcfbdbfc6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/blessures; recovered 1 files; 4373 bytes. Some data may have been lost. ****
|
||||||
BIN
packs/blessures/MANIFEST-000061
Normal file
BIN
packs/blessures/MANIFEST-000061
Normal file
Binary file not shown.
0
packs/blessures/lost/000059.log
Normal file
0
packs/blessures/lost/000059.log
Normal file
0
packs/competences-generales/000063.log
Normal file
0
packs/competences-generales/000063.log
Normal file
BIN
packs/competences-generales/000065.ldb
Normal file
BIN
packs/competences-generales/000065.ldb
Normal file
Binary file not shown.
1
packs/competences-generales/CURRENT
Normal file
1
packs/competences-generales/CURRENT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000061
|
||||||
0
packs/competences-generales/LOCK
Normal file
0
packs/competences-generales/LOCK
Normal file
11
packs/competences-generales/LOG
Normal file
11
packs/competences-generales/LOG
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
2026/04/01-22:41:42.545198 7fcfbdbfc6c0 Delete type=3 #1
|
||||||
|
2026/04/01-22:51:01.489437 7fcfbd3fb6c0 Level-0 table #64: started
|
||||||
|
2026/04/01-22:51:01.489459 7fcfbd3fb6c0 Level-0 table #64: 0 bytes OK
|
||||||
|
2026/04/01-22:51:01.495384 7fcfbd3fb6c0 Delete type=0 #62
|
||||||
|
2026/04/01-22:51:01.521152 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!26CQEICWZs8Gw4Xi' @ 72057594037927935 : 1 .. '!items!ylqZMDyXujUlSorr' @ 0 : 0; will stop at '!items!ylqZMDyXujUlSorr' @ 90 : 1
|
||||||
|
2026/04/01-22:51:01.521160 7fcfbd3fb6c0 Compacting 1@0 + 0@1 files
|
||||||
|
2026/04/01-22:51:01.524489 7fcfbd3fb6c0 Generated table #65@0: 30 keys, 18501 bytes
|
||||||
|
2026/04/01-22:51:01.524512 7fcfbd3fb6c0 Compacted 1@0 + 0@1 files => 18501 bytes
|
||||||
|
2026/04/01-22:51:01.531301 7fcfbd3fb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/04/01-22:51:01.531388 7fcfbd3fb6c0 Delete type=2 #40
|
||||||
|
2026/04/01-22:51:01.540868 7fcfbd3fb6c0 Manual compaction at level-0 from '!items!ylqZMDyXujUlSorr' @ 90 : 1 .. '!items!ylqZMDyXujUlSorr' @ 0 : 0; will stop at (end)
|
||||||
4
packs/competences-generales/LOG.old
Normal file
4
packs/competences-generales/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
2026/04/01-22:41:42.426252 7fcfbdbfc6c0 Log #59: 0 ops saved to Table #60 OK
|
||||||
|
2026/04/01-22:41:42.426381 7fcfbdbfc6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/competences-generales/000059.log: OK
|
||||||
|
2026/04/01-22:41:42.426460 7fcfbdbfc6c0 Table #40: 30 entries OK
|
||||||
|
2026/04/01-22:41:42.430037 7fcfbdbfc6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-yggdrasill/packs/competences-generales; recovered 1 files; 18501 bytes. Some data may have been lost. ****
|
||||||
BIN
packs/competences-generales/MANIFEST-000061
Normal file
BIN
packs/competences-generales/MANIFEST-000061
Normal file
Binary file not shown.
0
packs/competences-generales/lost/000059.log
Normal file
0
packs/competences-generales/lost/000059.log
Normal file
0
packs/competences-magiques/000063.log
Normal file
0
packs/competences-magiques/000063.log
Normal file
BIN
packs/competences-magiques/000065.ldb
Normal file
BIN
packs/competences-magiques/000065.ldb
Normal file
Binary file not shown.
1
packs/competences-magiques/CURRENT
Normal file
1
packs/competences-magiques/CURRENT
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000061
|
||||||
0
packs/competences-magiques/LOCK
Normal file
0
packs/competences-magiques/LOCK
Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user