Compare commits
36 Commits
fvtt-waste
...
04e35228e4
| Author | SHA1 | Date | |
|---|---|---|---|
| 04e35228e4 | |||
| ec2d5385c5 | |||
| 438caf3b1c | |||
| 627ccc707b | |||
| fdf28c4978 | |||
| e0eac58bc9 | |||
| b463323fbe | |||
| bddf772c99 | |||
| a716a3b3d1 | |||
| 5814ef41df | |||
| c0fcbe278f | |||
| 94f7ef8f90 | |||
| 19409dd547 | |||
| 217df7ee10 | |||
| 9990545568 | |||
| d2da332411 | |||
| 028e8bddac | |||
| 5c889a5153 | |||
| 68689add33 | |||
| 4ed2bcd2ee | |||
| 0edf336d28 | |||
| 046cdf4fb2 | |||
| cc0faec25e | |||
| 3419ddf8d6 | |||
| 5aa117b569 | |||
| 4b2dd20d49 | |||
| 3e394734ce | |||
| 06d0d9b24d | |||
| a3c5a9bfec | |||
| ca4b7f2803 | |||
| d4733f0c20 | |||
| 153c9e13b6 | |||
| 244a55777b | |||
| 7ac42672a3 | |||
| 02c80c1197 | |||
| da75a55978 |
63
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||
|
||||
#- uses: actions/checkout@v3
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Substitute the Manifest and Download URLs in the system.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: 'system.json'
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
manifest: https://www.uberwald.me/gitea/public/fvtt-wasteland/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-wasteland.zip
|
||||
|
||||
# Create a zip file with all files required by the module to add to the release
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./fvtt-wasteland.zip system.json README.md changelog.md assets/ lang/ modules/ packs/ styles/ templates/ template.json
|
||||
|
||||
- name: setup go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
|
||||
- name: Use Go Action
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
./fvtt-wasteland.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-wasteland'
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: 'https://www.uberwald.me/gitea/public/fvtt-wasteland/releases/download/latest/system.json'
|
||||
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-wasteland.zip'
|
||||
compatibility-minimum: '13'
|
||||
compatibility-verified: '13'
|
||||
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.history/
|
||||
node_modules
|
||||
|
||||
298
CREATURE_SHEET_IMPROVEMENTS.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# Améliorations de la Fiche Créature
|
||||
|
||||
## Vue d'ensemble
|
||||
La fiche créature a été complètement alignée avec les dernières améliorations de la fiche personnage pour assurer une expérience utilisateur cohérente à travers tout le système.
|
||||
|
||||
## Changements Apportés
|
||||
|
||||
## PARTIE 1 : ONGLET ATTRIBUTS (STATS)
|
||||
|
||||
### 1. Attributs avec Liste Déroulante (Dropdown)
|
||||
**Avant:**
|
||||
```handlebars
|
||||
<input type="number" name="system.attributs.{{key}}.value" value="{{attr.value}}" />
|
||||
```
|
||||
|
||||
**Après:**
|
||||
```handlebars
|
||||
<select name="system.attributs.{{key}}.value" value="{{attr.value}}" data-dtype="Number">
|
||||
{{selectOptions @root.config.listeNiveauCreature selected=attr.value}}
|
||||
</select>
|
||||
```
|
||||
|
||||
**Raison:**
|
||||
- Les créatures peuvent avoir des attributs de 0 à 35 (vs 0-10 pour personnages)
|
||||
- Utilise `listeNiveauCreature` créé dynamiquement dans `wasteland-main.js`
|
||||
- Interface plus propre et empêche les valeurs invalides
|
||||
|
||||
### 2. Attributs Cliquables (Rollable)
|
||||
**Avant:**
|
||||
```handlebars
|
||||
<span class="item-name">{{attr.label}}</span>
|
||||
```
|
||||
|
||||
**Après:**
|
||||
```handlebars
|
||||
<span class="item-name">
|
||||
<a class="rollable" data-action="rollAttribut" data-attr-key="{{key}}">{{attr.label}}</a>
|
||||
</span>
|
||||
```
|
||||
|
||||
**Raison:**
|
||||
- Permet de cliquer sur le nom de l'attribut pour faire un jet
|
||||
|
||||
### 3-5. Boutons +/- pour Santé et Psyché
|
||||
Ajouté des boutons d'ajustement pour:
|
||||
- Dégâts non létaux
|
||||
- Dégâts létaux
|
||||
- Psyché actuelle
|
||||
|
||||
**Raison:**
|
||||
- Facilite l'ajustement rapide en combat
|
||||
|
||||
### 6. Terminologie
|
||||
Changé "Courante" → "Actuelle" pour la psyché
|
||||
|
||||
## PARTIE 2 : ONGLET COMBAT
|
||||
|
||||
### 7. Valeurs de Combat - Grille 2x2 avec Champs Bonus
|
||||
**Layout:**
|
||||
```
|
||||
┌──────────────────────────────┬──────────────────────────────┐
|
||||
│ Initiative 12 [+2] = 14 │ Défense 15 [+2] = 17 │
|
||||
├──────────────────────────────┼──────────────────────────────┤
|
||||
│ Vitesse 8 [+0] = 8 │ Bonus Dég. +3 [+1] = +4 │
|
||||
└──────────────────────────────┴──────────────────────────────┘
|
||||
```
|
||||
|
||||
**Code:**
|
||||
```handlebars
|
||||
<div class="grid grid-2col">
|
||||
<div class="combat-stat-row">
|
||||
<label class="stat-label">Initiative</label>
|
||||
<div class="stat-values">
|
||||
<span class="stat-base">{{combat.initBase}}</span>
|
||||
<input type="number" class="input-numeric-short" name="system.combat.initbonus"
|
||||
value="{{system.combat.initbonus}}" data-tooltip="Bonus" />
|
||||
<span class="stat-total">= {{combat.initTotal}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 3 autres similaires -->
|
||||
</div>
|
||||
```
|
||||
|
||||
**Raison:**
|
||||
- **DIFFÉRENCE IMPORTANTE AVEC PERSONNAGE**: Créatures ont besoin des champs bonus éditables
|
||||
- **Grille 2x2**: Compacte mais lisible, 2 valeurs par ligne
|
||||
- Format: Nom | Base | [Bonus] | = Total
|
||||
|
||||
### 8. Compétences avec Boutons de Roll et Dropdown Niveau
|
||||
**Avant:**
|
||||
```handlebars
|
||||
<span class="item-niveau">Niveau: {{skill.system.niveau}}</span>
|
||||
```
|
||||
|
||||
**Après:**
|
||||
```handlebars
|
||||
<select class="status-small-label color-class-common edit-item-data competence-niveau"
|
||||
data-item-field="niveau" data-dtype="Number">
|
||||
{{selectOptions @root.config.listeNiveauSkill selected=skill.system.niveau}}
|
||||
</select>
|
||||
```
|
||||
|
||||
**Raison:**
|
||||
- **Liste déroulante pour le niveau** (0-10) au lieu de texte statique
|
||||
- Modification directe depuis la liste sans ouvrir la fiche
|
||||
- Utilise le handler `edit-item-data` existant
|
||||
- Appelle `editItemField()` pour mise à jour automatique
|
||||
- **Comportement identique** à la fiche personnage
|
||||
|
||||
**Ajouts:**
|
||||
- Boutons de roll par attribut (ADR:15, PUI:12, etc.)
|
||||
- Nom cliquable pour éditer
|
||||
- Bouton "Ajouter une compétence" en bas
|
||||
|
||||
### 9. Armes avec Format Moderne
|
||||
**Avant:**
|
||||
```handlebars
|
||||
<li class="item flexrow list-item items-title-bg">
|
||||
<span class="item-name-label-header">Armes</span>
|
||||
<span>Attaque</span> <span>Défense</span> <span>Dégâts</span>
|
||||
</li>
|
||||
```
|
||||
|
||||
**Après:**
|
||||
```handlebars
|
||||
<span class="weapon-stats">
|
||||
<span class="stat-offensif" data-tooltip="Attaque">
|
||||
<i class="fas fa-crosshairs"></i> {{arme.system.totalOffensif}}
|
||||
</span>
|
||||
{{#if arme.system.isdefense}}
|
||||
<span class="stat-defensif" data-tooltip="Défense">
|
||||
<i class="fas fa-shield"></i> {{arme.system.totalDefensif}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
<button class="button-sheet-roll" data-action="rollArmeOffensif">
|
||||
<i class="fas fa-dice-d20"></i>
|
||||
</button>
|
||||
<button class="button-sheet-roll" data-action="rollArmeDegats">
|
||||
<i class="fas fa-burst"></i>
|
||||
</button>
|
||||
```
|
||||
|
||||
**Raison:**
|
||||
- Stats avec icônes visuelles (🎯 crosshairs, 🛡️ shield)
|
||||
- Boutons avec icônes au lieu de texte
|
||||
- Suppression du header colonnes
|
||||
- Nom cliquable pour éditer
|
||||
- Bouton "Ajouter une arme" en bas
|
||||
|
||||
### 10. Capacités
|
||||
**Ajouts:**
|
||||
- Nom cliquable pour éditer
|
||||
- Bouton "Ajouter une capacité" en bas
|
||||
|
||||
## Fichiers Modifiés
|
||||
|
||||
### templates/actor-creature-sheet.hbs
|
||||
- **Lignes 26-37**: Attributs avec dropdown et rollable links
|
||||
- **Lignes 39-110**: Santé et Psyché avec boutons +/-
|
||||
- **Lignes 107-146**: Valeurs combat en grille 2x2 avec inputs bonus
|
||||
- **Lignes 148-189**: Compétences avec dropdown niveau et boutons de roll
|
||||
- **Lignes 191-243**: Armes au format moderne avec icônes
|
||||
- **Lignes 245-261**: Capacités avec nom cliquable
|
||||
- **Total**: ~140 lignes modifiées/ajoutées
|
||||
|
||||
### less/actor-styles.less
|
||||
- **Lignes 279-331**: Nouveaux styles pour `.combat-stats` (grille 2x2 créatures)
|
||||
- **Total**: 52 lignes ajoutées
|
||||
|
||||
## Styles CSS Ajoutés
|
||||
|
||||
```less
|
||||
.combat-stats {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.grid-2col {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.combat-stat-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid #6a0606;
|
||||
border-radius: 3px;
|
||||
padding: 0.4rem 0.6rem;
|
||||
gap: 0.5rem;
|
||||
|
||||
.stat-label {
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
min-width: 90px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.stat-values {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
flex: 1;
|
||||
|
||||
.stat-base { font-weight: bold; min-width: 30px; text-align: center; }
|
||||
.input-numeric-short { width: 50px; text-align: center; padding: 0.2rem; }
|
||||
.stat-total { font-weight: bold; color: #6a0606; min-width: 40px; }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Actions Utilisées
|
||||
|
||||
Toutes réutilisées depuis `base-actor-sheet.mjs`:
|
||||
- `rollAttribut` - Jets d'attributs
|
||||
- `incDecSante` - Boutons +/- santé/psyché
|
||||
- `rollCompetence` - Jets de compétence
|
||||
- `rollArmeOffensif` / `rollArmeDegats` - Jets d'arme
|
||||
- `createItem` / `editItem` / `deleteItem` - Gestion items
|
||||
|
||||
Handler spécial:
|
||||
- `edit-item-data` - Modification dropdown niveau compétence
|
||||
- Appelle `editItemField(itemId, itemType, itemField, dataType, value)` dans wasteland-actor.js
|
||||
|
||||
## Bénéfices
|
||||
|
||||
### Onglet Attributs
|
||||
1. **Cohérence**: Même interface que fiche personnage
|
||||
2. **Facilité**: Boutons +/- pour ajustements rapides
|
||||
3. **Prévention d'erreurs**: Dropdowns empêchent valeurs invalides
|
||||
4. **Ergonomie**: Attributs cliquables pour jets rapides
|
||||
|
||||
### Onglet Combat
|
||||
1. **Layout 2x2**: Valeurs de combat compactes
|
||||
2. **Champs Bonus**: Créatures peuvent ajuster leurs stats
|
||||
3. **Dropdown Niveau**: Modification compétences sans ouvrir fiche
|
||||
4. **Jets Rapides**: Boutons directement sur compétences/armes
|
||||
5. **Interface Moderne**: Icônes et layout épuré
|
||||
|
||||
## Comparaison Avant/Après
|
||||
|
||||
| Élément | Avant | Après | Bénéfice |
|
||||
|---------|-------|-------|----------|
|
||||
| **Attributs** | Input number | Select dropdown (0-35) + rollable | Prévention erreurs + jets rapides |
|
||||
| **Santé/Psyché** | Input seul | Input + boutons -/+ | Ajustement rapide en combat |
|
||||
| **Valeurs Combat** | Liste 4 lignes verticale | Grille 2x2 Base [Bonus] = Total | Layout compact + édition |
|
||||
| **Niveau Compétence** | Texte statique | Dropdown (0-10) éditable | Modification directe |
|
||||
| **Compétences** | Nom + niveau | Dropdown + boutons roll attributs | Jets + édition rapide |
|
||||
| **Armes** | Header + colonnes texte | Stats icônes + boutons icônes | Interface moderne |
|
||||
| **Capacités** | Nom statique | Nom cliquable + bouton ajout | Édition rapide |
|
||||
|
||||
## Tests Recommandés
|
||||
|
||||
### Onglet Attributs
|
||||
1. Vérifier dropdown attributs (0-35)
|
||||
2. Cliquer sur nom d'attribut pour jet
|
||||
3. Tester boutons +/- santé/psyché
|
||||
4. Vérifier sauvegarde modifications
|
||||
|
||||
### Onglet Combat
|
||||
1. Vérifier grille 2x2 valeurs combat
|
||||
2. Modifier les champs bonus
|
||||
3. **Tester dropdown niveau compétence** (nouveau)
|
||||
4. Tester boutons roll compétences
|
||||
5. Cliquer boutons attaque/dégâts armes
|
||||
6. Vérifier tooltips
|
||||
7. Tester ajout compétence/arme/capacité
|
||||
8. Cliquer noms pour éditer
|
||||
|
||||
## Notes Importantes
|
||||
|
||||
- **Aucune modification JavaScript nécessaire** (actions/handlers déjà existants)
|
||||
- **Modification CSS mineure** (52 lignes pour grille combat)
|
||||
- **Changements principalement template Handlebars**
|
||||
- **Compatible AppV2**
|
||||
- **Différence clé avec personnage**: Créatures ont champs bonus combat éditables
|
||||
- **Nouveau**: Dropdown niveau compétence avec modification directe (handler `edit-item-data`)
|
||||
|
||||
## Impact Visuel
|
||||
|
||||
```
|
||||
CRÉATURE (Valeurs Combat) - Grille 2x2:
|
||||
┌──────────────────────────────┬──────────────────────────────┐
|
||||
│ Initiative 12 [+2] = 14 │ Défense 15 [+2] = 17 │
|
||||
├──────────────────────────────┼──────────────────────────────┤
|
||||
│ Vitesse 8 [+0] = 8 │ Bonus Dég. +3 [+1] = +4 │
|
||||
└──────────────────────────────┴──────────────────────────────┘
|
||||
|
||||
CRÉATURE (Compétences):
|
||||
[🖼️] Mouvements [Dropdown 0-10: 3]
|
||||
[ADR : 15] [PUI : 12] [✏️] [🗑️]
|
||||
|
||||
PERSONNAGE (Compétences):
|
||||
[🖼️] Mouvements [Dropdown 0-10: 3]
|
||||
[ADR : 15] [PUI : 12] [✏️] [🗑️]
|
||||
Prédilections: Escalade, Course
|
||||
```
|
||||
|
||||
Total: ~140 lignes template + 52 lignes CSS = 192 lignes modifiées
|
||||
180
GITEA_RELEASE_WORKFLOW.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Workflow de Release Gitea pour Wasteland
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Ce workflow automatise la création de releases pour le système Wasteland dans Foundry VTT via Gitea Actions.
|
||||
|
||||
## Déclenchement
|
||||
|
||||
Le workflow se déclenche automatiquement lors de la **publication d'une release** sur Gitea :
|
||||
|
||||
```yaml
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
```
|
||||
|
||||
## Étapes du Workflow
|
||||
|
||||
### 1. Clone du Repository
|
||||
- Clone le repository Wasteland
|
||||
- Utilise `RouxAntoine/checkout@v3.5.4`
|
||||
|
||||
### 2. Extraction du Numéro de Version
|
||||
- Extrait la version depuis le tag de release
|
||||
- Exemple: tag `v1.2.3` → version `1.2.3`
|
||||
- Utilise `battila7/get-version-action@v2`
|
||||
|
||||
### 3. Substitution des URLs dans system.json
|
||||
Met à jour automatiquement le `system.json` avec :
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.2.3",
|
||||
"url": "https://www.uberwald.me/gitea/public/fvtt-wasteland",
|
||||
"manifest": "https://www.uberwald.me/gitea/public/fvtt-wasteland/releases/download/latest/system.json",
|
||||
"download": "https://www.uberwald.me/gitea/public/fvtt-wasteland/releases/download/v1.2.3/fvtt-wasteland.zip"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Création du ZIP
|
||||
Crée `fvtt-wasteland.zip` contenant :
|
||||
- `system.json` (mis à jour)
|
||||
- `README.md`
|
||||
- `changelog.md`
|
||||
- `assets/`
|
||||
- `lang/`
|
||||
- `modules/`
|
||||
- `packs/`
|
||||
- `styles/`
|
||||
- `templates/`
|
||||
- `template.json`
|
||||
|
||||
**Note:** Exclut `node_modules/`, `less/`, `gulpfile.js`, etc.
|
||||
|
||||
### 5. Upload vers Gitea
|
||||
- Upload du ZIP et du system.json vers la release
|
||||
- Utilise le secret `ALLOW_PUSH_RELEASE`
|
||||
|
||||
### 6. Publication sur Foundry VTT
|
||||
- Notifie le site officiel Foundry VTT de la nouvelle version
|
||||
- Utilise le secret `FOUNDRYVTT_RELEASE_TOKEN`
|
||||
- Compatibilité: Foundry V13
|
||||
|
||||
## Secrets Requis
|
||||
|
||||
Dans les paramètres du repository Gitea, configurer :
|
||||
|
||||
1. **`ALLOW_PUSH_RELEASE`**
|
||||
- Token Gitea avec droits d'écriture sur releases
|
||||
- Généré dans : Paramètres utilisateur → Applications → Tokens
|
||||
|
||||
2. **`FOUNDRYVTT_RELEASE_TOKEN`**
|
||||
- Token du Foundry Package Creator
|
||||
- Obtenu sur : https://foundryvtt.com/packages/edit/fvtt-wasteland
|
||||
|
||||
## Comment Créer une Release
|
||||
|
||||
### Méthode 1: Via l'Interface Gitea
|
||||
|
||||
1. Aller sur `https://www.uberwald.me/gitea/public/fvtt-wasteland`
|
||||
2. Cliquer sur "Releases"
|
||||
3. Cliquer sur "New Release"
|
||||
4. Remplir :
|
||||
- **Tag version**: `v1.2.3` (respecter le format `vX.Y.Z`)
|
||||
- **Release title**: `Version 1.2.3 - Description courte`
|
||||
- **Description**: Changelog détaillé
|
||||
5. Cocher "This is a pre-release" si applicable
|
||||
6. Cliquer sur "Publish Release"
|
||||
|
||||
### Méthode 2: Via Git CLI
|
||||
|
||||
```bash
|
||||
# Créer et pousser le tag
|
||||
git tag -a v1.2.3 -m "Version 1.2.3 - Description"
|
||||
git push origin v1.2.3
|
||||
|
||||
# Puis créer la release via l'interface Gitea
|
||||
```
|
||||
|
||||
## Déroulement Automatique
|
||||
|
||||
1. ✅ Détection de la publication de release
|
||||
2. ✅ Clone du repository
|
||||
3. ✅ Extraction de la version depuis le tag
|
||||
4. ✅ Mise à jour du system.json
|
||||
5. ✅ Création du ZIP
|
||||
6. ✅ Upload sur Gitea
|
||||
7. ✅ Publication sur Foundry VTT
|
||||
|
||||
## Vérification
|
||||
|
||||
Après publication, vérifier :
|
||||
|
||||
1. **Sur Gitea** : `https://www.uberwald.me/gitea/public/fvtt-wasteland/releases`
|
||||
- Le ZIP `fvtt-wasteland.zip` est disponible
|
||||
- Le `system.json` est disponible
|
||||
- Les URLs sont correctes
|
||||
|
||||
2. **Sur Foundry VTT** : https://foundryvtt.com/packages/fvtt-wasteland
|
||||
- La nouvelle version apparaît
|
||||
- Le manifest pointe vers le bon fichier
|
||||
|
||||
3. **Dans Foundry** :
|
||||
- Installer/Mettre à jour le système
|
||||
- Vérifier que tout fonctionne
|
||||
|
||||
## URLs Importantes
|
||||
|
||||
- **Repository**: https://www.uberwald.me/gitea/public/fvtt-wasteland
|
||||
- **Releases**: https://www.uberwald.me/gitea/public/fvtt-wasteland/releases
|
||||
- **Manifest (latest)**: https://www.uberwald.me/gitea/public/fvtt-wasteland/releases/download/latest/system.json
|
||||
- **Foundry Package**: https://foundryvtt.com/packages/fvtt-wasteland
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Le workflow ne se déclenche pas
|
||||
- Vérifier que la release est bien **published** (pas draft)
|
||||
- Vérifier que le fichier `.gitea/workflows/release.yaml` existe
|
||||
|
||||
### Erreur lors de la création du ZIP
|
||||
- Vérifier que tous les dossiers existent
|
||||
- Vérifier les permissions
|
||||
|
||||
### Erreur lors de la publication Foundry
|
||||
- Vérifier que `FOUNDRYVTT_RELEASE_TOKEN` est configuré
|
||||
- Vérifier que l'ID du package est correct (`fvtt-wasteland`)
|
||||
|
||||
### Les URLs ne sont pas mises à jour
|
||||
- Vérifier le format du tag (doit être `vX.Y.Z`)
|
||||
- Vérifier que `microsoft/variable-substitution` fonctionne
|
||||
|
||||
## Exemple de Changelog
|
||||
|
||||
Pour `v1.2.3` :
|
||||
|
||||
```markdown
|
||||
# Version 1.2.3 - Améliorations Fiches Créatures
|
||||
|
||||
## Nouvelles Fonctionnalités
|
||||
- Ajout de dropdowns pour niveaux de compétences créatures
|
||||
- Message de bienvenue stylé
|
||||
- Grille 2x2 pour valeurs de combat
|
||||
|
||||
## Corrections
|
||||
- Fix dialog render error
|
||||
- Fix attribute selection
|
||||
- Fix predilection reroll
|
||||
|
||||
## Améliorations
|
||||
- Interface créature alignée avec personnage
|
||||
- Styles cohérents pour tous les messages
|
||||
- Documentation complète
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Le workflow utilise Ubuntu latest
|
||||
- Go 1.20.1+ est installé pour l'action de release
|
||||
- Le système est compatible avec Foundry V13
|
||||
- Les packs sont inclus dans le ZIP (format NeDB/LevelDB)
|
||||
12
README.md
@@ -1,11 +1,14 @@
|
||||
# Système Foundry pour Wasteland (French RPG, Titam France/Sombres Projets)
|
||||
|
||||
Système Foundry pour Wasteland (French RPG, Titam France/Sombres Projets)
|
||||
|
||||
## EN
|
||||
|
||||
Unofficial system for Wasteland (French version from Titam France).
|
||||
Unofficial system for Wasteland (French RPG from Titam France).
|
||||
|
||||
Books are mandatory to play and are available at : http://www.titam-france.fr
|
||||
|
||||
``
|
||||
|
||||
## FR
|
||||
|
||||
Système non-officiel pour le JDR Wasteland (Titam France).
|
||||
@@ -16,8 +19,9 @@ Les livres du jeu sont nécessaires pour jouer, et sont disponibles ici : http:/
|
||||
|
||||
# Credits
|
||||
|
||||
Wasteland, le jeu de rôle de Sword & Sorcery, is a property of Titam France/Sombres Projets.
|
||||
Wasteland is a property of Titam France/Sombres Projets.
|
||||
|
||||
# Developmement
|
||||
|
||||
LeRatierBretonnien
|
||||
Code, CSS and automations : LeRatierBretonnien
|
||||
Compendiums : Pretre, LeRatierBretonnien
|
||||
|
||||
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 10 KiB |
BIN
assets/icons/armor.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/artifact.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
assets/icons/charm.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
BIN
assets/icons/gear.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
assets/icons/gear2.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
assets/icons/hability.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 11 KiB |
BIN
assets/icons/hubris.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/legacy.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
assets/icons/money.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 15 KiB |
BIN
assets/icons/mutation.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/origin.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
BIN
assets/icons/people.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/power.webp
Normal file
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 14 KiB |
BIN
assets/icons/shield.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
assets/icons/skill.webp
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/weapon.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/weapon_range.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/icons/work.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/logos/logo_wasteland.webp
Normal file
|
After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 35 KiB |
BIN
assets/ui/banniere_wasteland.webp
Normal file
|
After Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 236 KiB |
BIN
assets/ui/landing_page_wasteland.webp
Normal file
|
After Width: | Height: | Size: 431 KiB |
8
changelog.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# 12.0.1
|
||||
|
||||
- Fix v12 version
|
||||
|
||||
# 11.0.22
|
||||
|
||||
- Version initiale
|
||||
-
|
||||
35
gulpfile.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const gulp = require('gulp');
|
||||
const less = require('gulp-less');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
|
||||
// Paths
|
||||
const paths = {
|
||||
styles: {
|
||||
src: 'less/**/*.less',
|
||||
dest: 'styles/'
|
||||
}
|
||||
};
|
||||
|
||||
// Compile LESS to CSS
|
||||
function styles() {
|
||||
return gulp.src('less/wasteland.less')
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(less())
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest(paths.styles.dest));
|
||||
}
|
||||
|
||||
// Watch files
|
||||
function watchFiles() {
|
||||
gulp.watch(paths.styles.src, styles);
|
||||
}
|
||||
|
||||
// Define complex tasks
|
||||
const build = gulp.series(styles);
|
||||
const watch = gulp.series(build, watchFiles);
|
||||
|
||||
// Export tasks
|
||||
exports.styles = styles;
|
||||
exports.build = build;
|
||||
exports.watch = watch;
|
||||
exports.default = build;
|
||||
45
lang/fr.json
@@ -1,24 +1,27 @@
|
||||
{
|
||||
"ACTOR": {
|
||||
"TypePersonnage": "Personnage",
|
||||
"TypePNJ": "PNJ"
|
||||
},
|
||||
|
||||
"ITEM": {
|
||||
"TypeArme": "Arme",
|
||||
"TypeCompetence": "Compétence",
|
||||
"TypeProtection": "Protection",
|
||||
"TypeMonnaie": "Monnaie",
|
||||
"TypeEquipement": "Equipement",
|
||||
"TypeCapacite": "Capacité",
|
||||
"TypeOrigine": "Origine",
|
||||
"TypeHeritage": "Héritage",
|
||||
"TypeMetier": "Métier",
|
||||
"TypeBouclier": "Bouclier",
|
||||
"TypePouvoir": "Pouvoir",
|
||||
"TypeArtifex": "Artifex",
|
||||
"TypeMutation": "Mutation",
|
||||
"TypeCharme": "Charme",
|
||||
"TypePeuple": "Peuple"
|
||||
"TYPES": {
|
||||
"Item": {
|
||||
"arme": "Arme",
|
||||
"competence": "Compétence",
|
||||
"protection": "Protection",
|
||||
"monnaie": "Monnaie",
|
||||
"equipement": "Equipement",
|
||||
"don": "Don",
|
||||
"hubris": "Hubris",
|
||||
"capacite": "Capacité",
|
||||
"origine": "Origine",
|
||||
"heritage": "Héritage",
|
||||
"metier": "Métier",
|
||||
"bouclier": "Bouclier",
|
||||
"pouvoir": "Pouvoir",
|
||||
"artifex": "Artifex",
|
||||
"mutation": "Mutation",
|
||||
"charme": "Charme",
|
||||
"peuple": "Peuple"
|
||||
},
|
||||
"Actor": {
|
||||
"personnage": "Personnage",
|
||||
"creature": "Créature"
|
||||
}
|
||||
}
|
||||
}
|
||||
1201
less/actor-styles.less
Normal file
859
less/chat-styles.less
Normal file
@@ -0,0 +1,859 @@
|
||||
/* ============================================ */
|
||||
/* WASTELAND CHAT MESSAGE STYLES */
|
||||
/* Post-Apocalyptic Theme */
|
||||
/* ============================================ */
|
||||
|
||||
.wasteland-chat-result {
|
||||
background: linear-gradient(135deg, rgba(50, 40, 30, 0.95) 0%, rgba(30, 25, 20, 0.95) 100%);
|
||||
border: 2px solid #8b7355;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
font-family: "Charlemagne", serif;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
position: relative;
|
||||
|
||||
// Effet de texture sale/usée
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 2px,
|
||||
rgba(0, 0, 0, 0.03) 2px,
|
||||
rgba(0, 0, 0, 0.03) 4px
|
||||
);
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.chat-result-header {
|
||||
background: linear-gradient(135deg, #3d2f1f 0%, #2a1f15 100%);
|
||||
border-bottom: 2px solid #8b7355;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
position: relative;
|
||||
box-shadow: inset 0 -2px 4px rgba(0, 0, 0, 0.4);
|
||||
|
||||
// Effet rouille sur le bord
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
#6a0606 20%,
|
||||
#8b7355 40%,
|
||||
#6a0606 60%,
|
||||
transparent 100%
|
||||
);
|
||||
}
|
||||
|
||||
.actor-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 2px;
|
||||
border: 2px solid #8b7355;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
|
||||
filter: contrast(1.1) saturate(0.9);
|
||||
}
|
||||
|
||||
.header-info {
|
||||
flex: 1;
|
||||
|
||||
.actor-name {
|
||||
margin: 0;
|
||||
color: #e8dcc4;
|
||||
font-size: 1.1rem;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9);
|
||||
font-family: "Charlemagne", serif;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.action-title {
|
||||
color: #c9a86a;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.125rem;
|
||||
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.9);
|
||||
font-style: italic;
|
||||
|
||||
i {
|
||||
margin-right: 0.25rem;
|
||||
color: #8b7355;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-main {
|
||||
background: linear-gradient(180deg, rgba(230, 220, 200, 0.9) 0%, rgba(210, 200, 180, 0.9) 100%);
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-bottom: 1px solid rgba(139, 115, 85, 0.5);
|
||||
position: relative;
|
||||
|
||||
&.damage {
|
||||
background: linear-gradient(180deg, rgba(200, 180, 160, 0.95) 0%, rgba(180, 160, 140, 0.95) 100%);
|
||||
}
|
||||
|
||||
.result-display {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.1875rem;
|
||||
|
||||
.dice-result,
|
||||
.total-result,
|
||||
.difficulty {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
background: linear-gradient(180deg, rgba(50, 40, 30, 0.7) 0%, rgba(40, 30, 20, 0.8) 100%);
|
||||
padding: 0.25rem 0.375rem;
|
||||
border-radius: 2px;
|
||||
border: 2px solid #8b7355;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5), 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
|
||||
i {
|
||||
color: #c9a86a;
|
||||
font-size: 1rem;
|
||||
display: block;
|
||||
margin-bottom: 0.125rem;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dice-value,
|
||||
.total-value,
|
||||
.difficulty-value {
|
||||
font-size: 1.5rem;
|
||||
color: #e8dcc4;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9);
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.total-label,
|
||||
.difficulty-label {
|
||||
font-size: 0.75rem;
|
||||
color: #c9a86a;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
line-height: 1.1;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.damage-display {
|
||||
.damage-total {
|
||||
text-align: center;
|
||||
background: linear-gradient(180deg, rgba(60, 50, 40, 0.8) 0%, rgba(50, 40, 30, 0.9) 100%);
|
||||
padding: 0.5rem;
|
||||
border-radius: 2px;
|
||||
border: 2px solid #8b7355;
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.6), 0 2px 4px rgba(0, 0, 0, 0.4);
|
||||
|
||||
i {
|
||||
color: #c9a86a;
|
||||
font-size: 1.2rem;
|
||||
display: block;
|
||||
margin-bottom: 0.25rem;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.damage-label {
|
||||
display: block;
|
||||
font-size: 0.85rem;
|
||||
color: #c9a86a;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.25rem;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.damage-value {
|
||||
display: block;
|
||||
font-size: 2rem;
|
||||
color: #e8dcc4;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9), 0 0 8px rgba(200, 0, 0, 0.3);
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-badge-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 0.25rem;
|
||||
|
||||
.result-badge {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 2px;
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
||||
|
||||
i {
|
||||
margin-right: 0.375rem;
|
||||
}
|
||||
|
||||
&.heroique {
|
||||
background: linear-gradient(135deg, #c9a86a 0%, #8b7355 100%);
|
||||
color: #1a1a1a;
|
||||
text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.5);
|
||||
border-color: #8b7355;
|
||||
}
|
||||
|
||||
&.success {
|
||||
background: linear-gradient(135deg, #6b8e23 0%, #4a6017 100%);
|
||||
color: #e8dcc4;
|
||||
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.8);
|
||||
border-color: #4a6017;
|
||||
}
|
||||
|
||||
&.failure {
|
||||
background: linear-gradient(135deg, #5a4a3a 0%, #3a2a1a 100%);
|
||||
color: #c9a86a;
|
||||
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.9);
|
||||
border-color: #3a2a1a;
|
||||
}
|
||||
|
||||
&.dramatique {
|
||||
background: linear-gradient(135deg, #4a0404 0%, #2a0202 100%);
|
||||
color: #e8dcc4;
|
||||
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.9);
|
||||
border-color: #6a0606;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-details {
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(180deg, rgba(70, 60, 50, 0.6) 0%, rgba(60, 50, 40, 0.7) 100%);
|
||||
border-top: 1px solid rgba(139, 115, 85, 0.3);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
|
||||
.details-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1875rem;
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.1875rem 0.375rem;
|
||||
background: linear-gradient(90deg, rgba(230, 220, 200, 0.6) 0%, rgba(210, 200, 180, 0.5) 100%);
|
||||
border-radius: 1px;
|
||||
font-size: 0.85rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
border-left: 2px solid #8b7355;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
|
||||
&.bonus {
|
||||
background: linear-gradient(90deg, rgba(200, 220, 180, 0.7) 0%, rgba(180, 200, 160, 0.6) 100%);
|
||||
border-left-color: #6b8e23;
|
||||
}
|
||||
|
||||
&.malus {
|
||||
background: linear-gradient(90deg, rgba(220, 180, 160, 0.7) 0%, rgba(200, 160, 140, 0.6) 100%);
|
||||
border-left-color: #8b4513;
|
||||
}
|
||||
|
||||
&.rune {
|
||||
background: linear-gradient(90deg, rgba(190, 180, 210, 0.7) 0%, rgba(170, 160, 190, 0.6) 100%);
|
||||
border-left-color: #6a5acd;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
color: #2a1f15;
|
||||
font-weight: bold;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: #2a1f15;
|
||||
font-weight: 500;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-effects {
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(180deg, rgba(80, 70, 60, 0.5) 0%, rgba(70, 60, 50, 0.6) 100%);
|
||||
border-top: 1px solid rgba(139, 115, 85, 0.4);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
|
||||
.effect-success,
|
||||
.effect-warning,
|
||||
.effect-failure,
|
||||
.effect-damage,
|
||||
.effect-heroic {
|
||||
padding: 0.3125rem 0.5rem;
|
||||
margin-bottom: 0.3125rem;
|
||||
background: linear-gradient(90deg, rgba(230, 220, 200, 0.8) 0%, rgba(210, 200, 180, 0.7) 100%);
|
||||
border-radius: 1px;
|
||||
border-left: 3px solid;
|
||||
font-size: 0.85rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
|
||||
i {
|
||||
margin-right: 0.375rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.effect-success {
|
||||
border-left-color: #6b8e23;
|
||||
color: #2a1f15;
|
||||
}
|
||||
|
||||
.effect-heroic {
|
||||
border-left-color: #c9a86a;
|
||||
color: #2a1f15;
|
||||
font-weight: bold;
|
||||
background: linear-gradient(90deg, rgba(201, 168, 106, 0.3) 0%, rgba(230, 220, 200, 0.8) 100%);
|
||||
}
|
||||
|
||||
.effect-warning {
|
||||
border-left-color: #d97706;
|
||||
color: #2a1f15;
|
||||
}
|
||||
|
||||
.effect-failure {
|
||||
border-left-color: #8b4513;
|
||||
color: #2a1f15;
|
||||
}
|
||||
|
||||
.effect-damage {
|
||||
border-left-color: #6a0606;
|
||||
color: #2a1f15;
|
||||
background: linear-gradient(90deg, rgba(200, 100, 100, 0.3) 0%, rgba(210, 200, 180, 0.7) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.damage-button-section {
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(180deg, rgba(100, 70, 60, 0.5) 0%, rgba(80, 60, 50, 0.6) 100%);
|
||||
border-top: 1px solid rgba(139, 115, 85, 0.5);
|
||||
|
||||
.chat-card-button {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(to bottom, #6a0606 0%, #4a0404 100%);
|
||||
border: 2px solid #8b7355;
|
||||
border-radius: 2px;
|
||||
color: #e8dcc4;
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
font-family: "Charlemagne", serif;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, #8a0808 0%, #5a0505 100%);
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
border-color: #c9a86a;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.predilection-reroll-section {
|
||||
padding: 0.75rem;
|
||||
background: linear-gradient(135deg, rgba(139, 115, 85, 0.3) 0%, rgba(100, 80, 60, 0.4) 100%);
|
||||
border: 2px solid #8b7355;
|
||||
border-radius: 2px;
|
||||
margin: 0.5rem;
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
|
||||
// Cacher toute icône de dé qui pourrait apparaître par erreur
|
||||
.fa-dice {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.predilection-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid rgba(139, 115, 85, 0.5);
|
||||
|
||||
i {
|
||||
color: #c9a86a;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.predilection-title {
|
||||
color: #e8dcc4;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
font-family: "Charlemagne", serif;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.predilection-results {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
|
||||
.predilection-roll {
|
||||
flex: 1;
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(90deg, rgba(230, 220, 200, 0.4) 0%, rgba(210, 200, 180, 0.3) 100%);
|
||||
border-radius: 2px;
|
||||
border-left: 2px solid #8b7355;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
position: relative;
|
||||
|
||||
&.kept {
|
||||
background: linear-gradient(90deg, rgba(200, 220, 180, 0.6) 0%, rgba(180, 200, 160, 0.5) 100%);
|
||||
border-left-color: #6b8e23;
|
||||
box-shadow: 0 0 8px rgba(107, 142, 35, 0.3);
|
||||
}
|
||||
|
||||
.roll-label {
|
||||
color: #2a1f15;
|
||||
font-weight: bold;
|
||||
font-size: 0.75rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
.roll-value {
|
||||
color: #2a1f15;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
i.fa-check-circle {
|
||||
color: #6b8e23;
|
||||
font-size: 1.1rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.predilection-kept {
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(90deg, rgba(200, 220, 180, 0.7) 0%, rgba(180, 200, 160, 0.6) 100%);
|
||||
border: 1px solid #6b8e23;
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
color: #2a1f15;
|
||||
font-size: 0.95rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
i {
|
||||
color: #6b8e23;
|
||||
}
|
||||
|
||||
.kept-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.predilection-section {
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(180deg, rgba(100, 90, 70, 0.5) 0%, rgba(80, 70, 60, 0.6) 100%);
|
||||
border-top: 1px solid rgba(139, 115, 85, 0.5);
|
||||
|
||||
.chat-card-button {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(to bottom, #5a4a3a 0%, #3a2a1a 100%);
|
||||
border: 2px solid #8b7355;
|
||||
border-radius: 2px;
|
||||
color: #e8dcc4;
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
font-family: "Charlemagne", serif;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, #6a5a4a 0%, #4a3a2a 100%);
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
border-color: #c9a86a;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================ */
|
||||
/* WASTELAND ITEM CHAT POSTS */
|
||||
/* ============================================ */
|
||||
|
||||
.wasteland-chat-item {
|
||||
background: linear-gradient(135deg, rgba(50, 40, 30, 0.95) 0%, rgba(30, 25, 20, 0.95) 100%);
|
||||
border: 2px solid #8b7355;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
font-family: "Charlemagne", serif;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
position: relative;
|
||||
|
||||
// Effet de texture sale/usée
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 2px,
|
||||
rgba(0, 0, 0, 0.03) 2px,
|
||||
rgba(0, 0, 0, 0.03) 4px
|
||||
);
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.chat-item-header {
|
||||
background: linear-gradient(135deg, #3d2f1f 0%, #2a1f15 100%);
|
||||
border-bottom: 2px solid #8b7355;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
position: relative;
|
||||
box-shadow: inset 0 -2px 4px rgba(0, 0, 0, 0.4);
|
||||
|
||||
// Effet rouille sur le bord
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg,
|
||||
transparent 0%,
|
||||
#6a0606 20%,
|
||||
#8b7355 40%,
|
||||
#6a0606 60%,
|
||||
transparent 100%
|
||||
);
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 2px;
|
||||
border: 2px solid #8b7355;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
|
||||
filter: contrast(1.1) saturate(0.9);
|
||||
}
|
||||
|
||||
.header-info {
|
||||
flex: 1;
|
||||
|
||||
.item-name {
|
||||
margin: 0;
|
||||
color: #e8dcc4;
|
||||
font-size: 1.1rem;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.9);
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.item-type {
|
||||
margin-top: 0.25rem;
|
||||
color: #c9a86a;
|
||||
font-size: 0.85rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
text-transform: capitalize;
|
||||
|
||||
i {
|
||||
color: #8b7355;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-item-body {
|
||||
padding: 0.75rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.item-description {
|
||||
color: #e8dcc4;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 0.75rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
||||
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-properties {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.75rem;
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid rgba(139, 115, 85, 0.3);
|
||||
|
||||
.property {
|
||||
background: linear-gradient(90deg, rgba(230, 220, 200, 0.6) 0%, rgba(210, 200, 180, 0.5) 100%);
|
||||
padding: 0.375rem 0.5rem;
|
||||
border-radius: 1px;
|
||||
border-left: 2px solid #8b7355;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.property-label {
|
||||
color: #2a1f15;
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
.property-value {
|
||||
color: #2a1f15;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================================ */
|
||||
/* WASTELAND WELCOME MESSAGE */
|
||||
/* ============================================ */
|
||||
|
||||
.wasteland-welcome-message {
|
||||
background: linear-gradient(135deg, rgba(61, 47, 31, 0.15) 0%, rgba(42, 31, 21, 0.2) 100%);
|
||||
border: 2px solid #6a0606;
|
||||
border-radius: 8px;
|
||||
padding: 0;
|
||||
margin: 8px 0;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4),
|
||||
inset 0 1px 0 rgba(201, 168, 106, 0.1);
|
||||
font-family: "Charlemagne", serif;
|
||||
|
||||
.welcome-header {
|
||||
background: linear-gradient(135deg, #6a0606 0%, #4a0404 100%);
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
border-bottom: 2px solid #c9a86a;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
|
||||
.welcome-icon {
|
||||
font-size: 1.8rem;
|
||||
color: #c9a86a;
|
||||
margin-bottom: 4px;
|
||||
text-shadow: 0 0 10px rgba(201, 168, 106, 0.5);
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.welcome-title {
|
||||
margin: 4px 0 2px 0;
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: #e8dcc4;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||
font-family: "Charlemagne", serif;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.welcome-subtitle {
|
||||
font-size: 0.9rem;
|
||||
color: #c9a86a;
|
||||
font-style: italic;
|
||||
margin-top: 2px;
|
||||
line-height: 1.2;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-content {
|
||||
padding: 12px;
|
||||
background: linear-gradient(180deg, rgba(230, 220, 200, 0.9) 0%, rgba(210, 200, 180, 0.85) 100%);
|
||||
|
||||
.welcome-section {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 8px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 4px;
|
||||
border: 1px solid #c9a86a;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-icon {
|
||||
flex-shrink: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #6a0606 0%, #4a0404 100%);
|
||||
color: #c9a86a;
|
||||
border-radius: 50%;
|
||||
font-size: 1rem;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
|
||||
i {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.section-text {
|
||||
flex: 1;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
color: #3d2f1f;
|
||||
margin-bottom: 4px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
color: #2a1f15;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.welcome-link {
|
||||
display: inline-block;
|
||||
margin-top: 4px;
|
||||
color: #6a0606;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
font-size: 0.9rem;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #8b0606;
|
||||
text-shadow: 0 0 4px rgba(106, 6, 6, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.welcome-footer {
|
||||
background: linear-gradient(135deg, #4a0404 0%, #6a0606 100%);
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
color: #c9a86a;
|
||||
font-style: italic;
|
||||
font-size: 0.95rem;
|
||||
border-top: 1px solid #8b7355;
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
font-family: "Charlemagne", serif;
|
||||
|
||||
i {
|
||||
margin: 0 8px;
|
||||
opacity: 0.7;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
569
less/item-styles.less
Normal file
@@ -0,0 +1,569 @@
|
||||
/* ==================== Item Sheet Styles ==================== */
|
||||
|
||||
/* Item header with image and name */
|
||||
.fvtt-wasteland.item {
|
||||
/* Background pour toute la fiche d'item */
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
/* AppV2 - Remove window content padding */
|
||||
.window-content {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* AppV2 - Main section structure */
|
||||
section {
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat-y;
|
||||
color: black;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* AppV2 Item Sheets - Disabled inputs readability */
|
||||
input:disabled,
|
||||
select:disabled {
|
||||
color: #000000;
|
||||
opacity: 0.8;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* Inputs and selects styling */
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select {
|
||||
color: #000000;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
border: 1px solid #999999;
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
font-family: "Charlemagne", serif;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
textarea {
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0 4px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
border-bottom: 1px solid #999;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sheet-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0.5rem;
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.item-sheet-img {
|
||||
flex: 0 0 100px;
|
||||
height: 100px;
|
||||
border: 2px solid #999;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.item-sheet-title {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 1.5rem;
|
||||
border-bottom: none;
|
||||
|
||||
input {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
font-family: "Charlemagne", serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.item-subtitle {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
/* Navigation tabs - Modern style */
|
||||
nav.tabs {
|
||||
display: flex;
|
||||
border-bottom: 2px solid #403f3e;
|
||||
margin: 0;
|
||||
padding: 4px 8px;
|
||||
background: linear-gradient(to bottom, #2a2520 0%, #1a1510 100%);
|
||||
flex: 0 0 auto;
|
||||
gap: 4px;
|
||||
|
||||
a.item {
|
||||
padding: 8px 16px;
|
||||
color: rgba(218, 218, 218, 0.85);
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px 6px 0 0;
|
||||
font-family: "Charlemagne", serif;
|
||||
font-size: 0.9rem;
|
||||
font-weight: normal;
|
||||
transition: all 0.3s ease;
|
||||
background: rgba(64, 63, 62, 0.3);
|
||||
min-width: 80px;
|
||||
text-align: center;
|
||||
|
||||
i {
|
||||
display: none; // Hide icons for cleaner look
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(74, 4, 4, 0.4);
|
||||
color: #f5f5f5;
|
||||
border-color: rgba(218, 218, 218, 0.2);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: linear-gradient(to bottom, #4a0404 0%, #3a0303 100%);
|
||||
border: 1px solid transparent;
|
||||
color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Tab content */
|
||||
.tab {
|
||||
display: none;
|
||||
padding: 8px 12px;
|
||||
overflow-y: auto;
|
||||
flex: 1 1 auto;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sheet body - scrollable content */
|
||||
.sheet-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 1rem;
|
||||
|
||||
&[data-tab] {
|
||||
display: none;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dans l'onglet details, les form-group sont horizontaux par défaut */
|
||||
&[data-tab="details"] {
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: #464331;
|
||||
flex: 0 0 auto;
|
||||
min-width: 160px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select,
|
||||
textarea {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
/* Checkbox avec label après (pas avant) */
|
||||
&:has(input[type="checkbox"]:first-child) {
|
||||
label {
|
||||
min-width: auto;
|
||||
flex: 1;
|
||||
order: 2;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
order: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Exception: quand le label contient lui-même le checkbox */
|
||||
label:has(input[type="checkbox"]) {
|
||||
min-width: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pour les sections avec grilles, garder le comportement vertical */
|
||||
.grid .form-group {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.25rem;
|
||||
|
||||
label {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Form groups - comportement par défaut pour autres onglets */
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: #464331;
|
||||
}
|
||||
|
||||
&.horizontal {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
label {
|
||||
flex: 0 0 auto;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
input, select, textarea {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Grid layouts */
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
&.grid-2col {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
&.grid-3col {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
&.grid-4col {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Editor content */
|
||||
.editor-content {
|
||||
min-height: 200px;
|
||||
border: 1px solid #999;
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Actions buttons */
|
||||
.item-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
padding-top: 0.5rem;
|
||||
border-top: 1px solid #999;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 0.5rem 1rem;
|
||||
background: rgba(74, 4, 4, 0.8);
|
||||
color: white;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-family: "Charlemagne", serif;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(74, 4, 4, 1);
|
||||
box-shadow: 0 0 8px rgba(74, 4, 4, 0.6);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Rollable elements */
|
||||
.rollable {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #ff6600;
|
||||
text-shadow: 0 0 8px rgba(255, 102, 0, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Item-specific sections */
|
||||
.item-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
|
||||
.detail-section {
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid #999;
|
||||
border-radius: 4px;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
padding-bottom: 0.25rem;
|
||||
border-bottom: 1px solid #999;
|
||||
font-size: 1.1rem;
|
||||
color: #2a1510;
|
||||
font-family: "Charlemagne", serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Specific item type styles */
|
||||
.fvtt-wasteland.item {
|
||||
&.arme-content,
|
||||
&.bouclier-content {
|
||||
.weapon-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5rem;
|
||||
|
||||
.stat-box {
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid #999;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.competence-content {
|
||||
.predilections-container {
|
||||
margin-top: 0.5rem;
|
||||
|
||||
.no-predilections {
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
color: #999;
|
||||
padding: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.predilections-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 0.75rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
|
||||
.predilection-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(42, 37, 32, 0.3);
|
||||
border: 1px solid rgba(106, 6, 6, 0.3);
|
||||
border-radius: 4px;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(42, 37, 32, 0.5);
|
||||
border-color: rgba(106, 6, 6, 0.5);
|
||||
}
|
||||
|
||||
.predilection-main {
|
||||
flex: 1;
|
||||
|
||||
.predilection-name {
|
||||
width: 100%;
|
||||
padding: 0.375rem 0.5rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
font-family: inherit;
|
||||
|
||||
&::placeholder {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #6a0606;
|
||||
box-shadow: 0 0 0 2px rgba(106, 6, 6, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.predilection-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
flex-shrink: 0;
|
||||
|
||||
.predilection-used {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 0.9rem;
|
||||
color: rgba(218, 218, 218, 0.85);
|
||||
}
|
||||
|
||||
&:hover span {
|
||||
color: rgba(218, 218, 218, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.predilection-delete {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
background: rgba(106, 6, 6, 0.6);
|
||||
border: 1px solid rgba(106, 6, 6, 0.8);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
i {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(106, 6, 6, 0.9);
|
||||
border-color: #6a0606;
|
||||
transform: scale(1.05);
|
||||
|
||||
i {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-predilection-btn {
|
||||
width: 100%;
|
||||
padding: 0.5rem 1rem;
|
||||
background: linear-gradient(to bottom, #4a0404 0%, #3a0303 100%);
|
||||
border: 1px solid #6a0606;
|
||||
border-radius: 4px;
|
||||
color: rgba(218, 218, 218, 0.95);
|
||||
font-family: "Charlemagne", serif;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
i {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, #5a0505 0%, #4a0404 100%);
|
||||
border-color: #8a0808;
|
||||
color: #fff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
311
less/roll-dialog-styles.less
Normal file
@@ -0,0 +1,311 @@
|
||||
/* ============================================ */
|
||||
/* WASTELAND ROLL DIALOG STYLES */
|
||||
/* ============================================ */
|
||||
|
||||
.wasteland-roll-dialog {
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
|
||||
|
||||
.window-content {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: linear-gradient(to bottom, #4a0404 0%, #3a0303 100%);
|
||||
border-bottom: 2px solid #6a0606;
|
||||
margin: -0.5rem -0.5rem 0.5rem -0.5rem;
|
||||
|
||||
.actor-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 2px solid #6a0606;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
flex: 1;
|
||||
color: #f5f5f5;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 0.15rem 0;
|
||||
font-size: 1rem;
|
||||
font-family: "Charlemagne", serif;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.competence-name {
|
||||
font-size: 0.85rem;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-style: italic;
|
||||
|
||||
.attribut-info {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: 0 0.5rem 0.5rem 0.5rem;
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 0.4rem;
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 0.2rem;
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
color: #2a1510;
|
||||
font-family: "Charlemagne", serif;
|
||||
}
|
||||
|
||||
select,
|
||||
input[type="number"] {
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid #6a0606;
|
||||
border-radius: 3px;
|
||||
padding: 0.3rem 0.4rem;
|
||||
font-size: 0.85rem;
|
||||
color: #1a1510;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
border-color: #aa0a0a;
|
||||
box-shadow: 0 0 4px rgba(170, 10, 10, 0.3);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modifiers-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.attributes-section {
|
||||
background: rgba(106, 6, 6, 0.1);
|
||||
border: 1px solid #6a0606;
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
label {
|
||||
color: #6a0606;
|
||||
}
|
||||
}
|
||||
|
||||
.special-option {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(106, 6, 6, 0.05);
|
||||
border: 2px solid #6a0606;
|
||||
border-radius: 4px;
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&.highlight {
|
||||
span {
|
||||
font-weight: bold;
|
||||
color: #6a0606;
|
||||
font-family: "Charlemagne", serif;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
cursor: pointer;
|
||||
accent-color: #6a0606;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
font-size: 0.85rem;
|
||||
color: #2a1510;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Weapon Section */
|
||||
.weapon-section {
|
||||
background: rgba(139, 101, 8, 0.1);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(139, 101, 8, 0.4);
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
.weapon-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.4rem 0.5rem;
|
||||
background: rgba(139, 101, 8, 0.15);
|
||||
border-radius: 3px;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
.weapon-label {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: #2a1510;
|
||||
font-family: "Charlemagne", serif;
|
||||
}
|
||||
|
||||
.weapon-bonus {
|
||||
font-size: 0.85rem;
|
||||
color: #8b0000;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.defense-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.4rem 0.5rem;
|
||||
background: rgba(0, 100, 0, 0.1);
|
||||
border-radius: 3px;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
.defense-label {
|
||||
font-size: 0.85rem;
|
||||
color: #2a1510;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.defense-value {
|
||||
font-size: 1rem;
|
||||
color: #006400;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Combat Modifiers */
|
||||
.combat-modifiers,
|
||||
.ranged-combat-section {
|
||||
background: rgba(139, 69, 19, 0.1);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(139, 69, 19, 0.4);
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
color: #2a1510;
|
||||
font-size: 0.9rem;
|
||||
font-weight: bold;
|
||||
font-family: "Charlemagne", serif;
|
||||
text-transform: uppercase;
|
||||
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.3rem 0.4rem;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 0.3rem;
|
||||
transition: background 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
accent-color: #8b4513;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #2a1510;
|
||||
font-size: 0.85rem;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.info-message {
|
||||
padding: 0.4rem 0.6rem;
|
||||
background: rgba(201, 168, 106, 0.2);
|
||||
border-left: 3px solid rgba(201, 168, 106, 0.8);
|
||||
border-radius: 3px;
|
||||
font-size: 0.85rem;
|
||||
color: #2a1510;
|
||||
margin-bottom: 0.5rem;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.modifiers-columns {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.3rem 0.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Styles pour les boutons du dialog
|
||||
.dialog-buttons {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
padding: 0.5rem;
|
||||
border-top: 1px solid #6a0606;
|
||||
margin: 0.5rem -0.5rem -0.5rem -0.5rem;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: linear-gradient(to bottom, #4a0404 0%, #3a0303 100%);
|
||||
border: 1px solid #6a0606;
|
||||
border-radius: 3px;
|
||||
color: #f5f5f5;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
font-family: "Charlemagne", serif;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, #5a0505 0%, #4a0404 100%);
|
||||
box-shadow: 0 0 6px rgba(106, 6, 6, 0.6);
|
||||
}
|
||||
|
||||
&.default {
|
||||
border-width: 2px;
|
||||
border-color: #aa0a0a;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1365
less/simple-converted.less
Normal file
8
less/wasteland.less
Normal file
@@ -0,0 +1,8 @@
|
||||
// Main LESS file for Wasteland system
|
||||
// Importing base styles and component-specific styles
|
||||
|
||||
@import "simple-converted";
|
||||
@import "item-styles";
|
||||
@import "actor-styles";
|
||||
@import "roll-dialog-styles";
|
||||
@import "chat-styles";
|
||||
27
modules/applications/sheets/_module.mjs
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Index des applications AppV2 pour Wasteland
|
||||
* Ce fichier centralise tous les exports des applications
|
||||
*/
|
||||
|
||||
// Applications de feuilles d'acteurs
|
||||
export { default as WastelandPersonnageSheet } from './wasteland-personnage-sheet.mjs';
|
||||
export { default as WastelandCreatureSheet } from './wasteland-creature-sheet.mjs';
|
||||
|
||||
// Applications de feuilles d'items
|
||||
export { default as WastelandArmeSheet } from './wasteland-arme-sheet.mjs';
|
||||
export { default as WastelandArtifexSheet } from './wasteland-artifex-sheet.mjs';
|
||||
export { default as WastelandBouclierSheet } from './wasteland-bouclier-sheet.mjs';
|
||||
export { default as WastelandCapaciteSheet } from './wasteland-capacite-sheet.mjs';
|
||||
export { default as WastelandCharmeSheet } from './wasteland-charme-sheet.mjs';
|
||||
export { default as WastelandCompetenceSheet } from './wasteland-competence-sheet.mjs';
|
||||
export { default as WastelandDonSheet } from './wasteland-don-sheet.mjs';
|
||||
export { default as WastelandEquipementSheet } from './wasteland-equipement-sheet.mjs';
|
||||
export { default as WastelandHeritageSheet } from './wasteland-heritage-sheet.mjs';
|
||||
export { default as WastelandHubrisSheet } from './wasteland-hubris-sheet.mjs';
|
||||
export { default as WastelandMetierSheet } from './wasteland-metier-sheet.mjs';
|
||||
export { default as WastelandMonnaieSheet } from './wasteland-monnaie-sheet.mjs';
|
||||
export { default as WastelandMutationSheet } from './wasteland-mutation-sheet.mjs';
|
||||
export { default as WastelandOrigineSheet } from './wasteland-origine-sheet.mjs';
|
||||
export { default as WastelandPeupleSheet } from './wasteland-peuple-sheet.mjs';
|
||||
export { default as WastelandPouvoirSheet } from './wasteland-pouvoir-sheet.mjs';
|
||||
export { default as WastelandProtectionSheet } from './wasteland-protection-sheet.mjs';
|
||||
382
modules/applications/sheets/base-actor-sheet.mjs
Normal file
@@ -0,0 +1,382 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
import { WastelandUtility } from "../../wasteland-utility.js"
|
||||
|
||||
export default class WastelandActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
/**
|
||||
* Different sheet modes.
|
||||
* @enum {number}
|
||||
*/
|
||||
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-wasteland", "sheet", "actor"],
|
||||
position: {
|
||||
width: 650,
|
||||
height: 720,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
tabs: [
|
||||
{
|
||||
navSelector: 'nav[data-group="primary"]',
|
||||
contentSelector: "section.sheet-body",
|
||||
initial: "stats",
|
||||
},
|
||||
],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: WastelandActorSheet.#onEditImage,
|
||||
toggleSheet: WastelandActorSheet.#onToggleSheet,
|
||||
editItem: WastelandActorSheet.#onEditItem,
|
||||
deleteItem: WastelandActorSheet.#onDeleteItem,
|
||||
createItem: WastelandActorSheet.#onCreateItem,
|
||||
equipItem: WastelandActorSheet.#onEquipItem,
|
||||
modifyQuantity: WastelandActorSheet.#onModifyQuantity,
|
||||
incDecSante: WastelandActorSheet.#onIncDecSante,
|
||||
rollAttribut: WastelandActorSheet.#onRollAttribut,
|
||||
rollCompetence: WastelandActorSheet.#onRollCompetence,
|
||||
rollCharme: WastelandActorSheet.#onRollCharme,
|
||||
rollPouvoir: WastelandActorSheet.#onRollPouvoir,
|
||||
rollArmeOffensif: WastelandActorSheet.#onRollArmeOffensif,
|
||||
rollArmeDegats: WastelandActorSheet.#onRollArmeDegats,
|
||||
resetPredilections: WastelandActorSheet.#onResetPredilections,
|
||||
rollAssommer: WastelandActorSheet.#onRollAssommer,
|
||||
rollFuir: WastelandActorSheet.#onRollFuir,
|
||||
rollImmobiliser: WastelandActorSheet.#onRollImmobiliser,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Play' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPlayMode() {
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Edit' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isEditMode() {
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
*/
|
||||
tabGroups = { primary: "stats" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
|
||||
const context = {
|
||||
actor: actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
isEditable: this.isEditable,
|
||||
isEditMode: this.isEditMode,
|
||||
isPlayMode: this.isPlayMode,
|
||||
isGM: game.user.isGM,
|
||||
config: game.system.wasteland.config,
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true }),
|
||||
enrichedComportement: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.comportement || "", { async: true }),
|
||||
enrichedHabitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.habitat || "", { async: true }),
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
|
||||
// Handle edit-item-data changes
|
||||
this.element.querySelectorAll('.edit-item-data').forEach(element => {
|
||||
element.addEventListener('change', async (event) => {
|
||||
const target = event.currentTarget
|
||||
const itemElement = target.closest('[data-item-id]')
|
||||
if (!itemElement) return
|
||||
|
||||
const itemId = itemElement.dataset.itemId
|
||||
const itemType = itemElement.dataset.itemType
|
||||
const itemField = target.dataset.itemField
|
||||
const dataType = target.dataset.dtype
|
||||
const value = target.value
|
||||
|
||||
await this.document.editItemField(itemId, itemType, itemField, dataType, value)
|
||||
})
|
||||
})
|
||||
|
||||
// Activate tab navigation manually
|
||||
const nav = this.element.querySelector('nav.tabs[data-group]')
|
||||
if (nav) {
|
||||
const group = nav.dataset.group
|
||||
// Activate the current tab
|
||||
const activeTab = this.tabGroups[group] || "stats"
|
||||
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||
const tab = link.dataset.tab
|
||||
link.classList.toggle('active', tab === activeTab)
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
this.tabGroups[group] = tab
|
||||
this.render()
|
||||
})
|
||||
})
|
||||
|
||||
// Show/hide tab content
|
||||
this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => {
|
||||
content.classList.toggle('active', content.dataset.tab === activeTab)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop Workflow
|
||||
/**
|
||||
* Create drag-and-drop workflow handlers for this Application
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return []
|
||||
}
|
||||
|
||||
// #region Actions
|
||||
|
||||
/**
|
||||
* Handle editing the actor image
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onEditImage(event) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const filePicker = new FilePicker({
|
||||
type: "image",
|
||||
current: sheet.document.img,
|
||||
callback: (path) => {
|
||||
sheet.document.update({ img: path })
|
||||
},
|
||||
})
|
||||
filePicker.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle toggling the sheet mode
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onToggleSheet(event) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
sheet._sheetMode = sheet._sheetMode === sheet.constructor.SHEET_MODES.PLAY ? sheet.constructor.SHEET_MODES.EDIT : sheet.constructor.SHEET_MODES.PLAY
|
||||
sheet.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle editing an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onEditItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
const item = this.actor.items.get(itemId)
|
||||
if (item) item.sheet.render(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle deleting an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onDeleteItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
await WastelandUtility.confirmDelete(this, li)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle creating an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onCreateItem(event, target) {
|
||||
const itemType = target.dataset.type
|
||||
await this.actor.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle equipping an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onEquipItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
await this.actor.equipItem(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modifying item quantity
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onModifyQuantity(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
|
||||
const item = this.actor.items.get(itemId)
|
||||
if (!item) return
|
||||
|
||||
const qty = parseInt(target.dataset.qty) || 0
|
||||
const currentQty = item.system.quantite || 0
|
||||
const newQty = Math.max(0, currentQty + qty)
|
||||
|
||||
await item.update({ 'system.quantite': newQty })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modifying santé/psyché
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onIncDecSante(event, target) {
|
||||
const field = target.dataset.field
|
||||
const value = parseInt(target.dataset.value) || 0
|
||||
|
||||
if (field === 'psyche') {
|
||||
await this.actor.update({ 'system.psyche.value': this.actor.system.psyche.value + value })
|
||||
} else if (field === 'nonletaux') {
|
||||
await this.actor.update({ 'system.sante.nonletaux': this.actor.system.sante.nonletaux + value })
|
||||
} else if (field === 'letaux') {
|
||||
await this.actor.update({ 'system.sante.letaux': this.actor.system.sante.letaux + value })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling an attribute
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollAttribut(event, target) {
|
||||
const attrKey = target.dataset.attrKey
|
||||
await this.actor.rollAttribut(attrKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling a competence
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollCompetence(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
const attrKey = target.dataset.attrKey
|
||||
if (!itemId) return
|
||||
await this.actor.rollCompetence(attrKey, itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling a charme
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollCharme(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
await this.actor.rollCharme(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling a pouvoir
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollPouvoir(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
await this.actor.rollPouvoir(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling weapon attack
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollArmeOffensif(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
await this.actor.rollArmeOffensif(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling weapon damage
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollArmeDegats(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
await this.actor.rollArmeDegats(itemId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle resetting all predilections
|
||||
* @param {Event} event - The originating click event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onResetPredilections(event, target) {
|
||||
await this.actor.resetAllPredilections()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Assommer roll
|
||||
* @param {Event} event - The originating click event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollAssommer(event, target) {
|
||||
await this.actor.rollAssommer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Fuir roll
|
||||
* @param {Event} event - The originating click event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollFuir(event, target) {
|
||||
await this.actor.rollFuir()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Immobiliser roll
|
||||
* @param {Event} event - The originating click event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onRollImmobiliser(event, target) {
|
||||
await this.actor.rollImmobiliser()
|
||||
}
|
||||
}
|
||||
158
modules/applications/sheets/base-item-sheet.mjs
Normal file
@@ -0,0 +1,158 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class WastelandItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-wasteland", "item"],
|
||||
position: {
|
||||
width: 620,
|
||||
height: 600,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
tabs: [
|
||||
{
|
||||
navSelector: 'nav[data-group="primary"]',
|
||||
contentSelector: "section.sheet-body",
|
||||
initial: "description",
|
||||
},
|
||||
],
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: WastelandItemSheet.#onEditImage,
|
||||
postItem: WastelandItemSheet.#onPostItem,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @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 }),
|
||||
isEditMode: true,
|
||||
isEditable: this.isEditable,
|
||||
isGM: game.user.isGM,
|
||||
config: game.system.wasteland.config,
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
|
||||
// Activate tab navigation manually
|
||||
const nav = this.element.querySelector('nav.tabs[data-group]')
|
||||
if (nav) {
|
||||
const group = nav.dataset.group
|
||||
// Activate the current tab
|
||||
const activeTab = this.tabGroups[group] || "description"
|
||||
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||
const tab = link.dataset.tab
|
||||
link.classList.toggle('active', tab === activeTab)
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
this.tabGroups[group] = tab
|
||||
this.render()
|
||||
})
|
||||
})
|
||||
|
||||
// Show/hide tab content
|
||||
this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => {
|
||||
content.classList.toggle('active', content.dataset.tab === activeTab)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop Workflow
|
||||
/**
|
||||
* Create drag-and-drop workflow handlers for this Application
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return []
|
||||
}
|
||||
|
||||
// #region Actions
|
||||
|
||||
/**
|
||||
* Handle editing the item image
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onEditImage(event) {
|
||||
event.preventDefault()
|
||||
const filePicker = new FilePicker({
|
||||
type: "image",
|
||||
current: this.document.img,
|
||||
callback: (path) => {
|
||||
this.document.update({ img: path })
|
||||
},
|
||||
})
|
||||
filePicker.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posting the item to chat
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onPostItem(event) {
|
||||
event.preventDefault()
|
||||
|
||||
// Prepare chat data
|
||||
const chatData = {
|
||||
name: this.document.name,
|
||||
img: this.document.img,
|
||||
type: this.document.type,
|
||||
system: this.document.system,
|
||||
}
|
||||
|
||||
// Add actor reference if item is owned
|
||||
if (this.document.actor) {
|
||||
chatData.actor = { id: this.document.actor.id }
|
||||
}
|
||||
|
||||
// Don't post any image for the item if the default image is used
|
||||
if (chatData.img && chatData.img.includes("/blank.png")) {
|
||||
chatData.img = null
|
||||
}
|
||||
|
||||
// JSON object for easy creation
|
||||
chatData.jsondata = JSON.stringify({
|
||||
compendium: "postedItem",
|
||||
payload: chatData,
|
||||
})
|
||||
|
||||
// Render the chat card template
|
||||
const html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-wasteland/templates/post-item.hbs', chatData)
|
||||
|
||||
// Create the chat message
|
||||
const chatOptions = {
|
||||
user: game.user.id,
|
||||
content: html,
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.document.actor })
|
||||
}
|
||||
|
||||
ChatMessage.create(chatOptions)
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/wasteland-arme-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandArmeSheet extends WastelandItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["arme"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["arme-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-wasteland/templates/item-arme-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "details",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#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
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/wasteland-artifex-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandArtifexSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["artifex"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["artifex-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-artifex-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/wasteland-bouclier-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandBouclierSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["bouclier"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["bouclier-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-bouclier-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
|
||||
}
|
||||
}
|
||||
32
modules/applications/sheets/wasteland-capacite-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandCapaciteSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["capacite"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["capacite-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-capacite-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
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/wasteland-charme-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandCharmeSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["charme"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["charme-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-charme-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
|
||||
}
|
||||
}
|
||||
72
modules/applications/sheets/wasteland-competence-sheet.mjs
Normal file
@@ -0,0 +1,72 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandCompetenceSheet extends WastelandItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["competence"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["competence-content"],
|
||||
},
|
||||
actions: {
|
||||
"add-predilection": this.#onAddPredilection,
|
||||
"delete-predilection": this.#onDeletePredilection
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-wasteland/templates/item-competence-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
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
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle adding a new predilection
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The button element
|
||||
*/
|
||||
static async #onAddPredilection(event, target) {
|
||||
const predilections = foundry.utils.duplicate(this.document.system.predilections)
|
||||
predilections.push({ name: "Nouvelle prédilection", used: false })
|
||||
await this.document.update({ "system.predilections": predilections })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle deleting a predilection
|
||||
* @param {PointerEvent} event - The triggering event
|
||||
* @param {HTMLElement} target - The delete button element
|
||||
*/
|
||||
static async #onDeletePredilection(event, target) {
|
||||
const index = parseInt(target.dataset.index)
|
||||
const predilections = foundry.utils.duplicate(this.document.system.predilections)
|
||||
predilections.splice(index, 1)
|
||||
await this.document.update({ "system.predilections": predilections })
|
||||
}
|
||||
}
|
||||
40
modules/applications/sheets/wasteland-creature-sheet.mjs
Normal file
@@ -0,0 +1,40 @@
|
||||
import WastelandActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class WastelandCreatureSheet extends WastelandActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "creature"],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "Feuille de Créature",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-wasteland/templates/actor-creature-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "stats",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add creature-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.capacites = foundry.utils.duplicate(actor.getCapacites())
|
||||
context.combat = actor.getCombatValues()
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
32
modules/applications/sheets/wasteland-don-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandDonSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["don"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["don-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-don-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
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/wasteland-equipement-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandEquipementSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["equipement"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["equipement-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-equipement-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
|
||||
}
|
||||
}
|
||||
32
modules/applications/sheets/wasteland-heritage-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandHeritageSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["heritage"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["heritage-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-heritage-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
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/wasteland-hubris-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandHubrisSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["hubris"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["hubris-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-hubris-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
|
||||
}
|
||||
}
|
||||
32
modules/applications/sheets/wasteland-metier-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandMetierSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["metier"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["metier-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-metier-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
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/wasteland-monnaie-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandMonnaieSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["monnaie"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["monnaie-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-monnaie-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
|
||||
}
|
||||
}
|
||||
32
modules/applications/sheets/wasteland-mutation-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandMutationSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["mutation"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["mutation-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-mutation-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/wasteland-origine-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandOrigineSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["origine"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["origine-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-origine-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
|
||||
}
|
||||
}
|
||||
59
modules/applications/sheets/wasteland-personnage-sheet.mjs
Normal file
@@ -0,0 +1,59 @@
|
||||
import WastelandActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class WastelandPersonnageSheet extends WastelandActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes, "personnage"],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "Feuille de Personnage",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-wasteland/templates/actor-personnage-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "stats",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add personnage-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.pouvoirs = foundry.utils.duplicate(actor.getPouvoirs())
|
||||
context.dons = foundry.utils.duplicate(actor.getDons())
|
||||
context.hubrises = foundry.utils.duplicate(actor.getHubris())
|
||||
context.tours = foundry.utils.duplicate(actor.getTours())
|
||||
context.artifex = foundry.utils.duplicate(actor.getArtifex())
|
||||
context.charmes = foundry.utils.duplicate(actor.getCharmes())
|
||||
context.peuple = foundry.utils.duplicate(actor.getPeuple() || {})
|
||||
context.origine = foundry.utils.duplicate(actor.getOrigine() || {})
|
||||
context.heritage = foundry.utils.duplicate(actor.getHeritage() || {})
|
||||
context.metier = foundry.utils.duplicate(actor.getMetier() || {})
|
||||
context.combat = actor.getCombatValues()
|
||||
context.capacites = foundry.utils.duplicate(actor.getCapacites())
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments())
|
||||
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
|
||||
context.mutations = foundry.utils.duplicate(actor.getMutations())
|
||||
|
||||
// Enrich HTML fields for biodata
|
||||
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.notes || "", { async: true })
|
||||
context.enrichedGMNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.gmnotes || "", { async: true })
|
||||
context.enrichedSequelles = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.sequelles || "", { async: true })
|
||||
context.enrichedTraumatismes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.traumatismes || "", { async: true })
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
32
modules/applications/sheets/wasteland-peuple-sheet.mjs
Normal file
@@ -0,0 +1,32 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandPeupleSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["peuple"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["peuple-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-peuple-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
|
||||
}
|
||||
}
|
||||
33
modules/applications/sheets/wasteland-pouvoir-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandPouvoirSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["pouvoir"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["pouvoir-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-pouvoir-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/wasteland-protection-sheet.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
import WastelandItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class WastelandProtectionSheet extends WastelandItemSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["protection"],
|
||||
position: { width: 620 },
|
||||
window: { contentClasses: ["protection-content"] },
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: { template: "systems/fvtt-wasteland/templates/item-protection-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
|
||||
}
|
||||
}
|
||||
156
modules/applications/wasteland-roll-dialog.mjs
Normal file
@@ -0,0 +1,156 @@
|
||||
import { WastelandUtility } from "../wasteland-utility.js"
|
||||
|
||||
/**
|
||||
* Dialogue de jet de dé pour Wasteland - Version DialogV2
|
||||
*/
|
||||
export class WastelandRollDialog {
|
||||
|
||||
/**
|
||||
* Create and display the roll dialog
|
||||
* @param {WastelandActor} actor - The actor making the roll
|
||||
* @param {Object} rollData - Data for the roll
|
||||
* @returns {Promise<WastelandRollDialog>}
|
||||
*/
|
||||
static async create(actor, rollData) {
|
||||
// Préparer le contexte pour le template
|
||||
const context = {
|
||||
...rollData,
|
||||
difficulte: String(rollData.difficulte || 0),
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
config: game.system.wasteland.config,
|
||||
}
|
||||
|
||||
// Rendre le template en HTML
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-wasteland/templates/roll-dialog-v2.hbs",
|
||||
context
|
||||
)
|
||||
|
||||
// Utiliser DialogV2.wait avec le HTML rendu
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: { title: "Test de Capacité", icon: "fa-solid fa-dice-d20" },
|
||||
classes: ["wasteland-roll-dialog"],
|
||||
position: { width: 500 },
|
||||
modal: false,
|
||||
content,
|
||||
buttons: rollData.charme ? [
|
||||
{
|
||||
action: "roll",
|
||||
label: "Lancer",
|
||||
icon: "fa-solid fa-dice-d20",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
WastelandUtility.rollWasteland(rollData)
|
||||
}
|
||||
}
|
||||
] : [
|
||||
{
|
||||
action: "rolld10",
|
||||
label: "Lancer 1d10",
|
||||
icon: "fa-solid fa-dice-d10",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
rollData.mainDice = "1d10"
|
||||
WastelandUtility.rollWasteland(rollData)
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "rolld20",
|
||||
label: "Lancer 1d20",
|
||||
icon: "fa-solid fa-dice-d20",
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
rollData.mainDice = "1d20"
|
||||
WastelandUtility.rollWasteland(rollData)
|
||||
}
|
||||
},
|
||||
],
|
||||
rejectClose: false,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre à jour rollData avec les valeurs du formulaire
|
||||
* @param {Object} rollData - L'objet rollData à mettre à jour
|
||||
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
|
||||
* @param {WastelandActor} actor - L'acteur pour récupérer les attributs
|
||||
* @private
|
||||
*/
|
||||
static _updateRollDataFromForm(rollData, formElements, actor) {
|
||||
// Attributs
|
||||
if (formElements.attrKey) {
|
||||
rollData.attrKey = formElements.attrKey.value
|
||||
if (rollData.attrKey !== "tochoose" && actor) {
|
||||
rollData.attr = foundry.utils.duplicate(actor.system.attributs[rollData.attrKey])
|
||||
}
|
||||
}
|
||||
|
||||
// Modificateurs de base
|
||||
if (formElements.difficulte) {
|
||||
rollData.difficulte = Number(formElements.difficulte.value)
|
||||
}
|
||||
if (formElements.modificateur) {
|
||||
rollData.modificateur = Number(formElements.modificateur.value)
|
||||
}
|
||||
|
||||
// Charme
|
||||
if (formElements.charmeDice) {
|
||||
rollData.charmeDice = String(formElements.charmeDice.value)
|
||||
}
|
||||
|
||||
// Combat mêlée
|
||||
if (formElements.typeAttaque) {
|
||||
rollData.typeAttaque = String(formElements.typeAttaque.value)
|
||||
rollData.typeAttaqueLabel = rollData.config.attaques[rollData.typeAttaque]
|
||||
}
|
||||
if (formElements.isMonte !== undefined) {
|
||||
rollData.isMonte = formElements.isMonte.checked
|
||||
}
|
||||
|
||||
// Combat distance
|
||||
if (formElements.visee !== undefined) {
|
||||
rollData.visee = formElements.visee.checked
|
||||
}
|
||||
if (formElements.cibleconsciente !== undefined) {
|
||||
rollData.cibleconsciente = formElements.cibleconsciente.checked
|
||||
}
|
||||
if (formElements.ciblecourt !== undefined) {
|
||||
rollData.ciblecourt = formElements.ciblecourt.checked
|
||||
}
|
||||
if (formElements.typeCouvert) {
|
||||
rollData.typeCouvert = String(formElements.typeCouvert.value)
|
||||
const couvert = rollData.config.couverts[rollData.typeCouvert]
|
||||
if (rollData.typeCouvert !== "aucun" && couvert) {
|
||||
rollData.typeCouvertLabel = couvert.name
|
||||
rollData.typeCouvertValue = couvert.value
|
||||
}
|
||||
}
|
||||
|
||||
// Désavantages (avantages tactiques)
|
||||
if (!rollData.desavantages) rollData.desavantages = {}
|
||||
|
||||
if (formElements.cibleausol !== undefined) {
|
||||
rollData.desavantages.cibleausol = formElements.cibleausol.checked
|
||||
}
|
||||
if (formElements.cibledesarmee !== undefined) {
|
||||
rollData.desavantages.cibledesarmee = formElements.cibledesarmee.checked
|
||||
}
|
||||
if (formElements.ciblerestreint !== undefined) {
|
||||
rollData.desavantages.ciblerestreint = formElements.ciblerestreint.checked
|
||||
}
|
||||
if (formElements.cibleimmobilisée !== undefined) {
|
||||
rollData.desavantages.cibleimmobilisée = formElements.cibleimmobilisée.checked
|
||||
}
|
||||
if (formElements.ciblesurplomb !== undefined) {
|
||||
rollData.desavantages.ciblesurplomb = formElements.ciblesurplomb.checked
|
||||
}
|
||||
|
||||
// Double D20
|
||||
if (formElements.doubleD20 !== undefined) {
|
||||
rollData.doubleD20 = formElements.doubleD20.checked
|
||||
}
|
||||
}
|
||||
}
|
||||
26
modules/models/arme.mjs
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Data model pour les armes
|
||||
*/
|
||||
export default class ArmeDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
typearme: new fields.StringField({ initial: "" }),
|
||||
isdefense: new fields.BooleanField({ initial: false }),
|
||||
bonusmaniementoff: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusmaniementdef: new fields.NumberField({ initial: 0, integer: true }),
|
||||
nobonusdegats: new fields.BooleanField({ initial: false }),
|
||||
degats: new fields.StringField({ initial: "" }),
|
||||
nonletaux: new fields.BooleanField({ initial: false }),
|
||||
deuxmains: new fields.BooleanField({ initial: false }),
|
||||
courte: new fields.NumberField({ initial: 0, integer: true }),
|
||||
moyenne: new fields.NumberField({ initial: 0, integer: true }),
|
||||
longue: new fields.NumberField({ initial: 0, integer: true }),
|
||||
tr: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
}
|
||||
18
modules/models/artifex.mjs
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Data model pour les artifex
|
||||
*/
|
||||
export default class ArtifexDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
artifextype: new fields.StringField({ initial: "vapeur" }),
|
||||
competence: new fields.StringField({ initial: "" }),
|
||||
complexite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
dureerealisation: new fields.StringField({ initial: "" }),
|
||||
tempsmiseenroute: new fields.StringField({ initial: "" }),
|
||||
defautcourant: new fields.StringField({ initial: "" }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
17
modules/models/bouclier.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Data model pour les boucliers
|
||||
*/
|
||||
export default class BouclierDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
bonusdefense: new fields.NumberField({ initial: 0, integer: true }),
|
||||
degats: new fields.StringField({ initial: "" }),
|
||||
nonletaux: new fields.BooleanField({ initial: false }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/capacite.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les capacités
|
||||
*/
|
||||
export default class CapaciteDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
25
modules/models/charme.mjs
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Data model pour les charmes
|
||||
*/
|
||||
export default class CharmeDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
charmetype: new fields.StringField({ initial: "tour" }),
|
||||
resultats: new fields.ArrayField(new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: -1, integer: true }),
|
||||
description: new fields.StringField({ initial: "" })
|
||||
}), {
|
||||
initial: [
|
||||
{ value: -1, description: "" },
|
||||
{ value: -1, description: "" },
|
||||
{ value: -1, description: "" },
|
||||
{ value: -1, description: "" },
|
||||
{ value: -1, description: "" },
|
||||
{ value: -1, description: "" }
|
||||
]
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
21
modules/models/competence.mjs
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Data model pour les compétences
|
||||
*/
|
||||
export default class CompetenceDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
attribut1: new fields.StringField({ initial: "" }),
|
||||
attribut2: new fields.StringField({ initial: "" }),
|
||||
attribut3: new fields.StringField({ initial: "" }),
|
||||
doublebonus: new fields.BooleanField({ initial: false }),
|
||||
predilections: new fields.ArrayField(new fields.SchemaField({
|
||||
name: new fields.StringField({ initial: "" }),
|
||||
description: new fields.StringField({ initial: "" }),
|
||||
used: new fields.BooleanField({ initial: false })
|
||||
}), { initial: [] })
|
||||
};
|
||||
}
|
||||
}
|
||||
99
modules/models/creature.mjs
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Data model pour les créatures
|
||||
*/
|
||||
export default class CreatureDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
// Template biodata
|
||||
biodata: new fields.SchemaField({
|
||||
name: new fields.StringField({ initial: "" }),
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
alignement: new fields.StringField({ initial: "" }),
|
||||
poids: new fields.StringField({ initial: "" }),
|
||||
taille: new fields.StringField({ initial: "" }),
|
||||
cheveux: new fields.StringField({ initial: "" }),
|
||||
sexe: new fields.StringField({ initial: "" }),
|
||||
yeux: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
habitat: new fields.StringField({ initial: "" }),
|
||||
comportement: new fields.StringField({ initial: "" }),
|
||||
psychemultiplier: new fields.NumberField({ initial: 1, integer: true }),
|
||||
notes: new fields.HTMLField({ initial: "" }),
|
||||
gmnotes: new fields.HTMLField({ initial: "" })
|
||||
}),
|
||||
// Template core
|
||||
terreur: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: -1, integer: true })
|
||||
}),
|
||||
protection: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
ressource: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||
attributs: new fields.SchemaField({
|
||||
adr: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Adresse" }),
|
||||
labelnorm: new fields.StringField({ initial: "adresse" }),
|
||||
abbrev: new fields.StringField({ initial: "adr" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pui: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Puissance" }),
|
||||
labelnorm: new fields.StringField({ initial: "puissance" }),
|
||||
abbrev: new fields.StringField({ initial: "pui" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
cla: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Clairvoyance" }),
|
||||
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
|
||||
abbrev: new fields.StringField({ initial: "cla" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Présence" }),
|
||||
labelnorm: new fields.StringField({ initial: "presence" }),
|
||||
abbrev: new fields.StringField({ initial: "pre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
tre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Trempe" }),
|
||||
labelnorm: new fields.StringField({ initial: "trempe" }),
|
||||
abbrev: new fields.StringField({ initial: "tre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
bonneaventure: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
actuelle: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
experience: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
eclat: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
sante: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
nonletaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
letaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
sequelles: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
psyche: new fields.SchemaField({
|
||||
fullmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
currentmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
traumatismes: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
combat: new fields.SchemaField({
|
||||
initbonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
|
||||
defensebonus: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/don.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les dons
|
||||
*/
|
||||
export default class DonDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
coutpsyche: new fields.NumberField({ initial: 0, integer: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
14
modules/models/equipement.mjs
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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: "" }),
|
||||
quantite: new fields.NumberField({ initial: 1, integer: true, min: 0 }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/heritage.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les héritages
|
||||
*/
|
||||
export default class HeritageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/hubris.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les hubris
|
||||
*/
|
||||
export default class HubrisDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
hubristype: new fields.StringField({ initial: "mental" })
|
||||
};
|
||||
}
|
||||
}
|
||||
27
modules/models/index.mjs
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Index des DataModels pour Wasteland
|
||||
* Ce fichier centralise tous les exports des modèles de données
|
||||
*/
|
||||
|
||||
// Modèles d'items
|
||||
export { default as ArmeDataModel } from './arme.mjs';
|
||||
export { default as BouclierDataModel } from './bouclier.mjs';
|
||||
export { default as CapaciteDataModel } from './capacite.mjs';
|
||||
export { default as CompetenceDataModel } from './competence.mjs';
|
||||
export { default as DonDataModel } from './don.mjs';
|
||||
export { default as EquipementDataModel } from './equipement.mjs';
|
||||
export { default as HeritageDataModel } from './heritage.mjs';
|
||||
export { default as MetierDataModel } from './metier.mjs';
|
||||
export { default as MonnaieDataModel } from './monnaie.mjs';
|
||||
export { default as OrigineDataModel } from './origine.mjs';
|
||||
export { default as ProtectionDataModel } from './protection.mjs';
|
||||
export { default as MutationDataModel } from './mutation.mjs';
|
||||
export { default as PouvoirDataModel } from './pouvoir.mjs';
|
||||
export { default as CharmeDataModel } from './charme.mjs';
|
||||
export { default as ArtifexDataModel } from './artifex.mjs';
|
||||
export { default as PeupleDataModel } from './peuple.mjs';
|
||||
export { default as HubrisDataModel } from './hubris.mjs';
|
||||
|
||||
// Modèles d'acteurs
|
||||
export { default as PersonnageDataModel } from './personnage.mjs';
|
||||
export { default as CreatureDataModel } from './creature.mjs';
|
||||
11
modules/models/metier.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les métiers
|
||||
*/
|
||||
export default class MetierDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
13
modules/models/monnaie.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Data model pour les monnaies
|
||||
*/
|
||||
export default class MonnaieDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
unite: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/mutation.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les mutations
|
||||
*/
|
||||
export default class MutationDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/origine.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les origines
|
||||
*/
|
||||
export default class OrigineDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
100
modules/models/personnage.mjs
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Data model pour les personnages
|
||||
*/
|
||||
export default class PersonnageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
// Template biodata
|
||||
biodata: new fields.SchemaField({
|
||||
name: new fields.StringField({ initial: "" }),
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
alignement: new fields.StringField({ initial: "" }),
|
||||
poids: new fields.StringField({ initial: "" }),
|
||||
taille: new fields.StringField({ initial: "" }),
|
||||
cheveux: new fields.StringField({ initial: "" }),
|
||||
sexe: new fields.StringField({ initial: "" }),
|
||||
yeux: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
habitat: new fields.StringField({ initial: "" }),
|
||||
comportement: new fields.StringField({ initial: "" }),
|
||||
psychemultiplier: new fields.NumberField({ initial: 1, integer: true }),
|
||||
notes: new fields.HTMLField({ initial: "" }),
|
||||
gmnotes: new fields.HTMLField({ initial: "" })
|
||||
}),
|
||||
// Template core
|
||||
terreur: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: -1, integer: true })
|
||||
}),
|
||||
protection: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
ressource: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||
attributs: new fields.SchemaField({
|
||||
adr: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Adresse" }),
|
||||
labelnorm: new fields.StringField({ initial: "adresse" }),
|
||||
abbrev: new fields.StringField({ initial: "adr" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pui: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Puissance" }),
|
||||
labelnorm: new fields.StringField({ initial: "puissance" }),
|
||||
abbrev: new fields.StringField({ initial: "pui" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
cla: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Clairvoyance" }),
|
||||
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
|
||||
abbrev: new fields.StringField({ initial: "cla" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Présence" }),
|
||||
labelnorm: new fields.StringField({ initial: "presence" }),
|
||||
abbrev: new fields.StringField({ initial: "pre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
tre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Trempe" }),
|
||||
labelnorm: new fields.StringField({ initial: "trempe" }),
|
||||
abbrev: new fields.StringField({ initial: "tre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
bonneaventure: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
actuelle: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
experience: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
eclat: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
sante: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
nonletaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
letaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
sequelles: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
psyche: new fields.SchemaField({
|
||||
fullmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
currentmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
traumatismes: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
combat: new fields.SchemaField({
|
||||
initbonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
|
||||
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
monte: new fields.BooleanField({ initial: false })
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||