Compare commits
25 Commits
fvtt-malef
...
14.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 956ed9e916 | |||
| 5cc060b102 | |||
| a816380679 | |||
| 55d7e401c1 | |||
| 5e2916202e | |||
| c45837ea31 | |||
| 8735b7e4a4 | |||
| 34db8695d7 | |||
| a109fd6acb | |||
| d647fcc35e | |||
| 342f9c2342 | |||
| cd14db85cc | |||
| ec06f0fdcb | |||
| 234bd44742 | |||
| e0df1f1ff5 | |||
| 2c92dd6ef9 | |||
| 8af5851246 | |||
| 14b536cc52 | |||
| 9944ebe64d | |||
| 165c836f39 | |||
| cb8e70c6c1 | |||
| b2a9d8cb75 | |||
| 6d75c8532c | |||
| dce8ad025b | |||
| 6e4cd71b99 |
62
.gitea/workflows/release.yaml
Normal file
62
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will be cloned to the runner."
|
||||
|
||||
- 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-malefices/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-malefices.zip
|
||||
|
||||
# Create a zip file with all files required by the system to add to the release
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./fvtt-malefices.zip system.json README.md fonts/ images/ lang/ modules/ packs/ styles/ templates/
|
||||
|
||||
- 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-malefices.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-malefices'
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: 'https://www.uberwald.me/gitea/public/fvtt-malefices/releases/download/latest/system.json'
|
||||
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-malefices.zip'
|
||||
compatibility-minimum: '13'
|
||||
compatibility-verified: '14'
|
||||
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# IDE
|
||||
.idea/
|
||||
.vs/
|
||||
styles/*.css
|
||||
|
||||
# Node Modules
|
||||
node_modules/
|
||||
.github/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Système Foundry pour Maléfices (French RPG, Arkhane Asylum Publishing)
|
||||
|
||||
[Vue du système](https://www.lahiette.com/leratierbretonnien/wp-content/uploads/2023/02/malefices_snapshot.webp)
|
||||
|
||||
## EN
|
||||
|
||||
Unofficial system for Maléfices v4 (French version from Arkhane Asylum Publishing).
|
||||
|
||||
27
gulpfile.js
Normal file
27
gulpfile.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const gulp = require('gulp');
|
||||
const less = require('gulp-less');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
const rename = require('gulp-rename');
|
||||
|
||||
// Compile LESS to CSS
|
||||
function styles() {
|
||||
return gulp.src('less/malefices.less')
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(less())
|
||||
.pipe(rename('simple.css'))
|
||||
.pipe(sourcemaps.write('.', { mapFile: () => 'simple.css.map' }))
|
||||
.pipe(gulp.dest('styles/'));
|
||||
}
|
||||
|
||||
// Watch files
|
||||
function watchFiles() {
|
||||
gulp.watch('less/**/*.less', styles);
|
||||
}
|
||||
|
||||
const build = gulp.series(styles);
|
||||
const watch = gulp.series(build, watchFiles);
|
||||
|
||||
exports.styles = styles;
|
||||
exports.build = build;
|
||||
exports.watch = watch;
|
||||
exports.default = build;
|
||||
6
images/icons/.directory
Normal file
6
images/icons/.directory
Normal file
@@ -0,0 +1,6 @@
|
||||
[Dolphin]
|
||||
SortRole=modificationtime
|
||||
Timestamp=2023,2,26,15,32,34.892
|
||||
Version=4
|
||||
ViewMode=1
|
||||
VisibleRoles=Details_text,Details_size,Details_modificationtime,Details_creationtime,CustomizedDetails
|
||||
BIN
images/icons/resume.webp
Normal file
BIN
images/icons/resume.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
images/icons/tirage.webp
Normal file
BIN
images/icons/tirage.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
images/icons/tirer.webp
Normal file
BIN
images/icons/tirer.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
BIN
images/ui/malefices-background-01.jpg
Normal file
BIN
images/ui/malefices-background-01.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 354 KiB |
22
lang/fr.json
22
lang/fr.json
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"ACTOR": {
|
||||
"TypePersonnage": "Personnage"
|
||||
},
|
||||
"ITEM": {
|
||||
"TypeArme": "Arme",
|
||||
"TypeEquipement": "Equipement",
|
||||
"TypeTarot": "Tarot",
|
||||
"TypeElementbio": "Element Biographique",
|
||||
"TypeArchetype": "Archetype",
|
||||
"TypeSortilege": "Sortilège"
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"personnage" : "Personnage"
|
||||
},
|
||||
"Item": {
|
||||
"arme" : "Arme",
|
||||
"equipement" : "Equipement",
|
||||
"tarot" : "Tarot",
|
||||
"elementbio" : "Elément Biographique",
|
||||
"archetype" : "Archetype",
|
||||
"sortilege" : "Sortilège"
|
||||
}
|
||||
}
|
||||
}
|
||||
235
less/actor-sheet.less
Normal file
235
less/actor-sheet.less
Normal file
@@ -0,0 +1,235 @@
|
||||
/* ===================================================================
|
||||
AppV2 Actor Sheets
|
||||
=================================================================== */
|
||||
|
||||
/* NOTE: DocumentSheetV2 uses tag:"form" — the APPLICATION ROOT is the <form>.
|
||||
The DOM is: form.application > section.window-content > section.editable > ...
|
||||
There is NO <form> child inside window-content. */
|
||||
|
||||
.fvtt-malefices.actor {
|
||||
|
||||
/* window-content: background and remove Foundry's default padding.
|
||||
Foundry AppV2 already sets: display:flex flex-flow:column overflow:hidden */
|
||||
.window-content {
|
||||
padding: 0;
|
||||
background: @bg-sheet;
|
||||
color: @color-text;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* All sections inside actor fill their flex container and form a flex column.
|
||||
This covers: section.editable (template root) and section.sheet-body. */
|
||||
section {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* sheet-body: scroll container instead of clipping */
|
||||
section.sheet-body {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
|
||||
/* Override legacy fixed 210px height — shrink to fit content */
|
||||
.sheet-header {
|
||||
flex: 0 0 auto;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Override legacy "height: 100%" on .tab divs so their content
|
||||
can overflow sheet-body and trigger the scrollbar;
|
||||
hide all tabs, show only the active one */
|
||||
.tab[data-tab] {
|
||||
height: auto;
|
||||
display: none;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tab navigation */
|
||||
nav.tabs {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
font-family: @font-rivanna;
|
||||
font-size: @tab-font-size;
|
||||
font-weight: bold;
|
||||
height: @tab-height;
|
||||
margin: 0;
|
||||
padding: 0 0 0 0.25rem;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
line-height: @tab-height;
|
||||
border-top: 0 none;
|
||||
border-bottom: 0 none;
|
||||
background-color: @color-tab-bg;
|
||||
color: @color-tab-text;
|
||||
gap: 0.25rem;
|
||||
|
||||
a.item {
|
||||
position: relative;
|
||||
padding: 0 0.5rem;
|
||||
color: @color-tab-text;
|
||||
font-family: @font-rivanna;
|
||||
font-size: @tab-font-size;
|
||||
text-decoration: none;
|
||||
line-height: @tab-height;
|
||||
|
||||
&:hover {
|
||||
text-shadow: 1px 0px 0px @color-accent;
|
||||
}
|
||||
|
||||
&.active {
|
||||
text-shadow: 1px 0px 0px @color-accent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Force dark text on section titles and labels inside actor sheet body
|
||||
(overrides Foundry core heading/label colors from the default dark theme) */
|
||||
section.sheet-body {
|
||||
h1, h2, h3, h4, label, span, a {
|
||||
color: @color-text;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Belle Époque aesthetic improvements ─────────────────────────── */
|
||||
@be-bordeaux: #5a0a14;
|
||||
@be-gold: #8b6914;
|
||||
@be-gold-border: rgba(139, 105, 20, 0.45);
|
||||
@be-sepia: #3d2b1f;
|
||||
|
||||
// Sheet header — portrait with gold border, charname input styled
|
||||
.sheet-header {
|
||||
.profile-img {
|
||||
border: 2px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
box-shadow: 1px 1px 4px rgba(0,0,0,0.25);
|
||||
}
|
||||
|
||||
h1.charname input {
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 1.3rem;
|
||||
color: @be-bordeaux;
|
||||
border-bottom: 1px solid @be-gold-border;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
border-bottom: 1px solid @be-gold-border;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-bottom-color: @be-bordeaux;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Section title rows (Attributs, Armes, Équipements, etc.)
|
||||
.items-title-bg {
|
||||
background: linear-gradient(to right, rgba(90,10,20,0.15), rgba(139,105,20,0.10)) !important;
|
||||
border-bottom: 1px solid @be-gold-border;
|
||||
border-top: 1px solid @be-gold-border;
|
||||
margin-top: 6px;
|
||||
|
||||
.items-title-text {
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 0.9rem;
|
||||
color: @be-bordeaux !important;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
}
|
||||
|
||||
// Roll links — attributs and weapons
|
||||
a.roll-attribut, a.roll-arme {
|
||||
color: @be-sepia !important;
|
||||
font-weight: 600;
|
||||
transition: color 0.12s;
|
||||
|
||||
i { color: fade(@be-gold, 80%); margin-left: 0.2rem; font-size: 0.75em; }
|
||||
|
||||
&:hover {
|
||||
color: @be-bordeaux !important;
|
||||
text-decoration: none;
|
||||
i { color: @be-bordeaux; }
|
||||
}
|
||||
}
|
||||
|
||||
// Attribute value inputs
|
||||
input.item-field-label-short, input.item-field-label-medium {
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
color: @be-bordeaux;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
background: rgba(255,252,240,0.6);
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: @be-bordeaux;
|
||||
box-shadow: 0 0 3px rgba(90,10,20,0.2);
|
||||
}
|
||||
}
|
||||
|
||||
// Item rows — zebra effect with Belle Époque tones
|
||||
.alternate-list {
|
||||
.list-item:nth-child(even) {
|
||||
background: rgba(139,105,20,0.07);
|
||||
}
|
||||
.list-item:nth-child(odd) {
|
||||
background: rgba(61,43,31,0.04);
|
||||
}
|
||||
.list-item:hover {
|
||||
background: rgba(139,105,20,0.15) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Item icon — small gold border
|
||||
.sheet-competence-img {
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
// Item control icons (edit/delete)
|
||||
.item-controls a.item-control {
|
||||
color: fade(@be-sepia, 60%);
|
||||
&:hover { color: @be-bordeaux; }
|
||||
}
|
||||
|
||||
// Biography tab inputs
|
||||
.tab.biodata {
|
||||
input[type="text"] {
|
||||
border-bottom: 1px solid @be-gold-border;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
color: @be-sepia;
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-bottom-color: @be-bordeaux;
|
||||
}
|
||||
}
|
||||
|
||||
label.item-name-label-medium {
|
||||
font-weight: 600;
|
||||
color: @be-sepia !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
168
less/base.less
Normal file
168
less/base.less
Normal file
@@ -0,0 +1,168 @@
|
||||
/* ==================== (A) Fonts ==================== */
|
||||
@font-face {
|
||||
font-family: "Rivanna";
|
||||
src: url('../fonts/rivanna.ttf') format("truetype");
|
||||
}
|
||||
|
||||
|
||||
/* Global styles scoped to Maléfices windows only */
|
||||
.fvtt-malefices .window-app {
|
||||
text-align: justify;
|
||||
font-size: 16px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* Fonts — scoped to system sheets */
|
||||
.fvtt-malefices .sheet header.sheet-header h1 input,
|
||||
#actors .directory-list,
|
||||
#navigation #scene-list .scene.nav-item {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
.fvtt-malefices .sheet nav.sheet-tabs {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.fvtt-malefices .item-form,
|
||||
.fvtt-malefices .sheet header.sheet-header .flex-group-center.flex-compteurs,
|
||||
.fvtt-malefices .sheet header.sheet-header .flex-group-center.flex-fatigue,
|
||||
.fvtt-malefices .item-checkbox,
|
||||
#sidebar, #players, #navigation #nav-toggle {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.strong-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fvtt-malefices .tabs .item.active,
|
||||
.blessures-list li ul li:first-child:hover {
|
||||
text-shadow: 1px 0px 0px @color-accent;
|
||||
}
|
||||
|
||||
.rollable:hover, .rollable:focus {
|
||||
color: #000;
|
||||
text-shadow: 0 0 10px red;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fvtt-malefices input:hover, .fvtt-malefices select:hover {
|
||||
border-width: 4px;
|
||||
border-color: rgb(85, 65, 130);
|
||||
}
|
||||
|
||||
.fvtt-malefices input:disabled {
|
||||
color:#1c2058;
|
||||
}
|
||||
.fvtt-malefices select:disabled {
|
||||
color:#1c2058;
|
||||
}
|
||||
table {border: 1px solid #7a7971;}
|
||||
|
||||
.grid, .grid-2col {
|
||||
display: grid;
|
||||
grid-column: span 2 / span 2;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin: 10px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.grid-3col {
|
||||
grid-column: span 3 / span 3;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-4col {
|
||||
grid-column: span 4 / span 4;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-5col {
|
||||
grid-column: span 5 / span 5;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-6col {
|
||||
grid-column: span 5 / span 5;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-7col {
|
||||
grid-column: span 7 / span 7;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-8col {
|
||||
grid-column: span 8 / span 8;
|
||||
grid-template-columns: repeat(8, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-9col {
|
||||
grid-column: span 9 / span 9;
|
||||
grid-template-columns: repeat(9, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-10col {
|
||||
grid-column: span 10 / span 10;
|
||||
grid-template-columns: repeat(10, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-11col {
|
||||
grid-column: span 11 / span 11;
|
||||
grid-template-columns: repeat(11, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-12col {
|
||||
grid-column: span 12 / span 12;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-group-center,
|
||||
.flex-group-left,
|
||||
.flex-group-right {
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.flex-group-left {
|
||||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.flex-group-right {
|
||||
-webkit-box-pack: end;
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-create-actor {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-shrink {
|
||||
flex: 'flex-shrink' ;
|
||||
}
|
||||
325
less/chat.less
Normal file
325
less/chat.less
Normal file
@@ -0,0 +1,325 @@
|
||||
// ============================================================
|
||||
// Chat messages – Belle Époque theme
|
||||
// ============================================================
|
||||
|
||||
@be-bordeaux: #5a0a14;
|
||||
@be-gold: #8b6914;
|
||||
@be-gold-light: #c8a84b;
|
||||
@be-gold-border: rgba(139, 105, 20, 0.45);
|
||||
@be-sepia: #3d2b1f;
|
||||
@be-sepia-light: rgba(61, 43, 31, 0.06);
|
||||
|
||||
.malefices-chat-card {
|
||||
font-size: 0.85rem;
|
||||
color: @be-sepia;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
background: rgb(218, 218, 208); // opaque pour masquer le fond parchemin du sidebar
|
||||
|
||||
// ── Header ──────────────────────────────────────────────
|
||||
.chat-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
background: linear-gradient(135deg, rgba(90,10,20,0.12), rgba(139,105,20,0.12));
|
||||
border-bottom: 1px solid @be-gold-border;
|
||||
|
||||
.chat-actor-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chat-actor-name {
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 1.1rem;
|
||||
font-weight: normal;
|
||||
color: @be-bordeaux;
|
||||
line-height: 1.1;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,0.5);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.chat-header-roll {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
padding-left: 0.4rem;
|
||||
border-left: 1px solid @be-gold-border;
|
||||
|
||||
.chat-roll-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chat-roll-name {
|
||||
font-size: 0.75rem;
|
||||
color: fade(@be-sepia, 80%);
|
||||
font-style: italic;
|
||||
max-width: 80px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Decorative separator ─────────────────────────────────
|
||||
.chat-card-separator {
|
||||
height: 14px;
|
||||
margin: 0.15rem 0.4rem 0;
|
||||
background: url("../images/ui/separator_01.webp") center/auto 100% no-repeat;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
// ── Roll detail rows ─────────────────────────────────────
|
||||
.chat-roll-details {
|
||||
margin: 0;
|
||||
padding: 0 0.4rem 0.15rem;
|
||||
|
||||
.chat-detail-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
padding: 0.05rem 0;
|
||||
border-bottom: 1px dotted rgba(139, 105, 20, 0.2);
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
|
||||
dt {
|
||||
color: fade(@be-sepia, 75%);
|
||||
font-weight: normal;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
dd {
|
||||
font-weight: 600;
|
||||
color: @be-sepia;
|
||||
font-size: 0.85rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Target and roll value stand out slightly
|
||||
.chat-detail-target dd,
|
||||
.chat-detail-roll dd {
|
||||
font-size: 1rem;
|
||||
color: @be-bordeaux;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Result banner ────────────────────────────────────────
|
||||
.chat-card-result {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
margin: 0.2rem 0.4rem 0.25rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 2px;
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 1.15rem;
|
||||
text-align: center;
|
||||
border: 1px solid transparent;
|
||||
|
||||
&.result-success {
|
||||
background: linear-gradient(135deg, rgba(20, 80, 20, 0.12), rgba(40, 100, 40, 0.08));
|
||||
border-color: rgba(30, 100, 30, 0.35);
|
||||
color: #1a5c1a;
|
||||
}
|
||||
|
||||
&.result-failure {
|
||||
background: linear-gradient(135deg, rgba(90, 10, 20, 0.12), rgba(120, 20, 20, 0.08));
|
||||
border-color: rgba(90, 10, 20, 0.35);
|
||||
color: @be-bordeaux;
|
||||
}
|
||||
|
||||
i { margin-right: 0.3rem; }
|
||||
|
||||
.chat-result-damage {
|
||||
font-family: sans-serif;
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.85;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Action buttons (Relancer, etc.) ──────────────────────
|
||||
.chat-card-actions {
|
||||
padding: 0.15rem 0.4rem 0.25rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.chat-card-button {
|
||||
padding: 0.3rem 1rem;
|
||||
font-size: 0.82rem;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(to bottom, rgba(255,252,240,0.9), rgba(240,230,200,0.9));
|
||||
color: @be-sepia;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, rgba(240,220,170,0.95), rgba(220,195,140,0.95));
|
||||
border-color: @be-gold;
|
||||
color: @be-bordeaux;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Tarot card display ──────────────────────────────────
|
||||
.tarot-card-display {
|
||||
display: flex;
|
||||
gap: 0.6rem;
|
||||
align-items: flex-start;
|
||||
padding: 0.3rem 0.5rem 0.4rem;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
z-index: 100;
|
||||
|
||||
.tarot-card-img {
|
||||
transform: scale(2.5);
|
||||
box-shadow: 3px 3px 12px rgba(0,0,0,0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.tarot-card-img {
|
||||
width: 126px;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
transform-origin: left center;
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.tarot-card-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
padding-top: 0.2rem;
|
||||
|
||||
.tarot-card-name {
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 1rem;
|
||||
color: @be-bordeaux;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
.tarot-card-side {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
&.tarot-positif { color: #1a5c1a; }
|
||||
&.tarot-negatif { color: @be-bordeaux; }
|
||||
}
|
||||
|
||||
.tarot-card-value {
|
||||
font-size: 0.82rem;
|
||||
color: @be-sepia;
|
||||
strong { color: @be-bordeaux; font-size: 1rem; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Item post message ────────────────────────────────────
|
||||
.malefices-chat-card.malefices-chat-item {
|
||||
|
||||
.item-type-label {
|
||||
font-family: "Cinzel Decorative", "Cinzel", serif;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: @be-bordeaux;
|
||||
opacity: 0.8;
|
||||
margin-left: auto;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.item-damage {
|
||||
font-weight: 700;
|
||||
color: @be-bordeaux;
|
||||
font-size: 1rem;
|
||||
&.item-damage-crit {
|
||||
color: #8b0000;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-item-description {
|
||||
margin: 0.4rem 0.5rem 0.3rem;
|
||||
font-size: 0.82rem;
|
||||
color: @be-sepia;
|
||||
line-height: 1.5;
|
||||
border-top: 1px solid fade(@be-gold-border, 50%);
|
||||
padding-top: 0.4rem;
|
||||
|
||||
p { margin: 0 0 0.3rem; &:last-child { margin: 0; } }
|
||||
em { color: @be-bordeaux; font-style: italic; }
|
||||
strong { color: @be-sepia; }
|
||||
}
|
||||
}
|
||||
|
||||
// ── Welcome message ─────────────────────────────────────
|
||||
.malefices-chat-card.malefices-welcome {
|
||||
|
||||
.welcome-body {
|
||||
padding: 0.3rem 0.6rem 0.4rem;
|
||||
font-size: 0.82rem;
|
||||
color: @be-sepia;
|
||||
line-height: 1.4;
|
||||
|
||||
p { margin: 0.2rem 0; }
|
||||
|
||||
.welcome-title {
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 0.95rem;
|
||||
color: @be-bordeaux;
|
||||
font-weight: normal;
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
a { color: @be-gold; &:hover { color: @be-bordeaux; } }
|
||||
}
|
||||
|
||||
.welcome-commands {
|
||||
margin-top: 0.4rem;
|
||||
border-top: 1px solid @be-gold-border;
|
||||
padding-top: 0.3rem;
|
||||
|
||||
.welcome-commands-title {
|
||||
font-weight: 700;
|
||||
font-size: 0.8rem;
|
||||
color: @be-sepia;
|
||||
margin-bottom: 0.2rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.welcome-command-row {
|
||||
font-size: 0.8rem;
|
||||
color: @be-sepia;
|
||||
margin: 0.1rem 0;
|
||||
code {
|
||||
background: rgba(139,105,20,0.12);
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
padding: 0 3px;
|
||||
font-size: 0.78rem;
|
||||
color: @be-bordeaux;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
616
less/components.less
Normal file
616
less/components.less
Normal file
@@ -0,0 +1,616 @@
|
||||
/* ======================================== */
|
||||
/* Global UI elements */
|
||||
|
||||
/* ======================================== */
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
ul, li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.sheet li {
|
||||
margin: 0.010rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
.header-fields li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.alterne-list > .list-item:hover {
|
||||
background: rgba(100, 100, 50, 0.25);
|
||||
}
|
||||
.alterne-list > .list-item:nth-child(even) {
|
||||
background: rgba(80, 60, 0, 0.10);
|
||||
}
|
||||
.alterne-list > .list-item:nth-child(odd) {
|
||||
background: rgb(160, 130, 100, 0.05);
|
||||
}
|
||||
|
||||
.specialisation-label {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.carac-label,
|
||||
.attr-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
margin: 0.125rem;
|
||||
/*box-shadow: inset 0px 0px 1px #00000096;
|
||||
border-radius: 0.25rem;*/
|
||||
padding: 0.125rem;
|
||||
flex: 1 1 5rem;
|
||||
display: flex !important;
|
||||
color: @color-text;
|
||||
}
|
||||
.list-item-shadow {
|
||||
background:rgba(87, 60, 32, 0.35);
|
||||
flex-grow: 0;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.list-item-shadow2 {
|
||||
background:rgba(87, 60, 32, 0.25);
|
||||
flex-grow: 0;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.item-display-show {
|
||||
display: block;
|
||||
}
|
||||
.item-display-hide {
|
||||
display: none;
|
||||
}
|
||||
.item-quantite {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
.list-item-margin1 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.list-item-margin2 {
|
||||
margin-left: 2rem;
|
||||
}
|
||||
.list-item-margin3 {
|
||||
margin-left: 3rem;
|
||||
}
|
||||
.list-item-margin4 {
|
||||
margin-left: 4rem;
|
||||
}
|
||||
|
||||
.sheet-competence-img {
|
||||
width: 24px;
|
||||
max-width: 24px;
|
||||
height: 24px;
|
||||
max-height: 24px;
|
||||
flex-grow: 0;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
.competence-column {
|
||||
flex-direction: column;
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
flex-grow: 0;
|
||||
flex-basis: 1;
|
||||
}
|
||||
.competence-header {
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
font-weight: bold;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.description-label {
|
||||
flex-grow: 2;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.status-header-label {
|
||||
margin-left: 2px;
|
||||
}
|
||||
.roll-dialog-label {
|
||||
margin: 4px 0;
|
||||
min-width: 96px;
|
||||
}
|
||||
.short-label {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.keyword-label {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.item-sheet-label {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.item-text-long-line {
|
||||
flex-grow: 3;
|
||||
}
|
||||
|
||||
.score-label {
|
||||
flex-grow: 2;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.attribut-value,
|
||||
.carac-value {
|
||||
flex-grow: 0;
|
||||
flex-basis: 64px;
|
||||
margin-right: 4px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.sante-value,
|
||||
.competence-value {
|
||||
flex-grow: 0;
|
||||
flex-basis: 2rem;
|
||||
margin-right: 0.25rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
.description-value {
|
||||
flex-grow: 0;
|
||||
flex-basis: 4rem;
|
||||
margin-right: 0.25rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
.small-label {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.padd-right {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.padd-left {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.stack-left {
|
||||
align-items:center;
|
||||
flex-shrink: 1;
|
||||
flex-grow: 0;
|
||||
}
|
||||
.packed-left {
|
||||
white-space: nowrap;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.input-numeric-short {
|
||||
width: 40px;
|
||||
max-width: 40px;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
flex-basis: 40px;
|
||||
margin-right: 0.25rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.abilities-table {
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
/* ======================================== */
|
||||
.tokenhudext {
|
||||
display: flex;
|
||||
flex: 0 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
.tokenhudext.left {
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 2.75rem;
|
||||
right: 4rem;
|
||||
}
|
||||
.tokenhudext.right {
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 2.75rem;
|
||||
left: 4rem;
|
||||
}
|
||||
.control-icon.tokenhudicon {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
min-width: 6rem;
|
||||
flex-basis: auto;
|
||||
padding: 0;
|
||||
line-height: 1rem;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
.control-icon.tokenhudicon.right {
|
||||
margin-left: 8px;
|
||||
}
|
||||
#token-hud .status-effects.active{
|
||||
z-index: 2;
|
||||
}
|
||||
.token-sheet .window-content .flexcol .sheet-tabs {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* ======================================== */
|
||||
.item-checkbox {
|
||||
height: 25px;
|
||||
border: 1px solid #736953a6;
|
||||
border-left: none;
|
||||
font-weight: 500;
|
||||
font-size: 1rem;
|
||||
color: black;
|
||||
padding-top: 5px;
|
||||
margin-right: 0px;
|
||||
width: 45px;
|
||||
position: relative;
|
||||
left: 0px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.skill-label {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
.skill-good-checkbox {
|
||||
max-height: 10px;
|
||||
max-width: 10px;
|
||||
}
|
||||
|
||||
.flex-actions-bar {
|
||||
flex-grow: 2;
|
||||
}
|
||||
|
||||
/* ======================================== */
|
||||
/* Sidebar CSS */
|
||||
#sidebar {
|
||||
font-size: 1rem;
|
||||
/*background-position: 100%;*/
|
||||
background-color: @color-sidebar-bg;
|
||||
background-position: 0px 35px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: @bg-sheet;
|
||||
color: @color-text;
|
||||
}
|
||||
|
||||
#sidebar .scene {
|
||||
color: rgba(237, 240, 199, 0.95);
|
||||
}
|
||||
/* background: rgb(105,85,65) url("../images/ui/texture_feuille_perso_onglets.webp") no-repeat right bottom;*/
|
||||
|
||||
#sidebar.collapsed {
|
||||
height: 470px !important;
|
||||
}
|
||||
|
||||
#sidebar-tabs > .collapsed, #chat-controls .chat-control-icon {
|
||||
color: @color-text;
|
||||
text-shadow: 1px 1px 0 rgba(0,0,0,0.75);
|
||||
}
|
||||
|
||||
.sidebar-tab .directory-list .entity {
|
||||
border-top: 1px dashed rgba(0,0,0,0.25);
|
||||
border-bottom: 0 none;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.sidebar-tab .directory-list .entity:hover {
|
||||
background: rgba(0,0,0,0.05);
|
||||
cursor: pointer;
|
||||
}
|
||||
.chat-message-header {
|
||||
background: rgba(220,220,210,0.5);
|
||||
font-size: 1.1rem;
|
||||
height: 48px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chat-message .message-header .flavor-text, .chat-message .message-header .whisper-to {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.chat-result-text,
|
||||
.chat-actor-name {
|
||||
font-weight: bold;
|
||||
font-family: Rivanna;
|
||||
font-size: 1.2rem;
|
||||
padding: 4px;
|
||||
}
|
||||
.chat-result-success {
|
||||
color:darkgreen;
|
||||
}
|
||||
.chat-result-failure {
|
||||
color:darkred;
|
||||
}
|
||||
.chat-img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.roll-dialog-header {
|
||||
height: 52px;
|
||||
}
|
||||
|
||||
.actor-icon {
|
||||
float: left;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
padding: 2px 6px 2px 2px;
|
||||
}
|
||||
|
||||
.padding-dice {
|
||||
padding-top: .2rem;
|
||||
padding-bottom: .2rem;
|
||||
}
|
||||
|
||||
.dice-image {
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.dice-image-reroll {
|
||||
background-color:rgba(115, 224, 115, 0.25);
|
||||
border-color: #011d33;
|
||||
box-sizing: border-box;
|
||||
border: 1px;
|
||||
border-radius: 0%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.chat-dice {
|
||||
width: 15%;
|
||||
height: 15%;
|
||||
font-size: 15px;
|
||||
padding: 10px;
|
||||
padding-bottom: 20px;
|
||||
padding-top: .2rem;
|
||||
padding-bottom: .2rem;
|
||||
}
|
||||
|
||||
.div-center {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.chat-message {
|
||||
background: rgba(220,220,210,0.5);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.chat-message.whisper {
|
||||
background: rgba(220,220,210,0.75);
|
||||
border: 2px solid #545469;
|
||||
}
|
||||
|
||||
.chat-message .chat-icon {
|
||||
border: 0;
|
||||
padding: 2px 6px 2px 2px;
|
||||
float: left;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.ability-icon {
|
||||
border: 0;
|
||||
padding: 2px 2px 2px 2px;
|
||||
max-width:32px;
|
||||
max-height:32px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
.small-ability-icon {
|
||||
border: 0;
|
||||
padding: 2px 2px 2px 2px;
|
||||
max-width:16px;
|
||||
max-height:16px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
.combat-icon {
|
||||
border: 0;
|
||||
padding: 2px 2px 2px 2px;
|
||||
max-width:24px;
|
||||
max-height:24px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#sidebar-tabs {
|
||||
flex: 0 0 32px;
|
||||
box-sizing: border-box;
|
||||
margin: 0 0 5px;
|
||||
border-bottom: 1px solid rgba(0,0,0,0);
|
||||
box-shadow: inset 0 0 2rem rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
#sidebar-tabs > .item.active {
|
||||
border: 1px solid rgba(114,98,72,1);
|
||||
background: rgba(30, 25, 20, 0.75);
|
||||
box-shadow: 0 0 6px inset rgba(114,98,72,1);
|
||||
}
|
||||
|
||||
#sidebar #sidebar-tabs i{
|
||||
display: inline-block;
|
||||
background-position:center;
|
||||
background-size:cover;
|
||||
text-shadow: 1px 1px 0 rgba(0,0,0,0.75);
|
||||
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Control, Tool, hotbar & navigation */
|
||||
|
||||
#controls .scene-control, #controls .control-tool {
|
||||
box-shadow: 0 0 3px #000;
|
||||
margin: 0 0 8px;
|
||||
border-radius: 0;
|
||||
background: rgba(30, 25, 20, 1);
|
||||
background-origin: padding-box;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
}
|
||||
|
||||
#controls .scene-control.active, #controls .control-tool.active, #controls .scene-control:hover, #controls .control-tool:hover {
|
||||
background: rgba(72, 46, 28, 1);
|
||||
background-origin: padding-box;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
box-shadow: 0 0 3px #ff6400;
|
||||
}
|
||||
|
||||
#hotbar #action-bar #macro-list {
|
||||
border: 1px solid rgba(72, 46, 28, 1);
|
||||
box-shadow: 2px 2px 5px #000000;
|
||||
}
|
||||
|
||||
#hotbar #action-bar .macro {
|
||||
border-image: url(img/ui/bg_control.jpg) 21 repeat;
|
||||
border-image-slice: 6 6 6 6 fill;
|
||||
border-image-width: 6px 6px 6px 6px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
#hotbar .bar-controls {
|
||||
background: rgba(30, 25, 20, 1);
|
||||
border: 1px solid rgba(72, 46, 28, 1);
|
||||
}
|
||||
|
||||
#players {
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
background: rgba(30, 25, 20, 1);
|
||||
}
|
||||
|
||||
#navigation #scene-list .scene.nav-item.active {
|
||||
background: rgba(72, 46, 28, 1);
|
||||
}
|
||||
|
||||
#navigation #scene-list .scene.nav-item {
|
||||
background: rgba(30, 25, 20, 1);
|
||||
background-origin: padding-box;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
}
|
||||
|
||||
#navigation #scene-list .scene.view, #navigation #scene-list .scene.context {
|
||||
background: rgba(72, 46, 28, 1);
|
||||
background-origin: padding-box;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
box-shadow: 0 0 3px #ff6400;
|
||||
}
|
||||
|
||||
#navigation #nav-toggle {
|
||||
background: rgba(30, 25, 20, 1);
|
||||
background-origin: padding-box;
|
||||
border-image: url(img/ui/footer-button.png) 10 repeat;
|
||||
border-image-width: 4px;
|
||||
border-image-outset: 0px;
|
||||
}
|
||||
|
||||
/* Tooltip container */
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
/*border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
|
||||
}
|
||||
|
||||
/* Tooltip text */
|
||||
.tooltip .tooltiptext {
|
||||
text-align: left;
|
||||
background: rgba(231, 229, 226, 0.9);
|
||||
width: 150px;
|
||||
padding: 3px 0;
|
||||
font-size: 0.9rem;
|
||||
|
||||
/* Position the tooltip text */
|
||||
top: 1px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
|
||||
/* Fade in tooltip */
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
|
||||
.tooltip-nobottom {
|
||||
border-bottom: unset; /* If you want dots under the hoverable text */
|
||||
}
|
||||
|
||||
/* Show the tooltip text when you mouse over the tooltip container */
|
||||
.tooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.chat-card-button {
|
||||
box-shadow: inset 0px 1px 0px 0px #a6827e;
|
||||
background: linear-gradient(to bottom, #21374afc 5%, #152833ab 100%);
|
||||
background-color: #7d5d3b00;
|
||||
border-radius: 3px;
|
||||
border: 2px ridge #846109;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
color: #ffffff;
|
||||
font-size: 0.8rem;
|
||||
padding: 4px 12px 0px 12px;
|
||||
text-decoration: none;
|
||||
text-shadow: 0px 1px 0px #4d3534;
|
||||
position: relative;
|
||||
margin:2px;
|
||||
}
|
||||
|
||||
.chat-card-button:hover {
|
||||
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
|
||||
background-color: red;
|
||||
}
|
||||
.chat-card-button:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
.plus-minus-button {
|
||||
box-shadow: inset 0px 1px 0px 0px #a6827e;
|
||||
background: linear-gradient(to bottom, #21374afc 5%, #152833ab 100%);
|
||||
background-color: #7d5d3b00;
|
||||
border-radius: 2px;
|
||||
border: 1px ridge #846109;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
color: #ffffff;
|
||||
margin: 2px 2px 2px 2px;
|
||||
padding: 2px 2px 2px 2px;
|
||||
text-decoration: none;
|
||||
text-shadow: 0px 1px 0px #4d3534;
|
||||
position: relative;
|
||||
margin:0px;
|
||||
}
|
||||
|
||||
.plus-minus-button:hover,
|
||||
.chat-card-button:hover {
|
||||
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.plus-minus-button:active,
|
||||
.chat-card-button:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
.plus-minus {
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ul-level1 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
469
less/dialogs.less
Normal file
469
less/dialogs.less
Normal file
@@ -0,0 +1,469 @@
|
||||
/* ===================================================================
|
||||
AppV2 Dialogs — Style Belle Époque (France, ~1900)
|
||||
Palette : bordeaux, or antique, sépia, fond parchemin clair
|
||||
=================================================================== */
|
||||
|
||||
// Couleurs Belle Époque
|
||||
@be-bordeaux: #5a0a14;
|
||||
@be-gold: #8b6914;
|
||||
@be-gold-light: rgba(139, 105, 20, 0.25);
|
||||
@be-gold-border: rgba(139, 105, 20, 0.55);
|
||||
@be-sepia: #3d2b1f;
|
||||
@be-sepia-light: rgba(61, 43, 31, 0.08);
|
||||
|
||||
.malefices-roll-dialog {
|
||||
|
||||
.window-content {
|
||||
padding: 0;
|
||||
background: @bg-sheet;
|
||||
color: @be-sepia;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.skill-roll-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
// ── En-tête ──────────────────────────────────────────────
|
||||
header.roll-dialog-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.6rem 0.75rem 0.5rem;
|
||||
background: linear-gradient(to bottom, rgba(90, 10, 20, 0.12), rgba(90, 10, 20, 0.04));
|
||||
border-bottom: 2px solid @be-gold-border;
|
||||
}
|
||||
|
||||
.actor-icon {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
object-fit: cover;
|
||||
border: 2px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.35);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// Custom title div — no h1 to avoid Foundry theme overrides
|
||||
.dialog-roll-title {
|
||||
color: @be-bordeaux;
|
||||
font-family: @font-rivanna;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
line-height: 1.1;
|
||||
text-shadow: 1px 1px 2px rgba(255,255,255,0.6);
|
||||
}
|
||||
|
||||
// ── Séparateur décoratif ──────────────────────────────────
|
||||
.dialog-separator {
|
||||
width: 100%;
|
||||
height: 18px;
|
||||
background: url("../images/ui/separator_01.webp") center/auto 100% no-repeat;
|
||||
opacity: 0.7;
|
||||
margin: 0.1rem 0;
|
||||
}
|
||||
|
||||
// ── Corps du dialog ───────────────────────────────────────
|
||||
.dialog-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
padding: 0.5rem 0.75rem 0.75rem;
|
||||
}
|
||||
|
||||
// Ligne attribut principal
|
||||
.dialog-attribute-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
gap: 0.5rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
background: @be-gold-light;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
|
||||
.dialog-attr-label {
|
||||
font-family: @font-rivanna;
|
||||
font-size: 1.1rem;
|
||||
color: @be-bordeaux;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dialog-attr-value {
|
||||
font-family: @font-rivanna;
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: @be-sepia;
|
||||
min-width: 2rem;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
// Titre de section (éléments biographiques)
|
||||
.dialog-section-title {
|
||||
font-family: @font-rivanna;
|
||||
font-size: 0.95rem;
|
||||
color: @be-gold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border-bottom: 1px solid @be-gold-border;
|
||||
padding-bottom: 0.15rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
// Liste des éléments biographiques
|
||||
.dialog-bio-list {
|
||||
list-style: none;
|
||||
margin: 0 0 0.25rem 0;
|
||||
padding: 0 0 0 0.5rem;
|
||||
|
||||
li {
|
||||
color: @be-sepia;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.1rem 0;
|
||||
border-bottom: 1px dashed rgba(139, 105, 20, 0.2);
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
|
||||
&::before {
|
||||
content: "✦ ";
|
||||
color: @be-gold;
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zone des modificateurs
|
||||
.dialog-modifiers {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.dialog-modifier-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-bottom: 1px solid rgba(139, 105, 20, 0.18);
|
||||
|
||||
&:hover {
|
||||
background: @be-sepia-light;
|
||||
}
|
||||
|
||||
.dialog-modifier-label {
|
||||
flex: 1;
|
||||
color: @be-sepia;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
select {
|
||||
flex: 0 0 140px;
|
||||
width: 140px;
|
||||
border: 1px solid @be-gold-border;
|
||||
background: rgba(255, 252, 245, 0.85);
|
||||
color: @be-sepia;
|
||||
font-size: 0.82rem;
|
||||
padding: 1px 4px;
|
||||
border-radius: 2px;
|
||||
|
||||
&:hover {
|
||||
border-color: @be-gold;
|
||||
border-width: 2px;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: @be-bordeaux;
|
||||
box-shadow: 0 0 3px rgba(90, 10, 20, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer.form-footer {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: linear-gradient(to bottom, rgba(139, 105, 20, 0.08), rgba(139, 105, 20, 0.16));
|
||||
border-top: 1px solid @be-gold-border;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 0.4rem 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(to bottom, rgba(255, 252, 240, 0.9), rgba(240, 230, 200, 0.9));
|
||||
color: @be-sepia;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, rgba(240, 220, 170, 0.95), rgba(220, 195, 140, 0.95));
|
||||
border-color: @be-gold;
|
||||
color: @be-bordeaux;
|
||||
}
|
||||
|
||||
&[data-action="roll"],
|
||||
&[type="submit"] {
|
||||
background: linear-gradient(to bottom, @be-bordeaux, darken(@be-bordeaux, 8%));
|
||||
color: rgba(255, 245, 220, 0.95);
|
||||
border-color: darken(@be-bordeaux, 10%);
|
||||
font-size: 0.95rem;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, lighten(@be-bordeaux, 5%), @be-bordeaux);
|
||||
border-color: @be-bordeaux;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
Dialogs AppV2 partagés (class: MaleficesDialog)
|
||||
— utilisé par Tirage Tarot et Résumé des Personnages
|
||||
=================================================================== */
|
||||
.MaleficesDialog {
|
||||
|
||||
.window-content {
|
||||
background: @bg-sheet;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
// ── Résumé des Personnages ─────────────────────────────
|
||||
.character-summary-container {
|
||||
padding: 0.5rem 0.75rem;
|
||||
color: @be-sepia;
|
||||
|
||||
.items-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-bottom: 1px solid fade(@be-gold-border, 40%);
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
|
||||
&.item-header {
|
||||
background: linear-gradient(135deg, rgba(90,10,20,0.10), rgba(139,105,20,0.10));
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 0.25rem;
|
||||
font-family: "Cinzel Decorative", "Cinzel", serif;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
color: @be-bordeaux;
|
||||
text-transform: uppercase;
|
||||
|
||||
&:not(:first-child) { margin-top: 0.5rem; }
|
||||
}
|
||||
|
||||
&:hover:not(.item-header) {
|
||||
background: rgba(139, 105, 20, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.item-field {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
|
||||
&.item-name { flex: 3; text-align: left; font-weight: 600; }
|
||||
&.item-name-label-long { flex: 3; text-align: left; }
|
||||
&.item-name-label-short { flex: 1; text-align: center; }
|
||||
&.right { text-align: right; }
|
||||
}
|
||||
|
||||
a.summary-roll, a.actor-open {
|
||||
cursor: pointer;
|
||||
color: @be-sepia;
|
||||
&:hover { color: @be-bordeaux; text-decoration: underline; }
|
||||
}
|
||||
|
||||
.actor-delete {
|
||||
color: fade(@be-sepia, 50%);
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
&:hover { color: @be-bordeaux; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tirage-tarot-dialog {
|
||||
display: block;
|
||||
padding: 0.6rem 0.75rem;
|
||||
color: @be-sepia;
|
||||
|
||||
// ── Sélection joueur / attribution ────────────────────
|
||||
.tirage-select-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.4rem 0.6rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: linear-gradient(135deg, rgba(90,10,20,0.08), rgba(139,105,20,0.08));
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
|
||||
.tirage-select-label {
|
||||
flex: 1;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: @be-sepia;
|
||||
}
|
||||
|
||||
.tirage-select {
|
||||
flex: 0 0 180px;
|
||||
width: 180px;
|
||||
border: 1px solid @be-gold-border;
|
||||
background: rgba(255,252,240,0.85);
|
||||
color: @be-sepia;
|
||||
font-size: 0.85rem;
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
&:focus { outline: none; border-color: @be-bordeaux; }
|
||||
}
|
||||
}
|
||||
|
||||
.tirage-attribute-row {
|
||||
background: linear-gradient(135deg, rgba(20,80,20,0.08), rgba(30,100,30,0.05));
|
||||
border-color: rgba(30,100,30,0.35);
|
||||
}
|
||||
|
||||
// ── Section (main joueur / main secrète) ──────────────
|
||||
.tirage-section {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
.tirage-section-title {
|
||||
display: block;
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 1rem;
|
||||
color: @be-bordeaux;
|
||||
border-bottom: 1px solid @be-gold-border;
|
||||
padding-bottom: 0.2rem;
|
||||
margin-bottom: 0.4rem;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,0.4);
|
||||
|
||||
i { margin-right: 0.35rem; font-size: 0.85em; opacity: 0.7; }
|
||||
|
||||
.tirage-player-name {
|
||||
font-size: 0.85rem;
|
||||
font-style: italic;
|
||||
color: @be-sepia;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.tirage-secret-title { color: fade(@be-sepia, 70%); }
|
||||
}
|
||||
|
||||
// ── Grille de cartes ──────────────────────────────────
|
||||
.tirage-cards-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.6rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.tirage-card {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
width: 100px;
|
||||
vertical-align: top;
|
||||
|
||||
&:hover {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
|
||||
.tirage-card-img {
|
||||
transform: scale(2.2);
|
||||
transform-origin: center top;
|
||||
box-shadow: 3px 3px 12px rgba(0,0,0,0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.tirage-card-img {
|
||||
width: 100px;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
transform-origin: center center;
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
.tirage-card-name {
|
||||
font-family: @font-rivanna, serif;
|
||||
font-size: 0.75rem;
|
||||
color: @be-bordeaux;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.tirage-card-side {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
&.tirage-positif { color: #1a5c1a; }
|
||||
&.tirage-negatif { color: @be-bordeaux; }
|
||||
}
|
||||
|
||||
&.tirage-card-secret {
|
||||
opacity: 0.85;
|
||||
.tirage-card-name { color: fade(@be-sepia, 70%); }
|
||||
}
|
||||
}
|
||||
|
||||
// ── Séparateur décoratif ──────────────────────────────
|
||||
.tirage-separator {
|
||||
display: block;
|
||||
height: 18px;
|
||||
background: url("../images/ui/separator_01.webp") center/auto 100% no-repeat;
|
||||
opacity: 0.5;
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Footer avec bouton Fermer ─────────────────────────
|
||||
.tirage-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0.4rem 0.75rem;
|
||||
border-top: 1px solid @be-gold-border;
|
||||
background: linear-gradient(to bottom, rgba(139,105,20,0.08), rgba(139,105,20,0.16));
|
||||
|
||||
.tirage-close-btn {
|
||||
padding: 0.3rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
border: 1px solid @be-gold-border;
|
||||
border-radius: 2px;
|
||||
background: linear-gradient(to bottom, rgba(255,252,240,0.9), rgba(240,230,200,0.9));
|
||||
color: @be-sepia;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, rgba(240,220,170,0.95), rgba(220,195,140,0.95));
|
||||
border-color: @be-gold;
|
||||
color: @be-bordeaux;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
145
less/item-sheet.less
Normal file
145
less/item-sheet.less
Normal file
@@ -0,0 +1,145 @@
|
||||
/* ===================================================================
|
||||
AppV2 Item Sheets
|
||||
Selectors use .fvtt-malefices.item (both classes on the same root
|
||||
element, no space) to target only AppV2 item sheet windows.
|
||||
=================================================================== */
|
||||
|
||||
.fvtt-malefices.item {
|
||||
|
||||
/* window-content: background and remove padding.
|
||||
Foundry AppV2 already sets: display:flex flex-flow:column overflow:hidden */
|
||||
.window-content {
|
||||
padding: 0;
|
||||
background: @bg-sheet;
|
||||
color: @color-text;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* All sections inside item fill their flex container */
|
||||
section {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Fixed header bar */
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
|
||||
/* sheet-body: scroll container */
|
||||
section.sheet-body {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
|
||||
/* Override legacy height: 100% on tab divs; hide all tabs, show only the active one */
|
||||
.tab[data-tab] {
|
||||
height: auto;
|
||||
display: none;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Description editor: ensure enough vertical room */
|
||||
.tab.description {
|
||||
prose-mirror,
|
||||
.editor,
|
||||
.ProseMirror {
|
||||
min-height: 440px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Header layout override for item sheets (smaller than actor sheet header) */
|
||||
.sheet-header {
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.item-sheet-img {
|
||||
flex: 0 0 64px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
object-fit: cover;
|
||||
border: 1px solid #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.item-sheet-title {
|
||||
flex: 1;
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-bottom: none;
|
||||
|
||||
input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-family: @font-rivanna;
|
||||
font-size: 1.8rem;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Tab navigation: AppV2 uses nav.tabs (not nav.sheet-tabs) */
|
||||
nav.tabs {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
font-family: @font-rivanna;
|
||||
font-size: @tab-font-size;
|
||||
font-weight: bold;
|
||||
height: @tab-height;
|
||||
margin: 0;
|
||||
padding: 0 0 0 0.25rem;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
line-height: @tab-height;
|
||||
border-top: 0 none;
|
||||
border-bottom: 0 none;
|
||||
background-color: @color-tab-bg;
|
||||
color: @color-tab-text;
|
||||
gap: 0.25rem;
|
||||
|
||||
a.item {
|
||||
position: relative;
|
||||
padding: 0 0.5rem;
|
||||
color: @color-tab-text;
|
||||
font-family: @font-rivanna;
|
||||
font-size: @tab-font-size;
|
||||
text-decoration: none;
|
||||
line-height: @tab-height;
|
||||
|
||||
&:hover {
|
||||
text-shadow: 1px 0px 0px @color-accent;
|
||||
}
|
||||
|
||||
&.active {
|
||||
text-shadow: 1px 0px 0px @color-accent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
349
less/legacy-sheets.less
Normal file
349
less/legacy-sheets.less
Normal file
@@ -0,0 +1,349 @@
|
||||
/* Styles limited to sheets */
|
||||
.fvtt-malefices .sheet-header {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 210px;
|
||||
flex: 0 0 210px;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.fvtt-malefices .sheet-header .profile-img {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 128px;
|
||||
flex: 0 0 128px;
|
||||
width: 128px;
|
||||
height: auto;
|
||||
max-height:128px;
|
||||
margin-top: 0px;
|
||||
margin-right: 10px;
|
||||
object-fit: cover;
|
||||
object-position: 50% 0;
|
||||
border-width: 0px;
|
||||
}
|
||||
.profile-img-container {
|
||||
margin-right: 0.2rem;
|
||||
max-width: 140px;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.button-img {
|
||||
vertical-align: baseline;
|
||||
width: 8%;
|
||||
height: 8%;
|
||||
max-height: 48px;
|
||||
border-width: 0px;
|
||||
border: 1px solid rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.button-img:hover {
|
||||
color: rgba(255, 255, 128, 0.7);
|
||||
border: 1px solid rgba(255, 128, 0, 0.8);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-effect-img {
|
||||
vertical-align: baseline;
|
||||
width: 16px;
|
||||
max-height: 16px;
|
||||
height: 16;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.small-button-container {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border: 0;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.fvtt-malefices .sheet-header .header-fields {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.fvtt-malefices .sheet-header h1.charname {
|
||||
height: 50px;
|
||||
padding: 0px;
|
||||
margin: 5px 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.fvtt-malefices .sheet-header h1.charname input {
|
||||
font-family: Rivanna;
|
||||
font-size: 3rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.fvtt-malefices .sheet-tabs {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0;
|
||||
flex: 0;
|
||||
font-family: Rivanna;
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
.fvtt-malefices .sheet-body,
|
||||
.fvtt-malefices .sheet-body .tab,
|
||||
.fvtt-malefices .sheet-body .tab .editor {
|
||||
height: 100%;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.editor {
|
||||
border: 2;
|
||||
height: 100%;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
.medium-editor {
|
||||
border: 2;
|
||||
height: 240px;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
.small-editor {
|
||||
border: 2;
|
||||
height: 120px;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
.fvtt-malefices .tox .tox-editor-container {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.fvtt-malefices .tox .tox-edit-area {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.fvtt-malefices .resource-label {
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.fvtt-malefices .tabs {
|
||||
height: 40px;
|
||||
border-top: 1px solid #AAA;
|
||||
border-bottom: 1px solid #AAA;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.fvtt-malefices .tabs .item {
|
||||
line-height: 40px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fvtt-malefices .tabs .item.active {
|
||||
text-decoration: underline;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.fvtt-malefices .items-list {
|
||||
list-style: none;
|
||||
margin: 1px 0;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.fvtt-malefices .items-list .item-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.fvtt-malefices .items-list .item {
|
||||
height: 30px;
|
||||
line-height: 24px;
|
||||
padding: 1px 0;
|
||||
border-bottom: 1px solid #BBB;
|
||||
}
|
||||
|
||||
.fvtt-malefices .items-list .item .item-image {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 24px;
|
||||
flex: 0 0 24px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.fvtt-malefices .items-list .item img {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fvtt-malefices .items-list .item-name {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.fvtt-malefices .items-list .item-controls {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 0 86px;
|
||||
flex: 0 0 86px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
li.folder > .folder-header h3 {
|
||||
color: @color-text;
|
||||
}
|
||||
|
||||
/* ======================================== */
|
||||
/* Sheet */
|
||||
.fvtt-malefices .window-app.sheet .window-content .sheet-header{
|
||||
color: @color-text;
|
||||
background: @bg-sheet;
|
||||
/*background: #494e6b;*/
|
||||
}
|
||||
|
||||
.fvtt-malefices input[type="text"], .fvtt-malefices select[type="text"] {
|
||||
background:white;
|
||||
color: @color-input-text;
|
||||
}
|
||||
|
||||
.fvtt-malefices select {
|
||||
background:white;
|
||||
color: @color-input-text;
|
||||
}
|
||||
/* background: #011d33 url("../images/ui/fond1.webp") repeat left top;*/
|
||||
/*color: rgba(168, 139, 139, 0.5);*/
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-header select[type="text"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-header input[type="text"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-header input[type="number"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-body input[type="text"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-body input[type="number"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-body select[type="text"] {
|
||||
color: @color-text;
|
||||
}
|
||||
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-header input[type="password"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-header input[type="date"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-header input[type="time"] {
|
||||
color: @color-text;
|
||||
background: @bg-sheet;
|
||||
border: 1 none;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-body input[type="password"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-body input[type="date"],
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-body input[type="time"] {
|
||||
color: @color-text;
|
||||
background: @bg-sheet;
|
||||
border: 1 none;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-body select,
|
||||
.fvtt-malefices.window-app.sheet .window-content .sheet-header select {
|
||||
color: @color-text;
|
||||
background: #fff;
|
||||
border: 1 none;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.fvtt-malefices .window-app .window-content, .fvtt-malefices .window-app.sheet .window-content .sheet-body{
|
||||
font-size: 0.8rem;
|
||||
/*background: url("../images/ui/pc_sheet_bg.webp") repeat left top;*/
|
||||
background: @bg-sheet;
|
||||
color: @color-text;
|
||||
}
|
||||
|
||||
/* background: rgba(245,245,240,0.6) url("../images/ui/sheet_background.webp") left top;*/
|
||||
|
||||
section.sheet-body{padding: 0.25rem 0.5rem;}
|
||||
|
||||
.sheet header.sheet-header .profile-img {
|
||||
object-fit: cover;
|
||||
object-position: 50% 0;
|
||||
margin: 0.5rem 0 0.5rem 0.5rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.fvtt-malefices nav.sheet-tabs {
|
||||
font-size: @tab-font-size;
|
||||
font-weight: bold;
|
||||
height: @tab-height;
|
||||
flex: 0 0 @tab-height;
|
||||
margin: 0;
|
||||
padding: 0 0 0 0.25rem;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.5rem;
|
||||
border-top: 0 none;
|
||||
border-bottom: 0 none;
|
||||
background-color: @color-tab-bg;
|
||||
color: @color-tab-text;
|
||||
}
|
||||
|
||||
/* Dice tray specific overrides */
|
||||
.dice-tray button svg * {
|
||||
fill: #6d5923 !important;
|
||||
}
|
||||
.dice-tray input[type="text"] {
|
||||
color: #6d5923 !important;
|
||||
}
|
||||
.dice-tray button {
|
||||
color: #6d5923 !important;
|
||||
}
|
||||
|
||||
.fvtt-malefices nav.sheet-tabs .item {
|
||||
position: relative;
|
||||
padding: 0 0.25rem;
|
||||
color: @color-tab-text;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.fvtt-malefices nav.sheet-tabs .item:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 2rem;
|
||||
width: 1px;
|
||||
/*border-right: 1px dashed rgba(52, 52, 52, 0.25);*/
|
||||
}
|
||||
|
||||
.sheet .tab[data-tab] {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
section.sheet-body:after {
|
||||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.sheet header.sheet-header .flex-compteurs {text-align: right;}
|
||||
.sheet header.sheet-header .resource-content {width: 2rem;}
|
||||
|
||||
.select-diff {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content .tooltip:hover .tooltiptext {
|
||||
top: 2rem;
|
||||
left: 2rem;
|
||||
margin: 0;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.window-app.sheet .window-content .carac-value, .window-app.sheet .window-content .competence-xp {
|
||||
margin: 0.05rem;
|
||||
flex-basis: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
12
less/malefices.less
Normal file
12
less/malefices.less
Normal file
@@ -0,0 +1,12 @@
|
||||
// Main LESS file for Maléfices system
|
||||
// Importing base styles and component-specific styles
|
||||
|
||||
@import "variables";
|
||||
@import "base";
|
||||
@import "legacy-sheets";
|
||||
@import "components";
|
||||
@import "ui";
|
||||
@import "dialogs";
|
||||
@import "chat";
|
||||
@import "item-sheet";
|
||||
@import "actor-sheet";
|
||||
180
less/ui.less
Normal file
180
less/ui.less
Normal file
@@ -0,0 +1,180 @@
|
||||
/*************************************************************/
|
||||
#pause
|
||||
{
|
||||
font-size: 2rem;
|
||||
}
|
||||
#pause > h3
|
||||
{
|
||||
color: #CCC
|
||||
}
|
||||
#pause > img {
|
||||
content: url(../images/ui/logo_pause.webp);
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
top: -100px;
|
||||
left: calc(50% - 132px);
|
||||
}
|
||||
|
||||
#logo {
|
||||
content : url(../images/ui/logo_pause.webp);
|
||||
width: 100px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.dice-cell {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dice-formula,
|
||||
.dice-total {
|
||||
height: 54px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.status-small-label {
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
.no-grow {
|
||||
flex-grow: 1;
|
||||
max-width: 32px;
|
||||
}
|
||||
.status-col-name {
|
||||
max-width: 72px;
|
||||
}
|
||||
.img-no-border {
|
||||
max-width: 48px;
|
||||
max-height: 48px;
|
||||
border: 0px;
|
||||
}
|
||||
.items-title-bg {
|
||||
margin-top: 6px;
|
||||
color: @color-text;
|
||||
|
||||
}
|
||||
.items-title-text {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.lock-icon {
|
||||
width:16px;
|
||||
height: 16px;
|
||||
}
|
||||
.item-sheet-img {
|
||||
width: 64px;
|
||||
height: auto;
|
||||
border: 0;
|
||||
}
|
||||
.item-name-img {
|
||||
flex-grow:1;
|
||||
max-width: 2rem;
|
||||
min-width: 2rem;
|
||||
}
|
||||
.item-name-label-header {
|
||||
flex-grow:2;
|
||||
max-width: 12rem;
|
||||
min-width: 12rem;
|
||||
}
|
||||
.item-name-label-header-long {
|
||||
flex-grow:2;
|
||||
max-width: 14rem;
|
||||
min-width: 14rem;
|
||||
}
|
||||
.item-name-label-header-long2 {
|
||||
flex-grow:2;
|
||||
max-width: 24rem;
|
||||
min-width: 24rem;
|
||||
}
|
||||
.item-name-label {
|
||||
flex-grow:2;
|
||||
max-width: 10rem;
|
||||
min-width: 10rem;
|
||||
}
|
||||
.item-name-label-long {
|
||||
margin-top: 4px;
|
||||
flex-grow:2;
|
||||
max-width: 10rem;
|
||||
min-width: 10rem;
|
||||
}
|
||||
.item-name-label-short {
|
||||
flex-grow:1;
|
||||
max-width: 4rem;
|
||||
min-width: 4rem;
|
||||
}
|
||||
.item-name-label-medium {
|
||||
margin-top: 4px;
|
||||
flex-grow:2;
|
||||
max-width: 6rem;
|
||||
min-width: 6rem;
|
||||
}
|
||||
.item-name-label-long2 {
|
||||
margin-top: 4px;
|
||||
flex-grow:2;
|
||||
max-width: 22rem;
|
||||
min-width: 22rem;
|
||||
}
|
||||
.item-name-label-level2 {
|
||||
flex-grow:2;
|
||||
max-width: 9rem;
|
||||
min-width: 9rem;
|
||||
}
|
||||
.item-field-label-short {
|
||||
flex-grow:1;
|
||||
max-width: 4rem;
|
||||
min-width: 4rem;
|
||||
}
|
||||
.item-field-label-medium {
|
||||
flex-grow:1;
|
||||
max-width: 6rem;
|
||||
min-width: 6rem;
|
||||
}
|
||||
.item-field-skill {
|
||||
flex-grow:1;
|
||||
max-width: 6.8rem;
|
||||
min-width: 6.8rem;
|
||||
}
|
||||
.item-field-label-long {
|
||||
flex-grow:1;
|
||||
max-width: 10rem;
|
||||
min-width: 10rem;
|
||||
}
|
||||
.item-control-end {
|
||||
align-self: flex-end;
|
||||
}
|
||||
.alternate-list {
|
||||
margin-top: 4px;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.item-filler {
|
||||
flex-grow: 6;
|
||||
flex-shrink: 7;
|
||||
}
|
||||
.item-controls-fixed {
|
||||
min-width:2rem;
|
||||
max-width: 2rem;
|
||||
}
|
||||
.attribute-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
.flexrow-no-expand {
|
||||
flex-grow: 0;
|
||||
}
|
||||
.item-input-small {
|
||||
max-width: 16px;
|
||||
max-height: 12px;
|
||||
}
|
||||
.flip-tarot {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
.tarot-fixed-width {
|
||||
width: 140px;
|
||||
max-width: 140px;
|
||||
}
|
||||
.tarot-title {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.character-summary-rollable {
|
||||
text-decoration: underline;
|
||||
}
|
||||
19
less/variables.less
Normal file
19
less/variables.less
Normal file
@@ -0,0 +1,19 @@
|
||||
// ==================== Variables ====================
|
||||
|
||||
// Fonts
|
||||
@font-rivanna: Rivanna, serif;
|
||||
|
||||
// Colors
|
||||
@color-text: rgba(19, 18, 18, 0.95);
|
||||
@color-accent: #ff6600;
|
||||
@color-tab-bg: #252525;
|
||||
@color-tab-text: beige;
|
||||
@color-input-text: #494e6b;
|
||||
@color-sidebar-bg: #f5f5f5;
|
||||
|
||||
// Backgrounds
|
||||
@bg-sheet: url("../images/ui/background_01_clear.webp");
|
||||
|
||||
// Tabs
|
||||
@tab-height: 3rem;
|
||||
@tab-font-size: 1.2rem;
|
||||
13
modules/applications/sheets/_module.mjs
Normal file
13
modules/applications/sheets/_module.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Index des fiches AppV2 pour Maléfices
|
||||
*/
|
||||
// Actor sheets
|
||||
export { default as MaleficesPersonnageSheet } from './malefices-personnage-sheet.mjs';
|
||||
export { default as MaleficesNPCActorSheet } from './malefices-npc-actor-sheet.mjs';
|
||||
// Item sheets
|
||||
export { default as MaleficesArmeSheet } from './malefices-arme-sheet.mjs';
|
||||
export { default as MaleficesEquipementSheet } from './malefices-equipement-sheet.mjs';
|
||||
export { default as MaleficesArchetypeSheet } from './malefices-archetype-sheet.mjs';
|
||||
export { default as MaleficesTarotSheet } from './malefices-tarot-sheet.mjs';
|
||||
export { default as MaleficesSortilegeSheet } from './malefices-sortilege-sheet.mjs';
|
||||
export { default as MaleficesElementbioSheet } from './malefices-elementbio-sheet.mjs';
|
||||
132
modules/applications/sheets/base-item-sheet.mjs
Normal file
132
modules/applications/sheets/base-item-sheet.mjs
Normal file
@@ -0,0 +1,132 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class MaleficesItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-malefices", "item"],
|
||||
position: {
|
||||
width: 620,
|
||||
height: 600,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: MaleficesItemSheet.#onEditImage,
|
||||
postItem: MaleficesItemSheet.#onPostItem,
|
||||
},
|
||||
}
|
||||
|
||||
/** @type {object} */
|
||||
tabGroups = { primary: "description" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
item: this.document,
|
||||
system: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.description ?? "", { async: true }
|
||||
),
|
||||
isEditable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
isGM: game.user.isGM,
|
||||
config: game.system.malefices.config,
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
|
||||
// Manual tab navigation
|
||||
const nav = this.element.querySelector('nav.tabs[data-group]')
|
||||
if (nav) {
|
||||
const group = nav.dataset.group
|
||||
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()
|
||||
})
|
||||
})
|
||||
this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => {
|
||||
content.classList.toggle('active', content.dataset.tab === activeTab)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map((d) => {
|
||||
d.permissions = {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
}
|
||||
|
||||
_canDragStart(selector) { return this.isEditable }
|
||||
_canDragDrop(selector) { return this.isEditable }
|
||||
|
||||
_onDragStart(event) {
|
||||
const dragData = { type: "Item", uuid: this.document.uuid }
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
_onDragOver(event) {}
|
||||
|
||||
async _onDrop(event) {}
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
static async #onEditImage(event, target) {
|
||||
const fp = new FilePicker({
|
||||
type: "image",
|
||||
current: this.document.img,
|
||||
callback: (path) => { this.document.update({ img: path }) },
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
static async #onPostItem(event, target) {
|
||||
let chatData = foundry.utils.duplicate(this.document)
|
||||
if (this.document.actor) {
|
||||
chatData.actor = { id: this.document.actor.id }
|
||||
}
|
||||
if (chatData.img?.includes("/blank.png")) {
|
||||
chatData.img = null
|
||||
}
|
||||
chatData.jsondata = JSON.stringify({ compendium: "postedItem", payload: chatData })
|
||||
const html = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/fvtt-malefices/templates/post-item.hbs', chatData
|
||||
)
|
||||
ChatMessage.create({ user: game.user.id, content: html })
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
36
modules/applications/sheets/malefices-archetype-sheet.mjs
Normal file
36
modules/applications/sheets/malefices-archetype-sheet.mjs
Normal file
@@ -0,0 +1,36 @@
|
||||
import MaleficesItemSheet from "./base-item-sheet.mjs"
|
||||
import { MaleficesUtility } from "../../malefices-utility.js"
|
||||
|
||||
export default class MaleficesArchetypeSheet extends MaleficesItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["archetype"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["archetype-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/items/item-archetype-sheet.hbs" },
|
||||
}
|
||||
|
||||
tabGroups = { primary: "details" }
|
||||
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" },
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
const tarots = MaleficesUtility.getTarots() ?? []
|
||||
context.tarots = Object.fromEntries(tarots.map(t => [t._id, t.name]))
|
||||
return context
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/malefices-arme-sheet.mjs
Normal file
33
modules/applications/sheets/malefices-arme-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import MaleficesItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MaleficesArmeSheet extends MaleficesItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["arme"],
|
||||
position: { width: 640 },
|
||||
window: { contentClasses: ["arme-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/items/item-arme-sheet.hbs" },
|
||||
}
|
||||
|
||||
tabGroups = { primary: "details" }
|
||||
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" },
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
225
modules/applications/sheets/malefices-base-actor-sheet.mjs
Normal file
225
modules/applications/sheets/malefices-base-actor-sheet.mjs
Normal file
@@ -0,0 +1,225 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
import { MaleficesUtility } from "../../malefices-utility.js"
|
||||
|
||||
export default class MaleficesActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
this._editScore = true
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-malefices", "actor"],
|
||||
position: {
|
||||
width: 640,
|
||||
height: 680,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: MaleficesActorSheet.#onEditImage,
|
||||
toggleSheet: MaleficesActorSheet.#onToggleSheet,
|
||||
editItem: MaleficesActorSheet.#onEditItem,
|
||||
deleteItem: MaleficesActorSheet.#onDeleteItem,
|
||||
createItem: MaleficesActorSheet.#onCreateItem,
|
||||
equipItem: MaleficesActorSheet.#onEquipItem,
|
||||
modifyQuantity: MaleficesActorSheet.#onModifyQuantity,
|
||||
modifyAmmo: MaleficesActorSheet.#onModifyAmmo,
|
||||
rollAttribut: MaleficesActorSheet.#onRollAttribut,
|
||||
rollArme: MaleficesActorSheet.#onRollArme,
|
||||
editSubActor: MaleficesActorSheet.#onEditSubActor,
|
||||
deleteSubActor: MaleficesActorSheet.#onDeleteSubActor,
|
||||
},
|
||||
}
|
||||
|
||||
/** @type {object} */
|
||||
tabGroups = { primary: "main" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
return {
|
||||
actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
isEditable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
isGM: game.user.isGM,
|
||||
config: game.system.malefices.config,
|
||||
editScore: this._editScore,
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
|
||||
// Ignore Enter key in text inputs (not textarea)
|
||||
this.element.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && e.target.tagName !== 'TEXTAREA') e.preventDefault()
|
||||
})
|
||||
|
||||
// Manual tab navigation
|
||||
const nav = this.element.querySelector('nav.tabs[data-group]')
|
||||
if (nav) {
|
||||
const group = nav.dataset.group
|
||||
const activeTab = this.tabGroups[group] || "main"
|
||||
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||
link.classList.toggle('active', link.dataset.tab === activeTab)
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
this.tabGroups[group] = link.dataset.tab
|
||||
this.render()
|
||||
})
|
||||
})
|
||||
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(content => {
|
||||
content.classList.toggle('active', content.dataset.tab === activeTab)
|
||||
})
|
||||
}
|
||||
|
||||
// Handle .update-field change events (legacy support)
|
||||
this.element.querySelectorAll('.update-field').forEach(el => {
|
||||
el.addEventListener('change', (ev) => {
|
||||
const fieldName = ev.currentTarget.dataset.fieldName
|
||||
const value = Number(ev.currentTarget.value)
|
||||
this.actor.update({ [fieldName]: value })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map((d) => {
|
||||
d.permissions = {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop.implementation(d)
|
||||
})
|
||||
}
|
||||
|
||||
_canDragStart(selector) { return this.isEditable }
|
||||
_canDragDrop(selector) { return this.isEditable }
|
||||
|
||||
_onDragStart(event) {
|
||||
const li = event.currentTarget.closest('.item')
|
||||
if (!li) return
|
||||
const itemId = li.dataset.itemId
|
||||
const item = this.actor.items.get(itemId)
|
||||
if (item) {
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify({ type: "Item", uuid: item.uuid }))
|
||||
}
|
||||
}
|
||||
|
||||
_onDragOver(event) {}
|
||||
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
if (data?.type === "Actor") {
|
||||
const actor = await fromUuid(data.uuid)
|
||||
if (actor) this.actor.addSubActor(actor.id)
|
||||
} else {
|
||||
super._onDrop(event)
|
||||
}
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
static async #onEditImage(event, target) {
|
||||
const fp = new FilePicker({
|
||||
type: "image",
|
||||
current: this.document.img,
|
||||
callback: (path) => { this.document.update({ img: path }) },
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
static async #onToggleSheet(event, target) {
|
||||
this._editScore = !this._editScore
|
||||
this.render()
|
||||
}
|
||||
|
||||
static async #onEditItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
this.actor.items.get(itemId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onDeleteItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
MaleficesUtility.confirmDelete(this, li)
|
||||
}
|
||||
|
||||
static async #onCreateItem(event, target) {
|
||||
const dataType = target.dataset.type
|
||||
this.actor.createEmbeddedDocuments('Item', [{ name: "NewItem", type: dataType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
static async #onEquipItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
await this.actor.equipItem(itemId)
|
||||
this.render()
|
||||
}
|
||||
|
||||
static async #onModifyQuantity(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
const delta = parseInt(target.dataset.delta) || 0
|
||||
this.actor.incDecQuantity(itemId, delta)
|
||||
}
|
||||
|
||||
static async #onModifyAmmo(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
const delta = parseInt(target.dataset.delta) || 0
|
||||
this.actor.incDecAmmo(itemId, delta)
|
||||
}
|
||||
|
||||
static async #onRollAttribut(event, target) {
|
||||
const attrKey = target.dataset.attrKey
|
||||
this.actor.rollAttribut(attrKey)
|
||||
}
|
||||
|
||||
static async #onRollArme(event, target) {
|
||||
const armeId = target.dataset.armeId
|
||||
this.actor.rollArme(armeId)
|
||||
}
|
||||
|
||||
static async #onEditSubActor(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const actorId = li?.dataset.actorId
|
||||
if (!actorId) return
|
||||
game.actors.get(actorId)?.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onDeleteSubActor(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const actorId = li?.dataset.actorId
|
||||
if (!actorId) return
|
||||
this.actor.delSubActor(actorId)
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
32
modules/applications/sheets/malefices-elementbio-sheet.mjs
Normal file
32
modules/applications/sheets/malefices-elementbio-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import MaleficesItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MaleficesElementbioSheet extends MaleficesItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["elementbio"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["elementbio-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/items/item-elementbio-sheet.hbs" },
|
||||
}
|
||||
|
||||
tabGroups = { primary: "description" }
|
||||
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
description: { id: "description", group: "primary", label: "Description" },
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
32
modules/applications/sheets/malefices-equipement-sheet.mjs
Normal file
32
modules/applications/sheets/malefices-equipement-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import MaleficesItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MaleficesEquipementSheet extends MaleficesItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["equipement"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["equipement-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/items/item-equipement-sheet.hbs" },
|
||||
}
|
||||
|
||||
tabGroups = { primary: "description" }
|
||||
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
description: { id: "description", group: "primary", label: "Description" },
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
27
modules/applications/sheets/malefices-npc-actor-sheet.mjs
Normal file
27
modules/applications/sheets/malefices-npc-actor-sheet.mjs
Normal file
@@ -0,0 +1,27 @@
|
||||
import MaleficesActorSheet from "./malefices-base-actor-sheet.mjs"
|
||||
|
||||
export default class MaleficesNPCActorSheet extends MaleficesActorSheet {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["pnj"],
|
||||
position: { width: 560, height: 460 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/actors/npc-sheet.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "main" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.document.system.description ?? "", { async: true }
|
||||
)
|
||||
return context
|
||||
}
|
||||
}
|
||||
48
modules/applications/sheets/malefices-personnage-sheet.mjs
Normal file
48
modules/applications/sheets/malefices-personnage-sheet.mjs
Normal file
@@ -0,0 +1,48 @@
|
||||
import MaleficesActorSheet from "./malefices-base-actor-sheet.mjs"
|
||||
|
||||
export default class MaleficesPersonnageSheet extends MaleficesActorSheet {
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["personnage"],
|
||||
position: { width: 640, height: 680 },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/actors/actor-sheet.hbs" },
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "main" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
context.armes = foundry.utils.duplicate(actor.getArmes())
|
||||
context.tarots = foundry.utils.duplicate(actor.getTarots())
|
||||
context.tarotsCache = foundry.utils.duplicate(actor.getHiddenTarots())
|
||||
context.archetype = foundry.utils.duplicate(actor.getArchetype())
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipements())
|
||||
context.elementsbio = actor.getElementsBio()
|
||||
context.sorts = actor.getSorts()
|
||||
context.phyMalus = actor.getPhysiqueMalus()
|
||||
context.subActors = foundry.utils.duplicate(actor.getSubActors())
|
||||
|
||||
// Expose nested biodata schema fields for {{formInput}} helper
|
||||
context.biodataFields = actor.system.schema.fields.biodata.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.enrichedEquipementlibre = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
actor.system.equipementlibre ?? "", { async: true }
|
||||
)
|
||||
return context
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/malefices-sortilege-sheet.mjs
Normal file
33
modules/applications/sheets/malefices-sortilege-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import MaleficesItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MaleficesSortilegeSheet extends MaleficesItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["sortilege"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["sortilege-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/items/item-sortilege-sheet.hbs" },
|
||||
}
|
||||
|
||||
tabGroups = { primary: "details" }
|
||||
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" },
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/malefices-tarot-sheet.mjs
Normal file
33
modules/applications/sheets/malefices-tarot-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import MaleficesItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MaleficesTarotSheet extends MaleficesItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["tarot"],
|
||||
position: { width: 660, height: 640 },
|
||||
window: { contentClasses: ["tarot-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-malefices/templates/items/item-tarot-sheet.hbs" },
|
||||
}
|
||||
|
||||
tabGroups = { primary: "details" }
|
||||
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" },
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,13 @@
|
||||
import { MaleficesUtility } from "./malefices-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class MaleficesActorSheet extends ActorSheet {
|
||||
export class MaleficesActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-malefices", "sheet", "actor"],
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-malefices", "sheet", "actor", "malefices-actor-sheet"],
|
||||
template: "systems/fvtt-malefices/templates/actors/actor-sheet.hbs",
|
||||
width: 640,
|
||||
height:680,
|
||||
@@ -33,17 +33,20 @@ export class MaleficesActorSheet extends ActorSheet {
|
||||
name: this.actor.name,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
system: duplicate(this.object.system),
|
||||
system: foundry.utils.duplicate(this.object.system),
|
||||
limited: this.object.limited,
|
||||
armes: duplicate(this.actor.getArmes()),
|
||||
tarots: duplicate(this.actor.getTarots()),
|
||||
tarotsCache: duplicate(this.actor.getHiddenTarots()),
|
||||
archetype: duplicate(this.actor.getArchetype()),
|
||||
equipements: duplicate(this.actor.getEquipements()),
|
||||
subActors: duplicate(this.actor.getSubActors()),
|
||||
armes: foundry.utils.duplicate(this.actor.getArmes()),
|
||||
tarots: foundry.utils.duplicate(this.actor.getTarots()),
|
||||
tarotsCache: foundry.utils.duplicate(this.actor.getHiddenTarots()),
|
||||
archetype: foundry.utils.duplicate(this.actor.getArchetype()),
|
||||
equipements: foundry.utils.duplicate(this.actor.getEquipements()),
|
||||
subActors: foundry.utils.duplicate(this.actor.getSubActors()),
|
||||
phyMalus: this.actor.getPhysiqueMalus(),
|
||||
elementsbio: this.actor.getElementsBio(),
|
||||
sorts: this.actor.getSorts(),
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.description, { async: true }),
|
||||
notes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.notes, { async: true }),
|
||||
equipementlibre: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.equipementlibre, { async: true }),
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
editScore: this.options.editScore,
|
||||
@@ -51,7 +54,7 @@ export class MaleficesActorSheet extends ActorSheet {
|
||||
}
|
||||
this.formData = formData;
|
||||
|
||||
console.log("PC : ", formData, this.object);
|
||||
console.log("PC : ", formData, this.object );
|
||||
return formData;
|
||||
}
|
||||
|
||||
@@ -63,10 +66,10 @@ export class MaleficesActorSheet extends ActorSheet {
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
|
||||
html.bind("keydown", function(e) { // Ignore Enter in actores sheet
|
||||
if (e.keyCode === 13) return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
@@ -84,14 +87,14 @@ export class MaleficesActorSheet extends ActorSheet {
|
||||
let dataType = $(ev.currentTarget).data("type")
|
||||
this.actor.createEmbeddedDocuments('Item', [{ name: "NewItem", type: dataType }], { renderSheet: true })
|
||||
})
|
||||
|
||||
|
||||
html.find('.subactor-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
let actorId = li.data("actor-id");
|
||||
let actor = game.actors.get( actorId );
|
||||
actor.sheet.render(true);
|
||||
});
|
||||
|
||||
|
||||
html.find('.subactor-delete').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
let actorId = li.data("actor-id");
|
||||
@@ -114,38 +117,38 @@ export class MaleficesActorSheet extends ActorSheet {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
this.actor.incDecAmmo( li.data("item-id"), +1 )
|
||||
} );
|
||||
|
||||
|
||||
html.find('.roll-attribut').click((event) => {
|
||||
let attrKey = $(event.currentTarget).data("attr-key")
|
||||
this.actor.rollAttribut(attrKey)
|
||||
});
|
||||
});
|
||||
html.find('.roll-arme').click((event) => {
|
||||
const armeId = $(event.currentTarget).data("arme-id")
|
||||
this.actor.rollArme(armeId)
|
||||
});
|
||||
|
||||
|
||||
html.find('.lock-unlock-sheet').click((event) => {
|
||||
this.options.editScore = !this.options.editScore;
|
||||
this.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-link a').click((event) => {
|
||||
const itemId = $(event.currentTarget).data("item-id");
|
||||
const item = this.actor.getOwnedItem(itemId);
|
||||
item.sheet.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-equip').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.equipItem( li.data("item-id") );
|
||||
this.render(true);
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
html.find('.update-field').change(ev => {
|
||||
const fieldName = $(ev.currentTarget).data("field-name");
|
||||
let value = Number(ev.currentTarget.value);
|
||||
this.actor.update( { [`${fieldName}`]: value } );
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
|
||||
@@ -15,8 +15,8 @@ export class MaleficesActor extends Actor {
|
||||
/**
|
||||
* Override the create() function to provide additional SoS functionality.
|
||||
*
|
||||
* This overrided create() function adds initial items
|
||||
* Namely: Basic skills, money,
|
||||
* This overrided create() function adds initial items
|
||||
* Namely: Basic skills, money,
|
||||
*
|
||||
* @param {Object} data Barebones actor data which this function adds onto.
|
||||
* @param {Object} options (Unused) Additional options which customize the creation workflow.
|
||||
@@ -29,7 +29,7 @@ export class MaleficesActor extends Actor {
|
||||
if (data instanceof Array) {
|
||||
return super.create(data, options);
|
||||
}
|
||||
// If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic
|
||||
// If the created actor has items (only applicable to foundry.utils.duplicated actors) bypass the new actor creation logic
|
||||
if (data.items) {
|
||||
let actor = super.create(data, options);
|
||||
return actor;
|
||||
@@ -43,10 +43,6 @@ export class MaleficesActor extends Actor {
|
||||
return super.create(data, options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareBaseData() {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async prepareData() {
|
||||
|
||||
@@ -92,7 +88,7 @@ export class MaleficesActor extends Actor {
|
||||
return comp;
|
||||
}
|
||||
getArchetype() {
|
||||
let comp = duplicate(this.items.find(item => item.type == 'archetype') || {name: "Pas d'archetype"})
|
||||
let comp = foundry.utils.duplicate(this.items.find(item => item.type == 'archetype') || { name: "Pas d'archetype" })
|
||||
if (comp && comp.system) {
|
||||
comp.tarot = MaleficesUtility.getTarot(comp.system.lametutelaire)
|
||||
}
|
||||
@@ -101,25 +97,25 @@ export class MaleficesActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getElementsBio() {
|
||||
let comp = duplicate(this.items.filter(item => item.type == 'elementbio') || [])
|
||||
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'elementbio') || [])
|
||||
MaleficesUtility.sortArrayObjectsByName(comp)
|
||||
return comp;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getTarots() {
|
||||
let comp = duplicate(this.items.filter(item => item.type == 'tarot' && !item.system.isgm) || [])
|
||||
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'tarot' && !item.system.isgm) || [])
|
||||
MaleficesUtility.sortArrayObjectsByName(comp)
|
||||
return comp;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getHiddenTarots() {
|
||||
let comp = duplicate(this.items.filter(item => item.type == 'tarot' && item.system.isgm) || [])
|
||||
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'tarot' && item.system.isgm) || [])
|
||||
MaleficesUtility.sortArrayObjectsByName(comp)
|
||||
return comp;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getArmes() {
|
||||
let comp = duplicate(this.items.filter(item => item.type == 'arme') || [])
|
||||
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'arme') || [])
|
||||
MaleficesUtility.sortArrayObjectsByName(comp)
|
||||
return comp;
|
||||
}
|
||||
@@ -127,7 +123,7 @@ export class MaleficesActor extends Actor {
|
||||
getItemById(id) {
|
||||
let item = this.items.find(item => item.id == id);
|
||||
if (item) {
|
||||
item = duplicate(item)
|
||||
item = foundry.utils.duplicate(item)
|
||||
}
|
||||
return item;
|
||||
}
|
||||
@@ -173,7 +169,7 @@ export class MaleficesActor extends Actor {
|
||||
|
||||
/* ------------------------------------------- */
|
||||
async buildContainerTree() {
|
||||
let equipments = duplicate(this.items.filter(item => item.type == "equipment") || [])
|
||||
let equipments = foundry.utils.duplicate(this.items.filter(item => item.type == "equipment") || [])
|
||||
for (let equip1 of equipments) {
|
||||
if (equip1.system.iscontainer) {
|
||||
equip1.system.contents = []
|
||||
@@ -224,27 +220,27 @@ export class MaleficesActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
clearInitiative(){
|
||||
clearInitiative() {
|
||||
this.getFlag("world", "initiative", -1)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getInitiativeScore(combatId, combatantId) {
|
||||
let init = Math.floor(this.system.attributs.physique.value+this.system.attributs.habilete.value)
|
||||
let subvalue = new Roll("1d20").roll({async: false})
|
||||
return init + (subvalue / 100)
|
||||
let init = Math.floor((this.system.attributs.physique.value + this.system.attributs.habilite.value) / 2)
|
||||
let subvalue = new Roll("1d20").roll({ async: false })
|
||||
return init + (subvalue.total / 100)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getSubActors() {
|
||||
let subActors = [];
|
||||
for (let id of this.system.subactors) {
|
||||
subActors.push(duplicate(game.actors.get(id)))
|
||||
subActors.push(foundry.utils.duplicate(game.actors.get(id)))
|
||||
}
|
||||
return subActors;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async addSubActor(subActorId) {
|
||||
let subActors = duplicate(this.system.subactors);
|
||||
let subActors = foundry.utils.duplicate(this.system.subactors);
|
||||
subActors.push(subActorId);
|
||||
await this.update({ 'system.subactors': subActors });
|
||||
}
|
||||
@@ -275,25 +271,25 @@ export class MaleficesActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
incDecFluide(value) {
|
||||
let fluide = this.system.fluide + value
|
||||
this.update( {'system.fluide': fluide} )
|
||||
this.update({ 'system.fluide': fluide })
|
||||
}
|
||||
incDecDestin(value) {
|
||||
let destin = this.system.pointdestin + value
|
||||
this.update( {'system.pointdestin': destin} )
|
||||
this.update({ 'system.pointdestin': destin })
|
||||
}
|
||||
incDecMPMB(value) {
|
||||
let mpmb = this.system.mpmb + value
|
||||
this.update( {'system.mpmb': mpmb} )
|
||||
this.update({ 'system.mpmb': mpmb })
|
||||
}
|
||||
incDecMPMN(value) {
|
||||
let mpmn = this.system.mpmn + value
|
||||
this.update( {'system.mpmn': mpmn} )
|
||||
this.update({ 'system.mpmn': mpmn })
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
incDecAttr(attrKey, value) {
|
||||
let attr = duplicate(this.system.attributs[attrKey])
|
||||
let attr = foundry.utils.duplicate(this.system.attributs[attrKey])
|
||||
attr.value += value
|
||||
this.update( { [`system.attributs.${attrKey}`]: attr})
|
||||
this.update({ [`system.attributs.${attrKey}`]: attr })
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async incDecQuantity(objetId, incDec = 0) {
|
||||
@@ -317,16 +313,16 @@ export class MaleficesActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getAtttributImage( attrKey) {
|
||||
getAtttributImage(attrKey) {
|
||||
return `systems/fvtt-malefices/images/icons/${attrKey}.webp`
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
incDecDestin( value) {
|
||||
let newValue = Math.max( this.system.pointdestin + value, 0)
|
||||
this.update( {'system.pointdestin': newValue})
|
||||
incDecDestin(value) {
|
||||
let newValue = Math.max(this.system.pointdestin + value, 0)
|
||||
this.update({ 'system.pointdestin': newValue })
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCommonRollData() {
|
||||
|
||||
@@ -341,6 +337,7 @@ export class MaleficesActor extends Actor {
|
||||
rollData.isReroll = false
|
||||
rollData.confrontationDegre = 0
|
||||
rollData.confrontationModif = 0
|
||||
rollData.config = game.system.malefices.config
|
||||
|
||||
console.log("ROLLDATA", rollData)
|
||||
|
||||
@@ -348,7 +345,7 @@ export class MaleficesActor extends Actor {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getPhysiqueMalus() {
|
||||
if ( this.system.attributs.constitution.value <= 8) {
|
||||
if (this.system.attributs.constitution.value <= 8) {
|
||||
return -(9 - this.system.attributs.constitution.value)
|
||||
}
|
||||
return 0
|
||||
@@ -358,9 +355,9 @@ export class MaleficesActor extends Actor {
|
||||
rollAttribut(attrKey) {
|
||||
let attr = this.system.attributs[attrKey]
|
||||
let rollData = this.getCommonRollData()
|
||||
rollData.attr = duplicate(attr)
|
||||
rollData.attr = foundry.utils.duplicate(attr)
|
||||
rollData.mode = "attribut"
|
||||
rollData.title = attr.label
|
||||
rollData.title = attr.label
|
||||
rollData.img = this.getAtttributImage(attrKey)
|
||||
this.startRoll(rollData)
|
||||
}
|
||||
@@ -369,12 +366,12 @@ export class MaleficesActor extends Actor {
|
||||
rollArme(weaponId) {
|
||||
let arme = this.items.get(weaponId)
|
||||
if (arme) {
|
||||
arme = duplicate(arme)
|
||||
arme = foundry.utils.duplicate(arme)
|
||||
let rollData = this.getCommonRollData()
|
||||
if (arme.system.armetype == "mainsnues" || arme.system.armetype == "epee") {
|
||||
rollData.attr = { label: "(Physique+Habilité)/2", value: Math.floor( (this.getPhysiqueMalus()+this.system.attributs.physique+this.system.attributs.habilite) / 2) }
|
||||
rollData.attr = { label: "(Physique+Habilité)/2", value: Math.floor((this.getPhysiqueMalus() + this.system.attributs.physique.value + this.system.attributs.habilite.value) / 2) }
|
||||
} else {
|
||||
rollData.attr = duplicate(this.system.attributs.habilite)
|
||||
rollData.attr = foundry.utils.duplicate(this.system.attributs.habilite)
|
||||
}
|
||||
rollData.mode = "arme"
|
||||
rollData.arme = arme
|
||||
@@ -385,11 +382,10 @@ export class MaleficesActor extends Actor {
|
||||
ui.notifications.warn("Impossible de trouver l'arme concernée ")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async startRoll(rollData) {
|
||||
let rollDialog = await MaleficesRollDialog.create(this, rollData)
|
||||
rollDialog.render(true)
|
||||
await MaleficesRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ export class MaleficesCommands {
|
||||
if (!game.system.malefices.commands) {
|
||||
const commands = new MaleficesCommands();
|
||||
commands.registerCommand({ path: ["/tirage"], func: (content, msg, params) => MaleficesCommands.createTirage(msg), descr: "Tirage des tarots" });
|
||||
commands.registerCommand({ path: ["/carte"], func: (content, msg, params) => MaleficesCommands.tirerCarte(msg), descr: "Tirer une carte" });
|
||||
commands.registerCommand({ path: ["/resume"], func: (content, msg, params) => MaleficesCharacterSummary.displayPCSummary(), descr: "Affiche la liste des PJs!" });
|
||||
game.system.malefices.commands = commands;
|
||||
}
|
||||
@@ -79,7 +80,7 @@ export class MaleficesCommands {
|
||||
console.log("===> Processing command")
|
||||
let command = commandsTable[name];
|
||||
path = path + name + " ";
|
||||
if (command && command.subTable) {
|
||||
if (command?.subTable) {
|
||||
if (params[0]) {
|
||||
return this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path)
|
||||
}
|
||||
@@ -88,7 +89,7 @@ export class MaleficesCommands {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (command && command.func) {
|
||||
if (command?.func) {
|
||||
const result = command.func(content, msg, params);
|
||||
if (result == false) {
|
||||
CrucibleCommands._chatAnswer(msg, command.descr);
|
||||
@@ -105,7 +106,7 @@ export class MaleficesCommands {
|
||||
ChatMessage.create(msg);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* --------------------------------------------- */
|
||||
static async createTirage(msg) {
|
||||
if (game.user.isGM) {
|
||||
let tirageData = {
|
||||
@@ -114,7 +115,7 @@ export class MaleficesCommands {
|
||||
maxPlayerCard: 4,
|
||||
maxSecretCard: 1,
|
||||
cards: [],
|
||||
players: duplicate(game.users),
|
||||
players: foundry.utils.duplicate(game.users),
|
||||
secretCards: [],
|
||||
deck: MaleficesUtility.getTarots()
|
||||
}
|
||||
@@ -124,8 +125,22 @@ export class MaleficesCommands {
|
||||
tirageData.secretCards.push({ name: "???", img: "systems/fvtt-malefices/images/tarots/background.webp" })
|
||||
|
||||
let tirageDialog = await MaleficesTirageTarotDialog.create(this, tirageData)
|
||||
tirageDialog.render(true)
|
||||
}
|
||||
}
|
||||
/* --------------------------------------------- */
|
||||
static async tirerCarte(msg) {
|
||||
let deck = MaleficesUtility.getTarots()
|
||||
let index = Math.round(Math.random() * (deck.length-1))
|
||||
let selectedCard = deck[index]
|
||||
selectedCard.system.ispositif = true
|
||||
if ( selectedCard.system.isdualside) { // Cas des cartes pouvant avoir 2 sens
|
||||
selectedCard.system.ispositif = (Math.random() > 0.5)
|
||||
}
|
||||
selectedCard.system.isgm = false
|
||||
selectedCard.value = (selectedCard.system.ispositif)? selectedCard.system.numericvalueup : selectedCard.system.numericvaluedown
|
||||
MaleficesUtility.createChatMessage(game.user.name, "", {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-malefices/templates/chat/display-tarot-card.hbs`, selectedCard)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,4 +27,41 @@ export const MALEFICES_CONFIG = {
|
||||
"epee": "Epée, sabre, javelot, etc",
|
||||
"mainsnues": "Mains Nues"
|
||||
},
|
||||
|
||||
confrontationDegreOptions :{
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "5"
|
||||
},
|
||||
|
||||
confrontationModifOptions: {
|
||||
"-1": "-1",
|
||||
"0": "0",
|
||||
"1": "+1"
|
||||
},
|
||||
|
||||
bonusMalusPersoOptions: [
|
||||
{value: "-3", label: "-3"},
|
||||
{value: "-2", label: "-2"},
|
||||
{value: "-1", label: "-1"},
|
||||
{value: "0", label: "0"},
|
||||
{value: "+1", label: "+1"},
|
||||
{value: "+2", label: "+2"},
|
||||
{value: "+3", label: "+3"}
|
||||
],
|
||||
bonusMalusDefOptions: [
|
||||
{value: "-6", label: "-6 (réussite critique)"},
|
||||
{value: "-3", label: "-3 (réussite)"},
|
||||
{value: "0", label: "0 (echec ou pas d'esquive)"},
|
||||
{value: "+3", label: "+3 (echec critique)"}
|
||||
],
|
||||
bonusMalusPorteeOptions: [
|
||||
{value: "1", label: "+1 (Portée courte)"},
|
||||
{value: "0", label: "0 (Portée moyenne)"},
|
||||
{value: "-1", label: "-1 (Portée longue)"}
|
||||
]
|
||||
|
||||
}
|
||||
@@ -4,12 +4,12 @@ import { MaleficesUtility } from "./malefices-utility.js";
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class MaleficesItemSheet extends ItemSheet {
|
||||
export class MaleficesItemSheet extends foundry.appv1.sheets.ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-malefices", "sheet", "item"],
|
||||
template: "systems/fvtt-malefices/templates/item-sheet.hbs",
|
||||
dragDrop: [{ dragSelector: null, dropSelector: null }],
|
||||
@@ -19,20 +19,6 @@ export class MaleficesItemSheet extends ItemSheet {
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_getHeaderButtons() {
|
||||
let buttons = super._getHeaderButtons();
|
||||
// Add "Post to chat" button
|
||||
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
|
||||
buttons.unshift(
|
||||
{
|
||||
class: "post",
|
||||
icon: "fas fa-comment",
|
||||
onclick: ev => { }
|
||||
})
|
||||
return buttons
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
@@ -57,20 +43,20 @@ export class MaleficesItemSheet extends ItemSheet {
|
||||
name: this.object.name,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
system: duplicate(this.object.system),
|
||||
config: duplicate(game.system.malefices.config),
|
||||
system: foundry.utils.duplicate(this.object.system),
|
||||
config: foundry.utils.duplicate(game.system.malefices.config),
|
||||
limited: this.object.limited,
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
description: await TextEditor.enrichHTML(this.object.system.description, { async: true }),
|
||||
notes: await TextEditor.enrichHTML(this.object.system.notes, { 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 }),
|
||||
isGM: game.user.isGM
|
||||
}
|
||||
|
||||
if ( this.object.type == "archetype") {
|
||||
formData.tarots = MaleficesUtility.getTarots()
|
||||
}
|
||||
|
||||
|
||||
this.options.editable = !(this.object.origin == "embeddedItem");
|
||||
console.log("ITEM DATA", formData, this);
|
||||
return formData;
|
||||
@@ -90,24 +76,18 @@ export class MaleficesItemSheet extends ItemSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
postItem() {
|
||||
let chatData = duplicate(this.item)
|
||||
let chatData = foundry.utils.duplicate(this.item)
|
||||
if (this.actor) {
|
||||
chatData.actor = { id: this.actor.id };
|
||||
}
|
||||
// Don't post any image for the item (which would leave a large gap) if the default image is used
|
||||
if (chatData.img.includes("/blank.png")) {
|
||||
if (chatData.img?.includes("/blank.png")) {
|
||||
chatData.img = null;
|
||||
}
|
||||
// JSON object for easy creation
|
||||
chatData.jsondata = JSON.stringify(
|
||||
{
|
||||
compendium: "postedItem",
|
||||
payload: chatData,
|
||||
});
|
||||
chatData.config = game.system.malefices.config
|
||||
chatData.jsondata = JSON.stringify({ compendium: "postedItem", payload: chatData })
|
||||
|
||||
renderTemplate('systems/Malefices/templates/post-item.html', chatData).then(html => {
|
||||
let chatOptions = MaleficesUtility.chatDataSetup(html);
|
||||
ChatMessage.create(chatOptions)
|
||||
foundry.applications.handlebars.renderTemplate('systems/fvtt-malefices/templates/post-item.hbs', chatData).then(html => {
|
||||
ChatMessage.create(MaleficesUtility.chatDataSetup(html))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -116,7 +96,7 @@ export class MaleficesItemSheet extends ItemSheet {
|
||||
let levelIndex = Number($(ev.currentTarget).parents(".item").data("level-index"))
|
||||
let choiceIndex = Number($(ev.currentTarget).parents(".item").data("choice-index"))
|
||||
let featureId = $(ev.currentTarget).parents(".item").data("feature-id")
|
||||
|
||||
|
||||
let itemData = this.object.system.levels[levelIndex].choices[choiceIndex].features[featureId]
|
||||
|
||||
if (itemData.name != 'None') {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { MaleficesUtility } from "./malefices-utility.js";
|
||||
|
||||
export const defaultItemImg = {
|
||||
arme: "systems/fvtt-malefices/images/icons/arme.webp",
|
||||
arme: "systems/fvtt-malefices/images/icons/epee.webp",
|
||||
equipement: "systems/fvtt-malefices/images/icons/equipement.webp",
|
||||
elementbio: "systems/fvtt-malefices/images/icons/wisdom.webp",
|
||||
archetype: "systems/fvtt-malefices/images/icons/archetype.webp",
|
||||
|
||||
@@ -9,15 +9,19 @@
|
||||
/* -------------------------------------------- */
|
||||
// Import Modules
|
||||
import { MaleficesActor } from "./malefices-actor.js";
|
||||
import { MaleficesItemSheet } from "./malefices-item-sheet.js";
|
||||
import { MaleficesActorSheet } from "./malefices-actor-sheet.js";
|
||||
import { MaleficesNPCSheet } from "./malefices-npc-sheet.js";
|
||||
import { MaleficesUtility } from "./malefices-utility.js";
|
||||
import { MaleficesCombat } from "./malefices-combat.js";
|
||||
import { MaleficesItem } from "./malefices-item.js";
|
||||
import { MaleficesHotbar } from "./malefices-hotbar.js"
|
||||
import { MaleficesCharacterSummary } from "./malefices-summary-app.js"
|
||||
import { MALEFICES_CONFIG } from "./malefices-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 */
|
||||
@@ -27,7 +31,7 @@ import { MALEFICES_CONFIG } from "./malefices-config.js"
|
||||
Hooks.once("init", async function () {
|
||||
|
||||
console.log(`Initializing Malefices RPG`);
|
||||
|
||||
|
||||
game.system.malefices = {
|
||||
config: MALEFICES_CONFIG,
|
||||
MaleficesHotbar
|
||||
@@ -38,7 +42,7 @@ Hooks.once("init", async function () {
|
||||
MaleficesUtility.preloadHandlebarsTemplates();
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Set an initiative formula for the system
|
||||
// Set an initiative formula for the system
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "1d6",
|
||||
decimals: 1
|
||||
@@ -53,56 +57,51 @@ Hooks.once("init", async function () {
|
||||
// Define custom Entity classes
|
||||
CONFIG.Combat.documentClass = MaleficesCombat
|
||||
CONFIG.Actor.documentClass = MaleficesActor
|
||||
CONFIG.Actor.dataModels = {
|
||||
personnage: models.PersonnageDataModel,
|
||||
pnj: models.PnjDataModel
|
||||
}
|
||||
|
||||
CONFIG.Item.documentClass = MaleficesItem
|
||||
CONFIG.Item.dataModels = {
|
||||
arme: models.ArmeDataModel,
|
||||
equipement: models.EquipementDataModel,
|
||||
archetype: models.ArchetypeDataModel,
|
||||
tarot: models.TarotDataModel,
|
||||
sortilege: models.SortilegeDataModel,
|
||||
elementbio: models.ElementbioDataModel
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("fvtt-malefices", MaleficesActorSheet, { types: ["personnage"], makeDefault: true });
|
||||
Actors.registerSheet("fvtt-malefices", MaleficesNPCSheet, { types: ["pnj"], makeDefault: false });
|
||||
// Register AppV2 Actor Sheets
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-malefices", sheets.MaleficesPersonnageSheet, { types: ["personnage"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-malefices", sheets.MaleficesNPCActorSheet, { types: ["pnj"], makeDefault: true });
|
||||
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("fvtt-malefices", MaleficesItemSheet, { makeDefault: true });
|
||||
// Register AppV2 Item Sheets
|
||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-malefices", sheets.MaleficesArmeSheet, { types: ["arme"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-malefices", sheets.MaleficesEquipementSheet, { types: ["equipement"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-malefices", sheets.MaleficesArchetypeSheet, { types: ["archetype"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-malefices", sheets.MaleficesTarotSheet, { types: ["tarot"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-malefices", sheets.MaleficesSortilegeSheet, { types: ["sortilege"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-malefices", sheets.MaleficesElementbioSheet, { types: ["elementbio"], makeDefault: true });
|
||||
|
||||
MaleficesUtility.init()
|
||||
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
function welcomeMessage() {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: [game.user.id],
|
||||
content: `<div id="welcome-message-malefices"><span class="rdd-roll-part">
|
||||
<strong>Bienvenu dans Malefices, le JDR qui sent le souffre !</strong>
|
||||
<p>Le Livre de Base de Maléfices v4 est nécessaire pour jouer : https://arkhane-asylum.fr/en/malefices/</p>
|
||||
<p>Maléfices et un jeu de rôle publié par Arkhane Asylum Publishing, tout les droits leur appartiennent.</p>
|
||||
<p>Système développé par LeRatierBretonnien avec l'aide de la Dame du Lac et Malik, support sur le <a href="https://discord.gg/pPSDNJk">Discord FR de Foundry</a>.</p>
|
||||
` });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// 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
|
||||
async function welcomeMessage() {
|
||||
if (game.user.isGM) {
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/fvtt-malefices/templates/chat/welcome-message.hbs', {}
|
||||
)
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: [game.user.id],
|
||||
content
|
||||
});
|
||||
|
||||
let worldKey = game.settings.get(registerKey, "world-key")
|
||||
if ( worldKey == undefined || worldKey == "" ) {
|
||||
worldKey = randomID(32)
|
||||
game.settings.set(registerKey, "world-key", worldKey )
|
||||
}
|
||||
// Simple API counter
|
||||
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}"`
|
||||
//$.ajaxSetup({
|
||||
//headers: { 'Access-Control-Allow-Origin': '*' }
|
||||
//})
|
||||
$.ajax(regURL)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,18 +118,11 @@ Hooks.once("ready", function () {
|
||||
user: game.user._id
|
||||
});
|
||||
}
|
||||
|
||||
// CSS patch for v9
|
||||
if (game.version) {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
sidebar.style.width = "min-content";
|
||||
}
|
||||
|
||||
registerUsageCount('fvtt-malefices')
|
||||
ClassCounter.registerUsageCount();
|
||||
welcomeMessage();
|
||||
MaleficesUtility.ready()
|
||||
MaleficesUtility.init()
|
||||
MaleficesCharacterSummary.ready()
|
||||
MaleficesCharacterSummary.ready()
|
||||
|
||||
})
|
||||
|
||||
@@ -148,4 +140,3 @@ Hooks.on("chatMessage", (html, content, msg) => {
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
import { MaleficesUtility } from "./malefices-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class MaleficesNPCSheet extends ActorSheet {
|
||||
export class MaleficesNPCSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["Malefices", "sheet", "actor"],
|
||||
template: "systems/fvtt-malefices/templates/npc-sheet.html",
|
||||
width: 640,
|
||||
@@ -25,7 +25,7 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = this.object.system
|
||||
let actorData = duplicate(objectData)
|
||||
let actorData = foundry.utils.duplicate(objectData)
|
||||
|
||||
let formData = {
|
||||
title: this.title,
|
||||
@@ -38,16 +38,16 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
data: actorData,
|
||||
limited: this.object.limited,
|
||||
skills: this.actor.getSkills( ),
|
||||
weapons: this.actor.checkAndPrepareEquipments( duplicate(this.actor.getWeapons()) ),
|
||||
armors: this.actor.checkAndPrepareEquipments( duplicate(this.actor.getArmors())),
|
||||
shields: this.actor.checkAndPrepareEquipments( duplicate(this.actor.getShields())),
|
||||
spells: this.actor.checkAndPrepareEquipments( duplicate(this.actor.getLore())),
|
||||
equipments: this.actor.checkAndPrepareEquipments(duplicate(this.actor.getEquipmentsOnly()) ),
|
||||
equippedWeapons: this.actor.checkAndPrepareEquipments(duplicate(this.actor.getEquippedWeapons()) ),
|
||||
weapons: this.actor.checkAndPrepareEquipments( foundry.utils.duplicate(this.actor.getWeapons()) ),
|
||||
armors: this.actor.checkAndPrepareEquipments( foundry.utils.duplicate(this.actor.getArmors())),
|
||||
shields: this.actor.checkAndPrepareEquipments( foundry.utils.duplicate(this.actor.getShields())),
|
||||
spells: this.actor.checkAndPrepareEquipments( foundry.utils.duplicate(this.actor.getLore())),
|
||||
equipments: this.actor.checkAndPrepareEquipments(foundry.utils.duplicate(this.actor.getEquipmentsOnly()) ),
|
||||
equippedWeapons: this.actor.checkAndPrepareEquipments(foundry.utils.duplicate(this.actor.getEquippedWeapons()) ),
|
||||
equippedArmor: this.actor.getEquippedArmor(),
|
||||
equippedShield: this.actor.getEquippedShield(),
|
||||
subActors: duplicate(this.actor.getSubActors()),
|
||||
moneys: duplicate(this.actor.getMoneys()),
|
||||
subActors: foundry.utils.duplicate(this.actor.getSubActors()),
|
||||
moneys: foundry.utils.duplicate(this.actor.getMoneys()),
|
||||
encCapacity: this.actor.getEncumbranceCapacity(),
|
||||
saveRolls: this.actor.getSaveRoll(),
|
||||
conditions: this.actor.getConditions(),
|
||||
@@ -71,10 +71,10 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
|
||||
html.bind("keydown", function(e) { // Ignore Enter in actores sheet
|
||||
if (e.keyCode === 13) return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
@@ -92,17 +92,17 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
let dataType = $(ev.currentTarget).data("type")
|
||||
this.actor.createEmbeddedDocuments('Item', [{ name: "NewItem", type: dataType }], { renderSheet: true })
|
||||
})
|
||||
|
||||
|
||||
html.find('.equip-activate').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item")
|
||||
let itemId = li.data("item-id")
|
||||
this.actor.equipActivate( itemId)
|
||||
});
|
||||
});
|
||||
html.find('.equip-deactivate').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item")
|
||||
let itemId = li.data("item-id")
|
||||
this.actor.equipDeactivate( itemId)
|
||||
});
|
||||
});
|
||||
|
||||
html.find('.subactor-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
@@ -110,7 +110,7 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
let actor = game.actors.get( actorId );
|
||||
actor.sheet.render(true);
|
||||
});
|
||||
|
||||
|
||||
html.find('.subactor-delete').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
let actorId = li.data("actor-id");
|
||||
@@ -133,7 +133,7 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
this.actor.incDecAmmo( li.data("item-id"), +1 )
|
||||
} );
|
||||
|
||||
|
||||
html.find('.roll-ability').click((event) => {
|
||||
const abilityKey = $(event.currentTarget).data("ability-key");
|
||||
this.actor.rollAbility(abilityKey);
|
||||
@@ -142,7 +142,7 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
const skillId = li.data("item-id")
|
||||
this.actor.rollSkill(skillId)
|
||||
});
|
||||
});
|
||||
|
||||
html.find('.roll-weapon').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
@@ -163,28 +163,28 @@ export class MaleficesNPCSheet extends ActorSheet {
|
||||
const saveKey = $(event.currentTarget).data("save-key")
|
||||
this.actor.rollSave(saveKey)
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
html.find('.lock-unlock-sheet').click((event) => {
|
||||
this.options.editScore = !this.options.editScore;
|
||||
this.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-link a').click((event) => {
|
||||
const itemId = $(event.currentTarget).data("item-id");
|
||||
const item = this.actor.getOwnedItem(itemId);
|
||||
item.sheet.render(true);
|
||||
});
|
||||
});
|
||||
html.find('.item-equip').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.equipItem( li.data("item-id") );
|
||||
this.render(true);
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
html.find('.update-field').change(ev => {
|
||||
const fieldName = $(ev.currentTarget).data("field-name");
|
||||
let value = Number(ev.currentTarget.value);
|
||||
this.actor.update( { [`${fieldName}`]: value } );
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +1,57 @@
|
||||
import { MaleficesUtility } from "./malefices-utility.js";
|
||||
|
||||
export class MaleficesRollDialog extends Dialog {
|
||||
export class MaleficesRollDialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
const isCard = rollData?.attr?.iscard
|
||||
const template = isCard
|
||||
? 'systems/fvtt-malefices/templates/dialogs/confrontation-dialog.hbs'
|
||||
: 'systems/fvtt-malefices/templates/dialogs/roll-dialog-generic.hbs'
|
||||
|
||||
let options = { classes: ["MaleficesDialog"], width: 540, height: 'fit-content', 'z-index': 99999 }
|
||||
let html
|
||||
if (rollData.attr && rollData.attr.iscard) {
|
||||
html = await renderTemplate('systems/fvtt-malefices/templates/dialogs/confrontation-dialog.hbs', rollData);
|
||||
} else {
|
||||
html = await renderTemplate('systems/fvtt-malefices/templates/dialogs/roll-dialog-generic.hbs', rollData);
|
||||
}
|
||||
const content = await foundry.applications.handlebars.renderTemplate(template, rollData)
|
||||
|
||||
return new MaleficesRollDialog(actor, rollData, html, options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let isCard = rollData.attr && rollData.attr.iscard
|
||||
let conf = {
|
||||
title: (isCard) ? "Jet" : "Tirage",
|
||||
content: html,
|
||||
buttons: {
|
||||
roll: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: (isCard) ? "Tirer une carte" : "Lancer le dé",
|
||||
callback: () => { this.roll() }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Annuler",
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: {
|
||||
title: isCard ? "Tirage" : "Jet de dé",
|
||||
icon: isCard ? "fa-solid fa-layer-group" : "fa-solid fa-dice-d20",
|
||||
},
|
||||
close: close
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
classes: ["malefices-roll-dialog"],
|
||||
position: { width: 540 },
|
||||
modal: false,
|
||||
rejectClose: false,
|
||||
content,
|
||||
buttons: [
|
||||
{
|
||||
action: "roll",
|
||||
label: isCard ? "Tirer une carte" : "Lancer le dé",
|
||||
icon: isCard ? "fa-solid fa-layer-group" : "fa-solid fa-check",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
MaleficesRollDialog._updateRollDataFromForm(rollData, button.form.elements)
|
||||
if (isCard) {
|
||||
MaleficesUtility.tirageConfrontationMalefices(rollData)
|
||||
} else {
|
||||
MaleficesUtility.rollMalefices(rollData)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "cancel",
|
||||
label: "Annuler",
|
||||
icon: "fa-solid fa-times",
|
||||
}
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
roll() {
|
||||
let isCard = this.rollData.attr && this.rollData.attr.iscard
|
||||
if (isCard) {
|
||||
MaleficesUtility.tirageConfrontationMalefices(this.rollData)
|
||||
} else {
|
||||
MaleficesUtility.rollMalefices(this.rollData)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async refreshDialog() {
|
||||
const content = await renderTemplate("systems/fvtt-malefices/templates/dialogs/roll-dialog-generic.hbs", this.rollData)
|
||||
this.data.content = content
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
var dialog = this;
|
||||
function onLoad() {
|
||||
}
|
||||
$(function () { onLoad(); });
|
||||
|
||||
html.find('#bonusMalusSituation').change((event) => {
|
||||
this.rollData.bonusMalusSituation = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#bonusMalusPerso').change((event) => {
|
||||
this.rollData.bonusMalusPerso = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#bonusMalusDef').change((event) => {
|
||||
this.rollData.bonusMalusDef = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#bonusMalusPortee').change((event) => {
|
||||
this.rollData.bonusMalusPortee = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#confrontationDegre').change((event) => {
|
||||
this.rollData.confrontationDegre = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#confrontationModif').change((event) => {
|
||||
this.rollData.confrontationModif = Number(event.currentTarget.value)
|
||||
})
|
||||
|
||||
static _updateRollDataFromForm(rollData, elements) {
|
||||
if (elements.bonusMalusPerso) rollData.bonusMalusPerso = Number(elements.bonusMalusPerso.value)
|
||||
if (elements.bonusMalusSituation) rollData.bonusMalusSituation = Number(elements.bonusMalusSituation.value)
|
||||
if (elements.bonusMalusDef) rollData.bonusMalusDef = Number(elements.bonusMalusDef.value)
|
||||
if (elements.bonusMalusPortee) rollData.bonusMalusPortee = Number(elements.bonusMalusPortee.value)
|
||||
if (elements.confrontationDegre) rollData.confrontationDegre = Number(elements.confrontationDegre.value)
|
||||
if (elements.confrontationModif) rollData.confrontationModif = Number(elements.confrontationModif.value)
|
||||
}
|
||||
}
|
||||
@@ -1,129 +1,133 @@
|
||||
/* -------------------------------------------- */
|
||||
import { MaleficesUtility } from "./malefices-utility.js";
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class MaleficesCharacterSummary extends Application {
|
||||
export class MaleficesCharacterSummary extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static displayPCSummary(){
|
||||
game.system.malefices.charSummary.render(true)
|
||||
static DEFAULT_OPTIONS = {
|
||||
id: "malefices-character-summary",
|
||||
classes: ["MaleficesDialog"],
|
||||
window: { title: "Résumé des Personnages", resizable: true },
|
||||
position: { width: 960, height: "auto" },
|
||||
dragDrop: [{ dragSelector: null, dropSelector: ".character-summary-container" }],
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
form: { template: "systems/fvtt-malefices/templates/dialogs/character-summary.hbs" }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updatePCSummary(){
|
||||
if ( this.rendered) {
|
||||
this.render(true)
|
||||
static displayPCSummary() {
|
||||
if (game.user.isGM) {
|
||||
game.system.malefices.charSummary.render({ force: true })
|
||||
} else {
|
||||
ui.notifications.info("Commande /resume réservée au MJ !")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static createSummaryPos() {
|
||||
return { top: 200, left: 200 };
|
||||
updatePCSummary() {
|
||||
if (this.element?.isConnected) {
|
||||
this.render({ force: true })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static ready() {
|
||||
if ( !game.user.isGM ) { // Uniquement si GM
|
||||
if (!game.user.isGM) {
|
||||
return
|
||||
}
|
||||
let charSummary = new MaleficesCharacterSummary()
|
||||
game.system.malefices.charSummary = charSummary
|
||||
game.system.malefices.charSummary = new MaleficesCharacterSummary()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor() {
|
||||
super();
|
||||
//game.settings.set("world", "character-summary-data", {npcList: [], x:0, y:0})
|
||||
this.settings = game.settings.get("world", "character-summary-data")
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
const saved = game.settings.get("world", "character-summary-data")
|
||||
this.extraList = saved.extraList ?? saved.npcList ?? []
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
template: "systems/fvtt-malefices/templates/dialogs/character-summary.hbs",
|
||||
popOut: true,
|
||||
resizable: true,
|
||||
dragDrop: [{ dragSelector: ".items-list .item", dropSelector: null }],
|
||||
classes: ["bol", "dialog"], width: 920, height: 'fit-content'
|
||||
async _prepareContext(_options) {
|
||||
const pcs = game.actors.filter(ac => ac.type === "personnage" && ac.hasPlayerOwner)
|
||||
const extras = []
|
||||
const validList = []
|
||||
for (const actorId of this.extraList) {
|
||||
const actor = game.actors.get(actorId)
|
||||
if (actor) { extras.push(actor); validList.push(actorId) }
|
||||
}
|
||||
if (validList.length !== this.extraList.length) {
|
||||
this.extraList = validList
|
||||
this._persist()
|
||||
}
|
||||
return { pcs, extras, config: game.system.malefices.config }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_onRender(_context, _options) {
|
||||
const el = this.element
|
||||
|
||||
el.querySelectorAll('.actor-open').forEach(a => {
|
||||
a.addEventListener('click', event => {
|
||||
const li = event.currentTarget.closest('.item')
|
||||
const actor = game.actors.get(li.dataset.actorId)
|
||||
actor?.sheet.render(true)
|
||||
})
|
||||
})
|
||||
|
||||
el.querySelectorAll('.summary-roll').forEach(a => {
|
||||
a.addEventListener('click', event => {
|
||||
const li = event.currentTarget.closest('.item')
|
||||
const actor = game.actors.get(li.dataset.actorId)
|
||||
const key = event.currentTarget.dataset.key
|
||||
actor?.rollAttribut(key)
|
||||
})
|
||||
})
|
||||
|
||||
el.querySelectorAll('.actor-delete').forEach(a => {
|
||||
a.addEventListener('click', event => {
|
||||
const li = event.currentTarget.closest('.item')
|
||||
this.extraList = this.extraList.filter(id => id !== li.dataset.actorId)
|
||||
this._persist()
|
||||
this.render({ force: true })
|
||||
})
|
||||
})
|
||||
|
||||
const dropZone = el.querySelector('.character-summary-container')
|
||||
if (dropZone) {
|
||||
dropZone.addEventListener('dragover', ev => ev.preventDefault())
|
||||
dropZone.addEventListener('drop', ev => { ev.stopPropagation(); this._onDrop(ev) })
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getData() {
|
||||
let formData = super.getData();
|
||||
_canDragDrop(_selector) { return true }
|
||||
|
||||
formData.pcs = game.actors.filter( ac => ac.type == "personnage" && ac.hasPlayerOwner )
|
||||
formData.npcs = []
|
||||
let newList = []
|
||||
let toUpdate = false
|
||||
for( let actorId of this.settings.npcList ) {
|
||||
let actor = game.actors.get(actorId)
|
||||
if (actor) {
|
||||
formData.npcs.push( actor )
|
||||
newList.push(actorId)
|
||||
} else {
|
||||
toUpdate = true
|
||||
}
|
||||
}
|
||||
formData.config = game.system.malefices.config
|
||||
|
||||
if ( toUpdate ) {
|
||||
this.settings.npcList = newList
|
||||
//console.log("Going to update ...", this.settings)
|
||||
game.settings.set("world", "character-summary-data", this.settings)
|
||||
}
|
||||
|
||||
return formData
|
||||
/* -------------------------------------------- */
|
||||
_persist() {
|
||||
const saved = game.settings.get("world", "character-summary-data")
|
||||
game.settings.set("world", "character-summary-data", { ...saved, extraList: this.extraList })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateNPC() {
|
||||
game.settings.set("world", "character-summary-data", game.system.malefices.charSummary.settings)
|
||||
game.system.malefices.charSummary.close()
|
||||
setTimeout( function() { game.system.malefices.charSummary.render(true)}, 500)
|
||||
_saveAndRefresh() {
|
||||
this.render({ force: true })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onDrop(event) {
|
||||
//console.log("Dragged data are : ", dragData)
|
||||
let data = event.dataTransfer.getData('text/plain')
|
||||
let dataItem = JSON.parse( data)
|
||||
let actor = fromUuidSync(dataItem.uuid)
|
||||
if (actor) {
|
||||
game.system.malefices.charSummary.settings.npcList.push( actor.id )
|
||||
game.system.malefices.charSummary.updateNPC()
|
||||
|
||||
} else {
|
||||
ui.notifications.warn( "Pas d'acteur trouvé" )
|
||||
}
|
||||
try {
|
||||
const dataItem = JSON.parse(event.dataTransfer.getData('text/plain'))
|
||||
const actor = fromUuidSync(dataItem.uuid)
|
||||
if (actor && !this.extraList.includes(actor.id)) {
|
||||
this.extraList.push(actor.id)
|
||||
this._persist()
|
||||
this.render({ force: true })
|
||||
}
|
||||
} catch(e) { /* not a valid drag payload */ }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
async activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
html.find('.actor-open').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
const actor = game.actors.get(li.data("actor-id"))
|
||||
actor.sheet.render(true)
|
||||
})
|
||||
|
||||
html.find('.summary-roll').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
const actor = game.actors.get(li.data("actor-id"))
|
||||
let type = $(event.currentTarget).data("type")
|
||||
let key = $(event.currentTarget).data("key")
|
||||
actor.rollAttribut(key)
|
||||
})
|
||||
|
||||
html.find('.actor-delete').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
let actorId = li.data("actor-id")
|
||||
let newList = game.system.malefices.charSummary.settings.npcList.filter(id => id != actorId)
|
||||
game.system.malefices.charSummary.settings.npcList = newList
|
||||
game.system.malefices.charSummary.updateNPC()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,155 +1,132 @@
|
||||
import { MaleficesUtility } from "./malefices-utility.js";
|
||||
|
||||
export class MaleficesTirageTarotDialog extends Dialog {
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
|
||||
|
||||
export class MaleficesTirageTarotDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, tirageData) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
id: "malefices-tirage-tarot",
|
||||
classes: ["MaleficesDialog"],
|
||||
window: { title: "Tirage des Tarots", resizable: true },
|
||||
position: { width: 720, height: 740 },
|
||||
}
|
||||
|
||||
let options = { classes: ["MaleficesDialog"], width: 720, height: 740, 'z-index': 99999 };
|
||||
let html = await renderTemplate('systems/fvtt-malefices/templates/dialogs/tirage-tarot-dialog.hbs', tirageData);
|
||||
|
||||
return new MaleficesTirageTarotDialog(actor, tirageData, html, options);
|
||||
static PARTS = {
|
||||
form: { template: 'systems/fvtt-malefices/templates/dialogs/tirage-tarot-dialog.hbs' }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, tirageData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: "Tirage des tarots",
|
||||
content: html,
|
||||
buttons: {
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Fermer/Annuler",
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
}
|
||||
constructor(actor, tirageData, options = {}) {
|
||||
super(options)
|
||||
this.actor = actor
|
||||
this.tirageData = tirageData
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, tirageData) {
|
||||
const app = new MaleficesTirageTarotDialog(actor, tirageData)
|
||||
app.render({ force: true })
|
||||
return app
|
||||
}
|
||||
|
||||
this.actor = actor;
|
||||
this.tirageData = tirageData;
|
||||
/* -------------------------------------------- */
|
||||
async _prepareContext(_options) {
|
||||
return { ...this.tirageData }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_onRender(_context, _options) {
|
||||
const el = this.element
|
||||
|
||||
el.querySelector('#playerId')?.addEventListener('change', (event) => {
|
||||
if (event.currentTarget.value !== "none") {
|
||||
this.tirageData.playerId = event.currentTarget.value
|
||||
this.processSelectedPlayer()
|
||||
}
|
||||
})
|
||||
|
||||
el.querySelector('#actorId')?.addEventListener('change', (event) => {
|
||||
if (event.currentTarget.value !== "none") {
|
||||
this.attributeToActor(event.currentTarget.value)
|
||||
}
|
||||
})
|
||||
|
||||
el.querySelector('.tirage-close-btn')?.addEventListener('click', () => this.close())
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async sendCardRequest() {
|
||||
this.tirageData.state = 'waiting-user-card'
|
||||
let msg = await MaleficesUtility.createChatMessage(this.tirageData.user.name, "useronly", {
|
||||
content: await renderTemplate(`systems/fvtt-malefices/templates/chat/request-tarot-card.hbs`, this.tirageData)
|
||||
await MaleficesUtility.createChatMessage(this.tirageData.user.name, "useronly", {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-malefices/templates/chat/request-tarot-card.hbs`, this.tirageData)
|
||||
})
|
||||
//msg.setFlag("world", "tirage-data", this.tirageData)
|
||||
console.log("MSG IS", msg)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
drawCard() {
|
||||
let index = Math.round(Math.random() * (this.tirageData.deck.length-1))
|
||||
let index = Math.round(Math.random() * (this.tirageData.deck.length - 1))
|
||||
let selectedCard = this.tirageData.deck[index]
|
||||
selectedCard.system.ispositif = true
|
||||
if ( selectedCard.system.isdualside) { // Cas des cartes pouvant avoir 2 sens
|
||||
if (selectedCard.system.isdualside) {
|
||||
selectedCard.system.ispositif = (Math.random() > 0.5)
|
||||
}
|
||||
console.log("CARD SELECTED:", selectedCard)
|
||||
// Cas spécial de la Roue de la Fortune
|
||||
if ( selectedCard.name.toLowerCase().includes("fortune")) {
|
||||
if (selectedCard.name.toLowerCase().includes("fortune")) {
|
||||
this.tirageData.maxPlayerCard += 1
|
||||
this.tirageData.maxSecretCard += 1
|
||||
}
|
||||
let newList = []
|
||||
for(let card of this.tirageData.deck) {
|
||||
if (card.name != selectedCard.name) {
|
||||
newList.push(card)
|
||||
}
|
||||
}
|
||||
this.tirageData.deck = newList
|
||||
|
||||
this.tirageData.deck = this.tirageData.deck.filter(c => c.name !== selectedCard.name)
|
||||
return selectedCard
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async addCard( msgId ) {
|
||||
async addCard(msgId) {
|
||||
MaleficesUtility.removeChatMessageId(msgId)
|
||||
|
||||
let selectedCard = this.drawCard()
|
||||
selectedCard.system.isgm = false
|
||||
await MaleficesUtility.createChatMessage(this.tirageData.user.name, "gmroll", {
|
||||
content: await renderTemplate(`systems/fvtt-malefices/templates/chat/display-tarot-card.hbs`, selectedCard)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-malefices/templates/chat/display-tarot-card.hbs`, selectedCard)
|
||||
})
|
||||
if (this.tirageData.cards[0].name == "???") {
|
||||
this.tirageData.cards.shift()
|
||||
}
|
||||
if (this.tirageData.cards[0].name == "???") this.tirageData.cards.shift()
|
||||
this.tirageData.cards.push(selectedCard)
|
||||
this.tirageData.nbCard++
|
||||
|
||||
if (this.tirageData.nbCard == this.tirageData.maxPlayerCard) {
|
||||
for (let i=0; i<this.tirageData.maxSecretCard; i++) {
|
||||
let selectedCard = this.drawCard()
|
||||
selectedCard.system.isgm = true
|
||||
for (let i = 0; i < this.tirageData.maxSecretCard; i++) {
|
||||
let secretCard = this.drawCard()
|
||||
secretCard.system.isgm = true
|
||||
await MaleficesUtility.createChatMessage(this.tirageData.user.name, "blindroll", {
|
||||
content: await renderTemplate(`systems/fvtt-malefices/templates/chat/display-tarot-card.hbs`, selectedCard)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-malefices/templates/chat/display-tarot-card.hbs`, secretCard)
|
||||
})
|
||||
if (this.tirageData.secretCards[0].name == "???") {
|
||||
this.tirageData.secretCards.shift()
|
||||
}
|
||||
this.tirageData.secretCards.push(selectedCard)
|
||||
if (this.tirageData.secretCards[0].name == "???") this.tirageData.secretCards.shift()
|
||||
this.tirageData.secretCards.push(secretCard)
|
||||
}
|
||||
this.tirageData.actors = duplicate(game.actors)
|
||||
this.tirageData.actors = foundry.utils.duplicate(game.actors)
|
||||
this.tirageData.state = 'attribute-to-actor'
|
||||
}else {
|
||||
} else {
|
||||
this.sendCardRequest()
|
||||
}
|
||||
this.refreshDialog()
|
||||
this.render({ force: true })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async processSelectedPlayer() {
|
||||
let user = game.users.get(this.tirageData.playerId)
|
||||
this.tirageData.user = user
|
||||
this.tirageData.user = game.users.get(this.tirageData.playerId)
|
||||
this.tirageData.players = null
|
||||
console.log("Going to work with ", user.name)
|
||||
game.system.malefices.currentTirage = this
|
||||
this.refreshDialog()
|
||||
this.render({ force: true })
|
||||
this.sendCardRequest()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
attributeToActor(actorId) {
|
||||
let actor = game.actors.get(actorId)
|
||||
const actor = game.actors.get(actorId)
|
||||
if (actor) {
|
||||
actor.createEmbeddedDocuments('Item', this.tirageData.cards)
|
||||
actor.createEmbeddedDocuments('Item', this.tirageData.secretCards)
|
||||
ui.notifications.info("Les cartes ont été attribuées à " + actor.name)
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async refreshDialog() {
|
||||
const content = await renderTemplate("systems/fvtt-malefices/templates/dialogs/tirage-tarot-dialog.hbs", this.tirageData)
|
||||
this.data.content = content
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
var dialog = this;
|
||||
function onLoad() {
|
||||
}
|
||||
$(function () { onLoad(); });
|
||||
|
||||
html.find('#playerId').change((event) => {
|
||||
if ( event.currentTarget.value != "none") {
|
||||
dialog.tirageData.playerId = event.currentTarget.value
|
||||
dialog.processSelectedPlayer()
|
||||
}
|
||||
})
|
||||
html.find('#actorId').change((event) => {
|
||||
if ( event.currentTarget.value != "none") {
|
||||
let actorId = event.currentTarget.value
|
||||
dialog.attributeToActor(actorId)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,18 +5,18 @@ import { MaleficesCommands } from "./malefices-commands.js";
|
||||
/* -------------------------------------------- */
|
||||
export class MaleficesUtility {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async init() {
|
||||
Hooks.on('renderChatLog', (log, html, data) => MaleficesUtility.chatListeners(html));
|
||||
/*Hooks.on("dropCanvasData", (canvas, data) => {
|
||||
MaleficesUtility.dropItemOnToken(canvas, data)
|
||||
});*/
|
||||
|
||||
this.rollDataStore = {}
|
||||
this.defenderStore = {}
|
||||
|
||||
MaleficesCommands.init();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async ready() {
|
||||
|
||||
Handlebars.registerHelper('count', function (list) {
|
||||
return list.length;
|
||||
@@ -43,14 +43,26 @@ export class MaleficesUtility {
|
||||
Handlebars.registerHelper('add', function (a, b) {
|
||||
return parseInt(a) + parseInt(b);
|
||||
})
|
||||
// Handle v12 removal of this helper
|
||||
Handlebars.registerHelper('select', function (selected, options) {
|
||||
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
|
||||
const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']');
|
||||
const html = options.fn(this);
|
||||
return html.replace(rgx, "$& selected");
|
||||
});
|
||||
|
||||
|
||||
game.settings.register("world", "character-summary-data", {
|
||||
name: "character-summary-data",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: { npcList: [], x: 200, y: 200 },
|
||||
default: { extraList: [], x: 200, y: 200 },
|
||||
type: Object
|
||||
})
|
||||
|
||||
const tarots = await MaleficesUtility.loadCompendium("fvtt-malefices.malefices-tarots")
|
||||
this.tarots = tarots.map(i => i.toObject())
|
||||
|
||||
}
|
||||
|
||||
/*-------------------------------------------- */
|
||||
@@ -61,17 +73,10 @@ export class MaleficesUtility {
|
||||
|
||||
/*-------------------------------------------- */
|
||||
static getTarots() {
|
||||
return duplicate(this.tarots)
|
||||
return foundry.utils.duplicate(this.tarots ?? [])
|
||||
}
|
||||
static getTarot(tId) {
|
||||
return this.tarots.find(t => t._id == tId)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async ready() {
|
||||
const tarots = await MaleficesUtility.loadCompendium("fvtt-malefices.malefices-tarots")
|
||||
this.tarots = tarots.map(i => i.toObject())
|
||||
|
||||
return this.tarots.find(t => t._id == tId)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -102,14 +107,14 @@ export class MaleficesUtility {
|
||||
if (game.user.isGM) {
|
||||
game.system.malefices.currentTirage.addCard(msgId)
|
||||
} else {
|
||||
game.socket.emit( "system.fvtt-malefices", {name: "msg-draw-card", data: {msgId: msgId}})
|
||||
game.socket.emit("system.fvtt-malefices", { name: "msg-draw-card", data: { msgId: msgId } })
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async chatListeners(html) {
|
||||
|
||||
html.on("click", '.roll-destin', event => {
|
||||
$(html).on("click", '.roll-destin', event => {
|
||||
let messageId = MaleficesUtility.findChatMessageId(event.currentTarget)
|
||||
let message = game.messages.get(messageId)
|
||||
let rollData = message.getFlag("world", "rolldata")
|
||||
@@ -118,11 +123,11 @@ export class MaleficesUtility {
|
||||
rollData.isReroll = true
|
||||
this.rollMalefices(rollData)
|
||||
})
|
||||
html.on("click", '.draw-tarot-card', event => {
|
||||
$(html).on("click", '.draw-tarot-card', event => {
|
||||
let messageId = MaleficesUtility.findChatMessageId(event.currentTarget)
|
||||
this.drawDeckCard(messageId)
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -130,10 +135,15 @@ export class MaleficesUtility {
|
||||
|
||||
const templatePaths = [
|
||||
'systems/fvtt-malefices/templates/actors/editor-notes-gm.hbs',
|
||||
'systems/fvtt-malefices/templates/items/partial-item-header.hbs',
|
||||
'systems/fvtt-malefices/templates/items/partial-item-nav.hbs',
|
||||
'systems/fvtt-malefices/templates/items/partial-item-description.hbs'
|
||||
'systems/fvtt-malefices/templates/items/partial-item-description.hbs',
|
||||
'systems/fvtt-malefices/templates/post-item.hbs',
|
||||
'systems/fvtt-malefices/templates/actors/npc-sheet.hbs',
|
||||
'systems/fvtt-malefices/templates/chat/welcome-message.hbs',
|
||||
'systems/fvtt-malefices/templates/dialogs/character-summary.hbs'
|
||||
]
|
||||
return loadTemplates(templatePaths);
|
||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -199,7 +209,7 @@ export class MaleficesUtility {
|
||||
|
||||
let id = rollData.rollId
|
||||
let oldRollData = this.rollDataStore[id] || {}
|
||||
let newRollData = mergeObject(oldRollData, rollData)
|
||||
let newRollData = foundry.utils.mergeObject(oldRollData, rollData)
|
||||
this.rollDataStore[id] = newRollData
|
||||
}
|
||||
|
||||
@@ -207,7 +217,7 @@ export class MaleficesUtility {
|
||||
static async onSocketMesssage(msg) {
|
||||
console.log("SOCKET MESSAGE", msg.name)
|
||||
if (msg.name == "msg-draw-card") {
|
||||
if ( game.user.isGM && game.system.malefices.currentTirage) {
|
||||
if (game.user.isGM && game.system.malefices.currentTirage) {
|
||||
game.system.malefices.currentTirage.addCard(msg.data.msgId)
|
||||
}
|
||||
}
|
||||
@@ -274,71 +284,79 @@ export class MaleficesUtility {
|
||||
/* -------------------------------------------- */
|
||||
static processSpecialCard(actor, rollData) {
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("archange")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("archange"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("archange"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "gmroll", {
|
||||
content: `Conséquence supplémentaire ! <br>L'Archange : ${actor.name} gagne 1 point de Spiritualité.` })
|
||||
content: `Conséquence supplémentaire ! <br>L'Archange : ${actor.name} gagne 1 point de Spiritualité.`
|
||||
})
|
||||
actor.incDecAttr("spiritualite", 1)
|
||||
}
|
||||
}
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("vicaire")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("vicaire"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("vicaire"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "blindroll", {
|
||||
content: `Conséquence supplémentaire ! <br>Le Vicaire : ${actor.name} vient de gagner 1 point en Pratique de la Magie Blanche (MPMB, secret).` })
|
||||
content: `Conséquence supplémentaire ! <br>Le Vicaire : ${actor.name} vient de gagner 1 point en Pratique de la Magie Blanche (MPMB, secret).`
|
||||
})
|
||||
actor.incDecMPMB(1)
|
||||
}
|
||||
}
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("chance")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("chance"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("chance"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "gmroll", {
|
||||
content: `Conséquence supplémentaire ! <br>La Chance : ${actor.name} a gagné 1 point de Destin.` })
|
||||
content: `Conséquence supplémentaire ! <br>La Chance : ${actor.name} a gagné 1 point de Destin.`
|
||||
})
|
||||
actor.incDecDestin(1)
|
||||
}
|
||||
}
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("mort")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("mort"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("mort"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "gmroll", {
|
||||
content: `Conséquence supplémentaire ! <br>La Mort : ${actor.name} est pétrifié par la peur.` })
|
||||
content: `Conséquence supplémentaire ! <br>La Mort : ${actor.name} est pétrifié par la peur.`
|
||||
})
|
||||
actor.incDecDestin(1)
|
||||
}
|
||||
}
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("diable")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("diable"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("diable"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "gmroll", {
|
||||
content: `Conséquence supplémentaire ! <br>Le Diable : ${actor.name} gagne 1 point de Rationnalité.` })
|
||||
content: `Conséquence supplémentaire ! <br>Le Diable : ${actor.name} gagne 1 point de Rationnalité.`
|
||||
})
|
||||
actor.incDecAttr("rationnalite", 1)
|
||||
}
|
||||
}
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("lune noire")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("lune noire"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("lune noire"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "blindroll", {
|
||||
content: `Conséquence supplémentaire ! <br>La Lune Noire : ${actor.name} vient de gagner 1 point de Fluide (secret).` })
|
||||
content: `Conséquence supplémentaire ! <br>La Lune Noire : ${actor.name} vient de gagner 1 point de Fluide (secret).`
|
||||
})
|
||||
actor.incDecFluide(1)
|
||||
}
|
||||
}
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("grand livre")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("grand livre"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("grand livre"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "blindroll", {
|
||||
content: `Conséquence supplémentaire ! <br>La Lune Noire : ${actor.name} vient de gagner 1 point de Fluide (secret).` })
|
||||
content: `Conséquence supplémentaire ! <br>La Lune Noire : ${actor.name} vient de gagner 1 point de Fluide (secret).`
|
||||
})
|
||||
actor.incDecFluide(1)
|
||||
}
|
||||
}
|
||||
if (rollData.selectedCard.name.toLowerCase().includes("sorcier")) {
|
||||
let actorCard = actor.items.find( c => c.type =="tarot" && c.name.toLowerCase().includes("sorcier"))
|
||||
let actorCard = actor.items.find(c => c.type == "tarot" && c.name.toLowerCase().includes("sorcier"))
|
||||
if (actorCard) {
|
||||
MaleficesUtility.createChatMessage(actor.name, "blindroll", {
|
||||
content: `Conséquence supplémentaire ! <br>Le Vicaire : ${actor.name} vient de gagner 1 point en Pratique de la Magie Noire (MPMN, secret).` })
|
||||
content: `Conséquence supplémentaire ! <br>Le Vicaire : ${actor.name} vient de gagner 1 point en Pratique de la Magie Noire (MPMN, secret).`
|
||||
})
|
||||
actor.incDecMPMN(1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeResults(rollData) {
|
||||
@@ -365,30 +383,30 @@ export class MaleficesUtility {
|
||||
rollData.target = rollData.attr.value - rollData.confrontationDegre + rollData.confrontationModif
|
||||
|
||||
let deck = this.getTarots()
|
||||
let index = Math.round(Math.random() * (deck.length-1))
|
||||
let index = Math.round(Math.random() * (deck.length - 1))
|
||||
let selectedCard = deck[index]
|
||||
selectedCard.system.ispositif = (Math.random() > 0.5)
|
||||
selectedCard.value = (selectedCard.system.ispositif)? selectedCard.system.numericvalueup : selectedCard.system.numericvaluedown
|
||||
selectedCard.value = (selectedCard.system.ispositif) ? selectedCard.system.numericvalueup : selectedCard.system.numericvaluedown
|
||||
rollData.total = selectedCard.value
|
||||
rollData.selectedCard = selectedCard
|
||||
await MaleficesUtility.createChatMessage(actor.name, "gmroll", {
|
||||
content: await renderTemplate(`systems/fvtt-malefices/templates/chat/display-tarot-card.hbs`, selectedCard)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-malefices/templates/chat/display-tarot-card.hbs`, selectedCard)
|
||||
})
|
||||
|
||||
this.computeResults(rollData)
|
||||
|
||||
if (rollData.isSuccess) {
|
||||
rollData.gainAttr = Math.ceil(rollData.confrontationDegre/2) + ((rollData.isCritical ) ? 1 : 0)
|
||||
actor.incDecAttr(rollData.attr.abbrev, rollData.gainAttr )
|
||||
rollData.gainAttr = Math.ceil(rollData.confrontationDegre / 2) + ((rollData.isCritical) ? 1 : 0)
|
||||
actor.incDecAttr(rollData.attr.abbrev, rollData.gainAttr)
|
||||
} else {
|
||||
rollData.gainAttr = rollData.confrontationDegre
|
||||
actor.incDecAttr(rollData.attr.abbrev, -rollData.gainAttr )
|
||||
actor.incDecAttr(rollData.attr.abbrev, -rollData.gainAttr)
|
||||
}
|
||||
|
||||
await MaleficesUtility.createChatMessage(actor.name, "gmroll", {
|
||||
content: await renderTemplate(`systems/fvtt-malefices/templates/chat/chat-confrontation-result.hbs`, rollData)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-malefices/templates/chat/chat-confrontation-result.hbs`, rollData)
|
||||
})
|
||||
this.processSpecialCard(actor, rollData)
|
||||
this.processSpecialCard(actor, rollData)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static async rollMalefices(rollData) {
|
||||
@@ -405,15 +423,15 @@ export class MaleficesUtility {
|
||||
|
||||
// Performs roll
|
||||
console.log("Roll formula", diceFormula)
|
||||
let myRoll = new Roll(diceFormula).roll({ async: false })
|
||||
let myRoll = await new Roll(diceFormula).roll()
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
|
||||
rollData.roll = myRoll
|
||||
rollData.roll = foundry.utils.duplicate(myRoll)
|
||||
rollData.total = myRoll.total
|
||||
|
||||
this.computeResults(rollData)
|
||||
|
||||
let msg = await this.createChatWithRollMode(rollData.alias, {
|
||||
content: await renderTemplate(`systems/fvtt-malefices/templates/chat/chat-generic-result.hbs`, rollData)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-malefices/templates/chat/chat-generic-result.hbs`, rollData)
|
||||
})
|
||||
msg.setFlag("world", "rolldata", rollData)
|
||||
if (rollData.mode == "initiative") {
|
||||
@@ -465,7 +483,7 @@ export class MaleficesUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static blindMessageToGM(chatOptions) {
|
||||
let chatGM = duplicate(chatOptions);
|
||||
let chatGM = foundry.utils.duplicate(chatOptions);
|
||||
chatGM.whisper = this.getUsers(user => user.isGM);
|
||||
chatGM.content = "Blinde message of " + game.user.name + "<br>" + chatOptions.content;
|
||||
console.log("blindMessageToGM", chatGM);
|
||||
@@ -515,7 +533,7 @@ export class MaleficesUtility {
|
||||
/* -------------------------------------------- */
|
||||
static getBasicRollData() {
|
||||
let rollData = {
|
||||
rollId: randomID(16),
|
||||
rollId: foundry.utils.randomID(16),
|
||||
bonusMalusPerso: 0,
|
||||
bonusMalusSituation: 0,
|
||||
bonusMalusDef: 0,
|
||||
@@ -541,30 +559,16 @@ export class MaleficesUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async confirmDelete(actorSheet, li) {
|
||||
let itemId = li.data("item-id");
|
||||
let msgTxt = "<p>Are you sure to remove this Item ?";
|
||||
let buttons = {
|
||||
delete: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Yes, remove it",
|
||||
callback: () => {
|
||||
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
|
||||
li.slideUp(200, () => actorSheet.render(false));
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Cancel"
|
||||
}
|
||||
}
|
||||
msgTxt += "</p>";
|
||||
let d = new Dialog({
|
||||
title: "Confirm removal",
|
||||
content: msgTxt,
|
||||
buttons: buttons,
|
||||
default: "cancel"
|
||||
const itemId = li.dataset.itemId;
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: { title: "Confirmer la suppression" },
|
||||
content: "<p>Supprimer cet objet ?</p>",
|
||||
yes: { label: "Supprimer", icon: "fas fa-trash" },
|
||||
no: { label: "Annuler", icon: "fas fa-times" },
|
||||
});
|
||||
d.render(true);
|
||||
if (confirmed) {
|
||||
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
modules/models/archetype.mjs
Normal file
12
modules/models/archetype.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les archétypes
|
||||
*/
|
||||
export default class ArchetypeDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
lametutelaire: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
19
modules/models/arme.mjs
Normal file
19
modules/models/arme.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Data model pour les armes
|
||||
*/
|
||||
export default class ArmeDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
armetype: new fields.StringField({ initial: "" }),
|
||||
porteecourte: new fields.StringField({ initial: "" }),
|
||||
porteemoyenne: new fields.StringField({ initial: "" }),
|
||||
dommagenormale: new fields.NumberField({ initial: 0, integer: true }),
|
||||
dommagepart: new fields.NumberField({ initial: 0, integer: true }),
|
||||
dommagecritique: new fields.NumberField({ initial: 0, integer: true }),
|
||||
dommagecritiqueKO: new fields.BooleanField({ initial: false }),
|
||||
dommagecritiquemort: new fields.BooleanField({ initial: false }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/elementbio.mjs
Normal file
11
modules/models/elementbio.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les éléments biographiques
|
||||
*/
|
||||
export default class ElementbioDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/equipement.mjs
Normal file
11
modules/models/equipement.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les équipements
|
||||
*/
|
||||
export default class EquipementDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
15
modules/models/index.mjs
Normal file
15
modules/models/index.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Index des DataModels pour Maléfices
|
||||
*/
|
||||
|
||||
// Modèles d'acteurs
|
||||
export { default as PersonnageDataModel } from './personnage.mjs';
|
||||
export { default as PnjDataModel } from './pnj.mjs';
|
||||
|
||||
// Modèles d'items
|
||||
export { default as ArmeDataModel } from './arme.mjs';
|
||||
export { default as EquipementDataModel } from './equipement.mjs';
|
||||
export { default as ArchetypeDataModel } from './archetype.mjs';
|
||||
export { default as TarotDataModel } from './tarot.mjs';
|
||||
export { default as SortilegeDataModel } from './sortilege.mjs';
|
||||
export { default as ElementbioDataModel } from './elementbio.mjs';
|
||||
95
modules/models/personnage.mjs
Normal file
95
modules/models/personnage.mjs
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Data model pour les personnages joueurs (type "personnage")
|
||||
*/
|
||||
export default class PersonnageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
// Template biodata
|
||||
biodata: new fields.SchemaField({
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
size: new fields.StringField({ initial: "" }),
|
||||
lieunaissance: new fields.StringField({ initial: "" }),
|
||||
nationalite: new fields.StringField({ initial: "" }),
|
||||
profession: new fields.StringField({ initial: "" }),
|
||||
residence: new fields.StringField({ initial: "" }),
|
||||
milieusocial: new fields.StringField({ initial: "" }),
|
||||
poids: new fields.StringField({ initial: "" }),
|
||||
cheveux: new fields.StringField({ initial: "" }),
|
||||
sexe: new fields.StringField({ initial: "" }),
|
||||
yeux: new fields.StringField({ initial: "" }),
|
||||
enfance: new fields.StringField({ initial: "" }),
|
||||
adulte: new fields.StringField({ initial: "" }),
|
||||
loisirs: new fields.StringField({ initial: "" }),
|
||||
singularite: new fields.StringField({ initial: "" }),
|
||||
politique: new fields.StringField({ initial: "" }),
|
||||
religion: new fields.StringField({ initial: "" }),
|
||||
fantastique: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
notes: new fields.HTMLField({ initial: "" }),
|
||||
gmnotes: new fields.HTMLField({ initial: "" })
|
||||
}),
|
||||
// Template core
|
||||
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||
lamesdestin: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||
pointdestin: new fields.NumberField({ initial: 1, integer: true }),
|
||||
fluide: new fields.NumberField({ initial: 5, integer: true }),
|
||||
mpmb: new fields.NumberField({ initial: 0, integer: true }),
|
||||
mpmn: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipementlibre: new fields.HTMLField({ initial: "" }),
|
||||
attributs: new fields.SchemaField({
|
||||
constitution: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Constitution" }),
|
||||
abbrev: new fields.StringField({ initial: "constitution" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
hasmax: new fields.BooleanField({ initial: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
physique: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Aptitudes Physiques" }),
|
||||
abbrev: new fields.StringField({ initial: "physique" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
hasmax: new fields.BooleanField({ initial: false }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
culturegenerale: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Culture Générale" }),
|
||||
abbrev: new fields.StringField({ initial: "culturegenerale" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
hasmax: new fields.BooleanField({ initial: false }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
habilite: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Habilité" }),
|
||||
abbrev: new fields.StringField({ initial: "habilite" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
hasmax: new fields.BooleanField({ initial: false }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
perception: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Perception" }),
|
||||
abbrev: new fields.StringField({ initial: "perception" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
hasmax: new fields.BooleanField({ initial: false }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
spiritualite: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Spiritualite" }),
|
||||
abbrev: new fields.StringField({ initial: "spiritualite" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
hasmax: new fields.BooleanField({ initial: false }),
|
||||
iscard: new fields.BooleanField({ initial: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
rationnalite: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Rationnalite" }),
|
||||
abbrev: new fields.StringField({ initial: "rationnalite" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
hasmax: new fields.BooleanField({ initial: false }),
|
||||
iscard: new fields.BooleanField({ initial: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/pnj.mjs
Normal file
12
modules/models/pnj.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les PNJ (type "pnj")
|
||||
*/
|
||||
export default class PnjDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
npctype: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/sortilege.mjs
Normal file
12
modules/models/sortilege.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les sortilèges
|
||||
*/
|
||||
export default class SortilegeDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
seuil: new fields.NumberField({ initial: 0, integer: true }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
17
modules/models/tarot.mjs
Normal file
17
modules/models/tarot.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Data model pour les lames de tarot
|
||||
*/
|
||||
export default class TarotDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
tarottype: new fields.StringField({ initial: "" }),
|
||||
numericvalueup: new fields.NumberField({ initial: 0, integer: true }),
|
||||
numericvaluedown: new fields.NumberField({ initial: 0, integer: true }),
|
||||
isdualside: new fields.BooleanField({ initial: false }),
|
||||
ispositif: new fields.BooleanField({ initial: true }),
|
||||
isgm: new fields.BooleanField({ initial: false }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
4982
package-lock.json
generated
Normal file
4982
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
package.json
Normal file
17
package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "fvtt-malefices",
|
||||
"version": "13.0.0",
|
||||
"description": "Maléfices 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-rename": "^2.0.0",
|
||||
"gulp-sourcemaps": "^3.0.0"
|
||||
}
|
||||
}
|
||||
0
packs/malefices-archetypes/000078.log
Normal file
0
packs/malefices-archetypes/000078.log
Normal file
BIN
packs/malefices-archetypes/000080.ldb
Normal file
BIN
packs/malefices-archetypes/000080.ldb
Normal file
Binary file not shown.
1
packs/malefices-archetypes/CURRENT
Normal file
1
packs/malefices-archetypes/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000076
|
||||
0
packs/malefices-archetypes/LOCK
Normal file
0
packs/malefices-archetypes/LOCK
Normal file
11
packs/malefices-archetypes/LOG
Normal file
11
packs/malefices-archetypes/LOG
Normal file
@@ -0,0 +1,11 @@
|
||||
2026/04/21-11:52:44.202744 7ff1aaffd6c0 Delete type=3 #1
|
||||
2026/04/21-13:41:40.820174 7ff1a9ffb6c0 Level-0 table #79: started
|
||||
2026/04/21-13:41:40.820230 7ff1a9ffb6c0 Level-0 table #79: 0 bytes OK
|
||||
2026/04/21-13:41:40.826374 7ff1a9ffb6c0 Delete type=0 #77
|
||||
2026/04/21-13:41:40.846124 7ff1a9ffb6c0 Manual compaction at level-0 from '!items!2HWSdXDSFei9KC6y' @ 72057594037927935 : 1 .. '!items!xtYE2kVIfNtrXSoU' @ 0 : 0; will stop at '!items!xtYE2kVIfNtrXSoU' @ 92 : 1
|
||||
2026/04/21-13:41:40.846135 7ff1a9ffb6c0 Compacting 1@0 + 0@1 files
|
||||
2026/04/21-13:41:40.850988 7ff1a9ffb6c0 Generated table #80@0: 23 keys, 50829 bytes
|
||||
2026/04/21-13:41:40.851009 7ff1a9ffb6c0 Compacted 1@0 + 0@1 files => 50829 bytes
|
||||
2026/04/21-13:41:40.857011 7ff1a9ffb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||
2026/04/21-13:41:40.857165 7ff1a9ffb6c0 Delete type=2 #41
|
||||
2026/04/21-13:41:40.887698 7ff1a9ffb6c0 Manual compaction at level-0 from '!items!xtYE2kVIfNtrXSoU' @ 92 : 1 .. '!items!xtYE2kVIfNtrXSoU' @ 0 : 0; will stop at (end)
|
||||
4
packs/malefices-archetypes/LOG.old
Normal file
4
packs/malefices-archetypes/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
||||
2026/04/21-11:52:44.183987 7ff1aaffd6c0 Log #74: 0 ops saved to Table #75 OK
|
||||
2026/04/21-11:52:44.184084 7ff1aaffd6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-archetypes/000074.log: OK
|
||||
2026/04/21-11:52:44.186478 7ff1aaffd6c0 Table #41: 23 entries OK
|
||||
2026/04/21-11:52:44.190025 7ff1aaffd6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-archetypes; recovered 1 files; 50829 bytes. Some data may have been lost. ****
|
||||
BIN
packs/malefices-archetypes/MANIFEST-000076
Normal file
BIN
packs/malefices-archetypes/MANIFEST-000076
Normal file
Binary file not shown.
0
packs/malefices-archetypes/lost/000024.log
Normal file
0
packs/malefices-archetypes/lost/000024.log
Normal file
0
packs/malefices-archetypes/lost/000025.log
Normal file
0
packs/malefices-archetypes/lost/000025.log
Normal file
0
packs/malefices-archetypes/lost/000074.log
Normal file
0
packs/malefices-archetypes/lost/000074.log
Normal file
BIN
packs/malefices-archetypes/lost/MANIFEST-000023
Normal file
BIN
packs/malefices-archetypes/lost/MANIFEST-000023
Normal file
Binary file not shown.
0
packs/malefices-armes/000078.log
Normal file
0
packs/malefices-armes/000078.log
Normal file
BIN
packs/malefices-armes/000080.ldb
Normal file
BIN
packs/malefices-armes/000080.ldb
Normal file
Binary file not shown.
1
packs/malefices-armes/CURRENT
Normal file
1
packs/malefices-armes/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000076
|
||||
0
packs/malefices-armes/LOCK
Normal file
0
packs/malefices-armes/LOCK
Normal file
11
packs/malefices-armes/LOG
Normal file
11
packs/malefices-armes/LOG
Normal file
@@ -0,0 +1,11 @@
|
||||
2026/04/21-11:52:44.181427 7ff1aaffd6c0 Delete type=3 #1
|
||||
2026/04/21-13:41:40.838999 7ff1a9ffb6c0 Level-0 table #79: started
|
||||
2026/04/21-13:41:40.839022 7ff1a9ffb6c0 Level-0 table #79: 0 bytes OK
|
||||
2026/04/21-13:41:40.846003 7ff1a9ffb6c0 Delete type=0 #77
|
||||
2026/04/21-13:41:40.878282 7ff1a9ffb6c0 Manual compaction at level-0 from '!items!5J6qIaWdnhEGMAXJ' @ 72057594037927935 : 1 .. '!items!nkRQU81L1gWOfaeo' @ 0 : 0; will stop at '!items!nkRQU81L1gWOfaeo' @ 36 : 1
|
||||
2026/04/21-13:41:40.878297 7ff1a9ffb6c0 Compacting 1@0 + 0@1 files
|
||||
2026/04/21-13:41:40.881453 7ff1a9ffb6c0 Generated table #80@0: 9 keys, 2083 bytes
|
||||
2026/04/21-13:41:40.881477 7ff1a9ffb6c0 Compacted 1@0 + 0@1 files => 2083 bytes
|
||||
2026/04/21-13:41:40.887457 7ff1a9ffb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||
2026/04/21-13:41:40.887570 7ff1a9ffb6c0 Delete type=2 #41
|
||||
2026/04/21-13:41:40.887738 7ff1a9ffb6c0 Manual compaction at level-0 from '!items!nkRQU81L1gWOfaeo' @ 36 : 1 .. '!items!nkRQU81L1gWOfaeo' @ 0 : 0; will stop at (end)
|
||||
4
packs/malefices-armes/LOG.old
Normal file
4
packs/malefices-armes/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
||||
2026/04/21-11:52:44.164486 7ff1aaffd6c0 Log #74: 0 ops saved to Table #75 OK
|
||||
2026/04/21-11:52:44.164589 7ff1aaffd6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-armes/000074.log: OK
|
||||
2026/04/21-11:52:44.164875 7ff1aaffd6c0 Table #41: 9 entries OK
|
||||
2026/04/21-11:52:44.168545 7ff1aaffd6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-armes; recovered 1 files; 2083 bytes. Some data may have been lost. ****
|
||||
BIN
packs/malefices-armes/MANIFEST-000076
Normal file
BIN
packs/malefices-armes/MANIFEST-000076
Normal file
Binary file not shown.
0
packs/malefices-armes/lost/000024.log
Normal file
0
packs/malefices-armes/lost/000024.log
Normal file
0
packs/malefices-armes/lost/000025.log
Normal file
0
packs/malefices-armes/lost/000025.log
Normal file
0
packs/malefices-armes/lost/000074.log
Normal file
0
packs/malefices-armes/lost/000074.log
Normal file
BIN
packs/malefices-armes/lost/MANIFEST-000023
Normal file
BIN
packs/malefices-armes/lost/MANIFEST-000023
Normal file
Binary file not shown.
3
packs/malefices-macros.db
Normal file
3
packs/malefices-macros.db
Normal file
@@ -0,0 +1,3 @@
|
||||
{"name":"Résumé des PJs pour le MJ","type":"chat","scope":"global","author":"R9gIh86vXDB4IFn1","img":"systems/fvtt-malefices/images/icons/resume.webp","command":"/resume","flags":{"core":{"sourceId":"Macro.ulj2PgchTQVE1VV4"}},"_stats":{"systemId":"fvtt-malefices","systemVersion":"10.1.1","coreVersion":"10.291","createdTime":1677422022018,"modifiedTime":1677422143283,"lastModifiedBy":"R9gIh86vXDB4IFn1"},"ownership":{"default":0,"R9gIh86vXDB4IFn1":3},"folder":null,"sort":0,"_id":"ESV4er8Hy6liMOC3"}
|
||||
{"name":"Tirage des tarots","type":"chat","scope":"global","author":"R9gIh86vXDB4IFn1","img":"systems/fvtt-malefices/images/icons/tirage.webp","command":"/tirage","flags":{"core":{"sourceId":"Macro.ulj2PgchTQVE1VV4"}},"_stats":{"systemId":"fvtt-malefices","systemVersion":"10.1.1","coreVersion":"10.291","createdTime":1677422022018,"modifiedTime":1677422144635,"lastModifiedBy":"R9gIh86vXDB4IFn1"},"ownership":{"default":0,"R9gIh86vXDB4IFn1":3},"folder":null,"sort":0,"_id":"sVKXJsiG9KAaBglV"}
|
||||
{"name":"Tirer une carte","type":"chat","command":"/carte","author":"R9gIh86vXDB4IFn1","img":"systems/fvtt-malefices/images/icons/tirer.webp","scope":"global","flags":{"core":{"sourceId":"Macro.P2dPA3CA5ZjOwDeE"}},"_stats":{"systemId":"fvtt-malefices","systemVersion":"10.1.1","coreVersion":"10.291","createdTime":1677421496447,"modifiedTime":1677422146138,"lastModifiedBy":"R9gIh86vXDB4IFn1"},"ownership":{"default":0,"R9gIh86vXDB4IFn1":3},"folder":null,"sort":0,"_id":"zDPgmHiwNxBWhoYz"}
|
||||
0
packs/malefices-macros/000078.log
Normal file
0
packs/malefices-macros/000078.log
Normal file
BIN
packs/malefices-macros/000080.ldb
Normal file
BIN
packs/malefices-macros/000080.ldb
Normal file
Binary file not shown.
1
packs/malefices-macros/CURRENT
Normal file
1
packs/malefices-macros/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000076
|
||||
0
packs/malefices-macros/LOCK
Normal file
0
packs/malefices-macros/LOCK
Normal file
11
packs/malefices-macros/LOG
Normal file
11
packs/malefices-macros/LOG
Normal file
@@ -0,0 +1,11 @@
|
||||
2026/04/21-11:52:44.222882 7ff1abfff6c0 Delete type=3 #1
|
||||
2026/04/21-13:41:40.832543 7ff1a9ffb6c0 Level-0 table #79: started
|
||||
2026/04/21-13:41:40.832568 7ff1a9ffb6c0 Level-0 table #79: 0 bytes OK
|
||||
2026/04/21-13:41:40.838884 7ff1a9ffb6c0 Delete type=0 #77
|
||||
2026/04/21-13:41:40.867899 7ff1a9ffb6c0 Manual compaction at level-0 from '!macros!ESV4er8Hy6liMOC3' @ 72057594037927935 : 1 .. '!macros!zDPgmHiwNxBWhoYz' @ 0 : 0; will stop at '!macros!zDPgmHiwNxBWhoYz' @ 12 : 1
|
||||
2026/04/21-13:41:40.867910 7ff1a9ffb6c0 Compacting 1@0 + 0@1 files
|
||||
2026/04/21-13:41:40.871553 7ff1a9ffb6c0 Generated table #80@0: 3 keys, 843 bytes
|
||||
2026/04/21-13:41:40.871580 7ff1a9ffb6c0 Compacted 1@0 + 0@1 files => 843 bytes
|
||||
2026/04/21-13:41:40.877546 7ff1a9ffb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||
2026/04/21-13:41:40.877655 7ff1a9ffb6c0 Delete type=2 #41
|
||||
2026/04/21-13:41:40.887725 7ff1a9ffb6c0 Manual compaction at level-0 from '!macros!zDPgmHiwNxBWhoYz' @ 12 : 1 .. '!macros!zDPgmHiwNxBWhoYz' @ 0 : 0; will stop at (end)
|
||||
4
packs/malefices-macros/LOG.old
Normal file
4
packs/malefices-macros/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
||||
2026/04/21-11:52:44.205891 7ff1abfff6c0 Log #74: 0 ops saved to Table #75 OK
|
||||
2026/04/21-11:52:44.206027 7ff1abfff6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-macros/000074.log: OK
|
||||
2026/04/21-11:52:44.206120 7ff1abfff6c0 Table #41: 3 entries OK
|
||||
2026/04/21-11:52:44.210039 7ff1abfff6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-macros; recovered 1 files; 843 bytes. Some data may have been lost. ****
|
||||
BIN
packs/malefices-macros/MANIFEST-000076
Normal file
BIN
packs/malefices-macros/MANIFEST-000076
Normal file
Binary file not shown.
0
packs/malefices-macros/lost/000024.log
Normal file
0
packs/malefices-macros/lost/000024.log
Normal file
0
packs/malefices-macros/lost/000025.log
Normal file
0
packs/malefices-macros/lost/000025.log
Normal file
0
packs/malefices-macros/lost/000074.log
Normal file
0
packs/malefices-macros/lost/000074.log
Normal file
BIN
packs/malefices-macros/lost/MANIFEST-000023
Normal file
BIN
packs/malefices-macros/lost/MANIFEST-000023
Normal file
Binary file not shown.
0
packs/malefices-tarots/000078.log
Normal file
0
packs/malefices-tarots/000078.log
Normal file
BIN
packs/malefices-tarots/000080.ldb
Normal file
BIN
packs/malefices-tarots/000080.ldb
Normal file
Binary file not shown.
1
packs/malefices-tarots/CURRENT
Normal file
1
packs/malefices-tarots/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000076
|
||||
0
packs/malefices-tarots/LOCK
Normal file
0
packs/malefices-tarots/LOCK
Normal file
11
packs/malefices-tarots/LOG
Normal file
11
packs/malefices-tarots/LOG
Normal file
@@ -0,0 +1,11 @@
|
||||
2026/04/21-11:52:44.160569 7ff1aa7fc6c0 Delete type=3 #1
|
||||
2026/04/21-13:41:40.826507 7ff1a9ffb6c0 Level-0 table #79: started
|
||||
2026/04/21-13:41:40.826536 7ff1a9ffb6c0 Level-0 table #79: 0 bytes OK
|
||||
2026/04/21-13:41:40.832425 7ff1a9ffb6c0 Delete type=0 #77
|
||||
2026/04/21-13:41:40.857305 7ff1a9ffb6c0 Manual compaction at level-0 from '!items!1DRKmbzGzbCRCswc' @ 72057594037927935 : 1 .. '!items!zbGGMEQFdwVdlKAf' @ 0 : 0; will stop at '!items!zbGGMEQFdwVdlKAf' @ 88 : 1
|
||||
2026/04/21-13:41:40.857314 7ff1a9ffb6c0 Compacting 1@0 + 0@1 files
|
||||
2026/04/21-13:41:40.860393 7ff1a9ffb6c0 Generated table #80@0: 22 keys, 4074 bytes
|
||||
2026/04/21-13:41:40.860404 7ff1a9ffb6c0 Compacted 1@0 + 0@1 files => 4074 bytes
|
||||
2026/04/21-13:41:40.867688 7ff1a9ffb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||
2026/04/21-13:41:40.867784 7ff1a9ffb6c0 Delete type=2 #41
|
||||
2026/04/21-13:41:40.887714 7ff1a9ffb6c0 Manual compaction at level-0 from '!items!zbGGMEQFdwVdlKAf' @ 88 : 1 .. '!items!zbGGMEQFdwVdlKAf' @ 0 : 0; will stop at (end)
|
||||
4
packs/malefices-tarots/LOG.old
Normal file
4
packs/malefices-tarots/LOG.old
Normal file
@@ -0,0 +1,4 @@
|
||||
2026/04/21-11:52:44.059054 7ff1aa7fc6c0 Log #74: 0 ops saved to Table #75 OK
|
||||
2026/04/21-11:52:44.059194 7ff1aa7fc6c0 Archiving /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-tarots/000074.log: OK
|
||||
2026/04/21-11:52:44.059258 7ff1aa7fc6c0 Table #41: 22 entries OK
|
||||
2026/04/21-11:52:44.063146 7ff1aa7fc6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-dev/Data/systems/fvtt-malefices/packs/malefices-tarots; recovered 1 files; 4074 bytes. Some data may have been lost. ****
|
||||
BIN
packs/malefices-tarots/MANIFEST-000076
Normal file
BIN
packs/malefices-tarots/MANIFEST-000076
Normal file
Binary file not shown.
0
packs/malefices-tarots/lost/000024.log
Normal file
0
packs/malefices-tarots/lost/000024.log
Normal file
0
packs/malefices-tarots/lost/000025.log
Normal file
0
packs/malefices-tarots/lost/000025.log
Normal file
0
packs/malefices-tarots/lost/000074.log
Normal file
0
packs/malefices-tarots/lost/000074.log
Normal file
BIN
packs/malefices-tarots/lost/MANIFEST-000023
Normal file
BIN
packs/malefices-tarots/lost/MANIFEST-000023
Normal file
Binary file not shown.
1599
styles/simple.css
1599
styles/simple.css
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user