11 Commits

Author SHA1 Message Date
uberwald ec0e522145 Add ranged attacks for monsters
Release Creation / build (release) Successful in 1m13s
2026-04-29 22:24:42 +02:00
uberwald 8123b53f75 Import de personnages du précédent système
Release Creation / build (release) Successful in 1m21s
2026-04-27 22:29:49 +02:00
uberwald 58478d56ea Amélioration du rendu des polices
Release Creation / build (release) Successful in 1m22s
2026-04-27 21:54:04 +02:00
uberwald a99eeaccba Corrections sur font, again v3
Release Creation / build (release) Successful in 1m35s
2026-04-27 17:40:59 +02:00
uberwald 2ab380786f Correction sur O dans police de titre, step2
Release Creation / build (release) Successful in 1m12s
2026-04-27 06:39:11 +02:00
uberwald c3ce628e24 Ameliorations CSS et font diverses
Release Creation / build (release) Successful in 1m25s
2026-04-26 22:44:23 +02:00
uberwald 8e5fb9aca1 Correction sur jauge de destin
Release Creation / build (release) Successful in 1m26s
2026-04-16 22:26:44 +02:00
uberwald 1b2a74969d Update READM.md 2026-04-16 08:39:52 +02:00
uberwald 98a6a41078 Ajout README.md 2026-04-15 11:53:52 +02:00
uberwald c73136b3c9 Ajout README.md 2026-04-15 11:41:44 +02:00
uberwald 49996104ce Roll and styles update
Release Creation / build (release) Failing after 1m17s
2026-04-15 02:16:51 +02:00
68 changed files with 4541 additions and 331 deletions
+84
View File
@@ -0,0 +1,84 @@
# Célestopol 1922 — Système FoundryVTT
Système [Foundry VTT](https://foundryvtt.com) pour **Célestopol 1922**, le jeu de rôle d'[Antre Monde Éditions](https://antremonde.fr).
Copyright 2025-2026 Antre Monde Editions All rights reserved
Celestopol 1922 is a game written by Emmanuel Chastellière and Julien Arnaud. The authors retain their moral rights to this work in both print and digital formats.
This system for FoundryVTT has been approved and authorized by Antre-Monde Edition
---
## ✨ Fonctionnalités
### Personnages joueurs (PJ)
- **4 attributs** (Âme, Corps, Cœur, Esprit) × **4 compétences** chacun (16 compétences au total)
- Gestion des **Blessures** (8 niveaux avec malus automatique aux jets)
- Suivi du **Destin** et du **Spleen** (jauges à 8 crans)
- **Anomalies** : 9 types, déclenchées sur certains résultats de dé
- **Factions** : 8 factions standard + 2 personnalisées, avec aspects liés
- **Équipement** : armes, armures, équipements génériques
- Onglets dédiés : Principal · Compétences · Factions · Équipement · Combat · Biographie
### Personnages non-joueurs (PNJ)
- Fiche simplifiée : compétences, blessures, équipement, biographie
### Items
- **Arme** : mêlée ou à distance, modificateurs de portée
- **Armure** : protection et malus éventuels
- **Aspect de faction** : lié à une faction, bonus / usage limité
- **Anomalie** : type, usages, description
- **Équipement** générique
### Mécanique de jet de désde démonstration
- **Pool de d6** : `max(1, compétence + malus_blessures)` dés
- **Bonus Phase de Lune** : automatique selon la phase en cours (0 à +3)
- **Modificateurs** : difficulté et bonus libres via DialogV2
- Seuil de succès standard : **7**
- Résultats spéciaux : **Brio** (+destin), **Contrecoup** (destin), **Triomphe** (+anomalie/spleen), **Catastrophe** (anomalie/+spleen)
### Dé de la Lune
- Jet de dé de lune indépendant (menu contextuel du token)
- 8 faces : Nouvelle Lune, Premiers Croissants, Dernier Croissant, Gibbeuses ×2, Pleine Lune, Lune de Feu, Lune Noire
- Sur certains résultats : **choix de contrepartie** via pop-up (perte d'anomalie, spleen, ou échec catastrophique)
- Carte de résultat avec boutons d'application directe
### Combat
- **Initiative Célestopol** : jet d'initiative avec dé spécial, insertion dans le tracker
- Attaque avec calcul automatique dommages / protection
- Chat de combat avec récapitulatif des dégâts et blessures appliqués
### Compendiums inclus
| Pack | Contenu |
| ------------ | ------------------------------ |
| Anomalies | Les 8 anomalies du jeu de base |
| Prétirés | 8 personnages prêts à jouer |
| Aides de jeu | Aide du système |
| Scènes | Scènes utiles |
## 🎨 Charte graphique
- Police de titre : **CopaseticNF** (Regular + Bold)
- Vert sombre en-tête : `#0c4c0c`
- Orange texte : `#e07b00`
- Fond parchemin : `#f0e8d4`
- Texture en-tête : `assets/ui/fond_cadrille.jpg`
---
## 👤 Auteur
**LeRatierBretonnien / Uberwald**
- Discord : `LeRatierBretonnien`
- Site : [uberwald.me](https://www.uberwald.me)
---
## 📜 Licence
Copyright 2025 Antre Monde Editions All rights reserved
Celestopol 1922 is a game written by Emmanuel Chastellière and Julien Arnaud. The authors retain their moral rights to this work in both print and digital formats.
This system for FoundryVTT has been approved and authorized by Antre-Monde Edition.
+368
View File
@@ -0,0 +1,368 @@
#!/usr/bin/env python3
"""
convert-old-system.py
Convertit les fichiers JSON d'acteurs exportés de l'ancien système Célestopol 1922
(system id: celestopol1922) vers le format du nouveau système (fvtt-celestopol).
Usage:
python3 convert-old-system.py <fichier.json> [fichier2.json ...]
Le fichier converti est écrit à côté du fichier source sous le nom :
<nom>-converted.json
"""
import json
import os
import re
import sys
import uuid
# ─── Mapping des types d'anomalies (préfixe "CEL1922.opt." → clé nouveau système) ─────
ANOMALY_TYPE_MAP = {
"none": "none",
"entropie": "entropie",
"communicationaveclesmorts": "communicationaveclesmorts",
"illusion": "illusion",
"suggestion": "suggestion",
"tarotdivinatoire": "tarotdivinatoire",
"telekinesie": "telekinesie",
"telepathie": "telepathie",
"voyageastral": "voyageastral",
}
# Clé anomaly vide → "none"
VALID_ANOMALY_TYPES = set(ANOMALY_TYPE_MAP.values())
# ─── Domaines (stats) ──────────────────────────────────────────────────────────────────
STATS = ["ame", "corps", "coeur", "esprit"]
# Compétences par domaine (dans l'ordre du nouveau système)
SKILLS = {
"ame": ["artifice", "attraction", "coercition", "faveur"],
"corps": ["echauffouree", "effacement", "mobilite", "prouesse"],
"coeur": ["appreciation", "arts", "inspiration", "traque"],
"esprit": ["instruction", "mtechnologique", "raisonnement", "traitement"],
}
def make_id():
"""Génère un identifiant Foundry-compatible (16 chars hex)."""
return uuid.uuid4().hex[:16]
def strip_prefix(label: str) -> str:
"""Extrait la clé depuis 'CEL1922.opt.<clé>'."""
return label.split(".")[-1]
def resolve_anomaly_type(old_system: dict) -> str:
"""
Résout le type d'anomalie depuis l'ancien système.
old_system.anomaly est un int (index dans anomalytypes[]).
"""
anomalytypes = old_system.get("skill", {}).get("anomalytypes", [])
idx = old_system.get("anomaly", 0)
try:
idx = int(idx)
except (ValueError, TypeError):
idx = 0
if idx == 0 or not anomalytypes:
return "none"
if idx < len(anomalytypes):
raw = strip_prefix(anomalytypes[idx])
return ANOMALY_TYPE_MAP.get(raw, "none")
return "none"
def resolve_anomaly_type_from_name(item_name: str) -> str:
"""
Infère le type d'anomalie depuis le nom de l'item (ex: 'Entropie 1''entropie').
Fallback si le mapping par index est insuffisant.
"""
# Normalise : minuscules, retire accents, retire espaces et chiffres
name_clean = item_name.lower().strip()
name_clean = re.sub(r"\s*\d+\s*$", "", name_clean).strip() # retire le niveau en fin
name_clean = re.sub(r"\s+", "", name_clean) # retire tous les espaces
# Normalisation des accents courants
replacements = [
("é", "e"), ("è", "e"), ("ê", "e"), ("ë", "e"),
("à", "a"), ("â", "a"), ("ä", "a"),
("î", "i"), ("ï", "i"),
("ô", "o"), ("ö", "o"),
("û", "u"), ("ù", "u"), ("ü", "u"),
("ç", "c"),
]
for src, dst in replacements:
name_clean = name_clean.replace(src, dst)
for key in ANOMALY_TYPE_MAP:
if key == "none":
continue
if key in name_clean or name_clean in key:
return key
return "none"
def convert_stats_character(old_skill: dict, warnings: list) -> dict:
"""Convertit system.skill (ancien) → system.stats (nouveau) pour un PJ."""
stats = {}
for stat in STATS:
old_stat = old_skill.get(stat, {})
new_stat = {
"label": stat,
"res": int(old_stat.get("res", 0) or 0),
}
for skill in SKILLS[stat]:
old_sk = old_stat.get(skill, {})
val = old_sk.get("value", 0)
try:
val = int(val) if val is not None else 0
except (ValueError, TypeError):
warnings.append(f"Valeur de compétence invalide pour {stat}.{skill}: {val!r} → 0")
val = 0
new_stat[skill] = {"label": skill, "value": val}
stats[stat] = new_stat
return stats
def convert_stats_npc(old_skill: dict, warnings: list) -> dict:
"""Convertit system.skill (ancien) → system.stats (nouveau) pour un PNJ."""
stats = {}
for stat in STATS:
old_stat = old_skill.get(stat, {})
res = int(old_stat.get("res", 0) or 0)
stats[stat] = {
"label": stat,
"res": res,
"actuel": res, # actuel = res par défaut
}
return stats
def convert_attributs(old_attributs: dict) -> dict:
"""Convertit les attributs du vieux format plat vers SchemaField {value, max}."""
return {
"entregent": {
"value": int(old_attributs.get("entregent", 0) or 0),
"max": int(old_attributs.get("entregentmax", 0) or 0),
},
"fortune": {
"value": int(old_attributs.get("fortune", 0) or 0),
"max": int(old_attributs.get("fortunemax", 0) or 0),
},
"reve": {
"value": int(old_attributs.get("reve", 0) or 0),
"max": int(old_attributs.get("revemax", 0) or 0),
},
"vision": {
"value": int(old_attributs.get("vision", 0) or 0),
"max": int(old_attributs.get("visionmax", 0) or 0),
},
}
def convert_item(item: dict, warnings: list) -> dict | None:
"""
Convertit un item de l'ancien format vers le nouveau.
Retourne None si l'item doit être ignoré (type inconnu sans données utiles).
"""
old_type = item.get("type", "")
old_sys = item.get("system", {})
name = item.get("name", "Sans nom")
new_item = {
"_id": make_id(),
"name": name,
"img": item.get("img", "icons/svg/item-bag.svg"),
"effects": [],
"flags": {},
"sort": 0,
}
if old_type == "anomaly":
level = 0
try:
level = int(old_sys.get("value", 1) or 1)
except (ValueError, TypeError):
level = 1
level = max(1, min(4, level))
# Résolution du subtype : l'ancien système le stocke mal ("weapon"), on l'infère du nom
subtype = resolve_anomaly_type_from_name(name)
if subtype == "none":
warnings.append(f"Impossible de déterminer le type d'anomalie depuis '{name}', 'none' utilisé")
new_item["type"] = "anomaly"
new_item["system"] = {
"subtype": subtype,
"level": level,
"usesRemaining": level,
"technique": old_sys.get("technique", "") or "",
"narratif": old_sys.get("narratif", "") or "",
}
elif old_type == "aspect":
valeur = 0
try:
valeur = int(old_sys.get("value", 0) or 0)
except (ValueError, TypeError):
valeur = 0
new_item["type"] = "aspect"
new_item["system"] = {
"valeur": valeur,
"description": old_sys.get("narratif", "") or old_sys.get("technique", "") or "",
}
elif old_type == "item":
old_subtype = (old_sys.get("subtype") or "").lower().strip()
damage = old_sys.get("damage", "") or ""
protect = old_sys.get("protection", "") or ""
if old_subtype == "weapon" or (damage and not protect):
new_item["type"] = "weapon"
new_item["system"] = {
"type": "melee",
"degats": "0",
"portee": "contact",
"equipped": False,
"description": old_sys.get("technique", "") or old_sys.get("narratif", "") or "",
}
if damage:
warnings.append(f"Item '{name}' : valeur damage='{damage}' non convertie automatiquement, à saisir manuellement")
elif old_subtype == "armor" or (protect and not damage):
new_item["type"] = "armure"
new_item["system"] = {
"protection": 1,
"malus": 1,
"equipped": False,
"description": old_sys.get("technique", "") or old_sys.get("narratif", "") or "",
}
if protect:
warnings.append(f"Item '{name}' : valeur protection='{protect}' non convertie automatiquement, à saisir manuellement")
else:
# Équipement générique
new_item["type"] = "equipment"
new_item["system"] = {
"description": old_sys.get("technique", "") or old_sys.get("narratif", "") or "",
}
else:
warnings.append(f"Type d'item inconnu '{old_type}' pour '{name}', ignoré")
return None
return new_item
def convert_actor(old: dict) -> tuple[dict, list[str]]:
"""Convertit un acteur complet. Retourne (new_actor, warnings)."""
warnings = []
actor_type = old.get("type", "character")
old_sys = old.get("system", {})
old_skill = old_sys.get("skill", {})
new_sys = {}
# ── Champs communs ──────────────────────────────────────────────────────────────
new_sys["concept"] = old_sys.get("concept", "") or ""
new_sys["description"] = old_sys.get("description", "") or "" # gardé dans metier/concept
new_sys["metier"] = old_sys.get("metier", "") or old_sys.get("concept", "") or ""
new_sys["faction"] = old_sys.get("faction", "") or ""
# ── Blessures / Destin / Spleen ─────────────────────────────────────────────────
new_sys["blessures"] = {"lvl": int(old_sys.get("blessures", {}).get("lvl", 0) or 0)}
new_sys["destin"] = {"lvl": int(old_sys.get("destin", {}).get("lvl", 0) or 0)}
new_sys["spleen"] = {"lvl": int(old_sys.get("spleen", {}).get("lvl", 0) or 0)}
# ── Stats ───────────────────────────────────────────────────────────────────────
if actor_type == "character":
new_sys["stats"] = convert_stats_character(old_skill, warnings)
# Anomalie : type depuis l'index, niveau depuis anomalyval
anomaly_type = resolve_anomaly_type(old_sys)
anomaly_val = int(old_sys.get("anomalyval", 0) or 0)
new_sys["anomaly"] = {"type": anomaly_type, "value": anomaly_val}
# Attributs
new_sys["attributs"] = convert_attributs(old_sys.get("attributs", {}))
# Biographie → historique
new_sys["historique"] = old_sys.get("description", "") or ""
new_sys["descriptionPhysique"] = ""
new_sys["descriptionPsychologique"] = ""
new_sys["initiative"] = 0
# Factions (vide)
new_sys["factions"] = old_sys.get("factions", {})
elif actor_type == "npc":
new_sys["stats"] = convert_stats_npc(old_skill, warnings)
new_sys["npcType"] = old_sys.get("npcType", "standard") or "standard"
new_sys["historique"] = old_sys.get("description", "") or ""
# ── Items ───────────────────────────────────────────────────────────────────────
new_items = []
for item in old.get("items", []):
converted = convert_item(item, warnings)
if converted:
new_items.append(converted)
new_actor = {
"_id": make_id(),
"name": old.get("name", "Personnage sans nom"),
"type": actor_type,
"img": old.get("img", "icons/svg/mystery-man.svg"),
"system": new_sys,
"items": new_items,
"effects": [],
"folder": None,
"flags": {},
"prototypeToken": old.get("prototypeToken", {}),
}
return new_actor, warnings
def convert_file(path: str) -> None:
"""Lit path, convertit, écrit <base>-converted.json."""
print(f"\n{'' * 60}")
print(f"Traitement : {path}")
with open(path, "r", encoding="utf-8") as f:
old = json.load(f)
new_actor, warnings = convert_actor(old)
for w in warnings:
print(f"{w}")
base, _ = os.path.splitext(path)
out_path = f"{base}-converted.json"
with open(out_path, "w", encoding="utf-8") as f:
json.dump(new_actor, f, ensure_ascii=False, indent=2)
print(f" ✓ Écrit : {out_path}")
print(f" type={new_actor['type']} items={len(new_actor['items'])} avertissements={len(warnings)}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 convert-old-system.py <fichier.json> [fichier2.json ...]")
sys.exit(1)
for path in sys.argv[1:]:
if not os.path.isfile(path):
print(f"Fichier introuvable : {path}", file=sys.stderr)
continue
convert_file(path)
print(f"\n{'' * 60}")
print("Conversion terminée.")
if __name__ == "__main__":
main()
@@ -0,0 +1,143 @@
{
"_id": "e9e583fc41454c90",
"name": "Ajax",
"type": "npc",
"img": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/ajax.Avatar.webp?1719437847752",
"system": {
"concept": "",
"description": "",
"metier": "",
"faction": "",
"blessures": {
"lvl": 0
},
"destin": {
"lvl": 0
},
"spleen": {
"lvl": 0
},
"stats": {
"ame": {
"label": "ame",
"res": 0,
"actuel": 0
},
"corps": {
"label": "corps",
"res": 0,
"actuel": 0
},
"coeur": {
"label": "coeur",
"res": 0,
"actuel": 0
},
"esprit": {
"label": "esprit",
"res": 0,
"actuel": 0
}
},
"npcType": "standard",
"historique": ""
},
"items": [],
"effects": [],
"folder": null,
"flags": {},
"prototypeToken": {
"name": "Ajax",
"displayName": 0,
"actorLink": false,
"appendNumber": false,
"prependAdjective": false,
"texture": {
"src": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/ajax.Token.webp?1719437847752",
"scaleX": 1,
"scaleY": 1,
"offsetX": 0,
"offsetY": 0,
"rotation": 0,
"anchorX": 0.5,
"anchorY": 0.5,
"fit": "contain",
"tint": "#ffffff",
"alphaThreshold": 0.75
},
"width": 1,
"height": 1,
"lockRotation": false,
"rotation": 0,
"alpha": 1,
"disposition": -1,
"displayBars": 0,
"bar1": {
"attribute": null
},
"bar2": {
"attribute": null
},
"light": {
"alpha": 0.5,
"angle": 360,
"bright": 0,
"coloration": 1,
"dim": 0,
"attenuation": 0.5,
"luminosity": 0.5,
"saturation": 0,
"contrast": 0,
"shadows": 0,
"animation": {
"type": null,
"speed": 5,
"intensity": 5,
"reverse": false
},
"darkness": {
"min": 0,
"max": 1
},
"negative": false,
"priority": 0,
"color": null
},
"sight": {
"enabled": true,
"range": 30,
"angle": 360,
"visionMode": "basic",
"color": null,
"attenuation": 0.1,
"brightness": 0,
"saturation": 0,
"contrast": 0
},
"detectionModes": [],
"flags": {},
"randomImg": false,
"occludable": {
"radius": 0
},
"ring": {
"enabled": false,
"colors": {
"ring": null,
"background": null
},
"effects": 1,
"subject": {
"scale": 1,
"texture": null
}
},
"turnMarker": {
"mode": 1,
"animation": null,
"src": null,
"disposition": false
},
"movementAction": null
}
}
@@ -0,0 +1,459 @@
{
"folder": "fbRXVyFLLyOpuiTd",
"name": "Ajax",
"type": "npc",
"img": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/ajax.Avatar.webp?1719437847752",
"system": {
"concept": "",
"anomaly": "0",
"anomalyval": 0,
"anomalymax": "0",
"initiative": 0,
"description": "",
"prefs": {
"typeofthrow": {
"check": true,
"choice": "0"
}
},
"prompt": {
"typeofthrow": {
"check": true,
"choice": "0"
},
"configure": {
"numberofdice": 0,
"aspect": 0,
"bonus": 0,
"bonusauspiciousdice": 0,
"typeofthrow": 0,
"aspectskill": 0,
"bonusmalusskill": 0,
"aspectspeciality": 0,
"rolldifficulty": 0,
"bonusmalusspeciality": 0
}
},
"skill": {
"skilltypes": [
"CEL1922.opt.ame",
"CEL1922.opt.attraction",
"CEL1922.opt.artifice",
"CEL1922.opt.coercition",
"CEL1922.opt.faveur",
"CEL1922.opt.corps",
"CEL1922.opt.echauffouree",
"CEL1922.opt.effacement",
"CEL1922.opt.prouesse",
"CEL1922.opt.mobilite",
"CEL1922.opt.coeur",
"CEL1922.opt.appreciation",
"CEL1922.opt.arts",
"CEL1922.opt.inspiration",
"CEL1922.opt.traque",
"CEL1922.opt.esprit",
"CEL1922.opt.instruction",
"CEL1922.opt.mtechnologique",
"CEL1922.opt.raisonnement",
"CEL1922.opt.traitement"
],
"moondicetypes": [
"CEL1922.opt.nouvellelune",
"CEL1922.opt.premiercroissant",
"CEL1922.opt.premierquartier",
"CEL1922.opt.lunegibbeuse",
"CEL1922.opt.lunevoutee",
"CEL1922.opt.derniercroissant",
"CEL1922.opt.dernierquartier",
"CEL1922.opt.pleinelune"
],
"woundstypes": [
"CEL1922.opt.none",
"CEL1922.opt.anodin",
"CEL1922.opt.derisoire",
"CEL1922.opt.negligeable",
"CEL1922.opt.superficiel",
"CEL1922.opt.leger",
"CEL1922.opt.modere",
"CEL1922.opt.grave",
"CEL1922.opt.dramatique"
],
"woundsmalus": [
0,
0,
0,
-1,
-1,
-2,
-2,
-3,
-999
],
"woundsrecup": [
"CEL1922.opt.none",
"CEL1922.1 minute",
"CEL1922.1 minute",
"CEL1922.10 minutes",
"CEL1922.10 minutes",
"CEL1922.30 minutes",
"CEL1922.30 minutes",
"CEL1922.1 day",
"CEL1922.Out of Fiction"
],
"destinytypes": [
"CEL1922.opt.none",
"CEL1922.opt.libel1",
"CEL1922.opt.libel2",
"CEL1922.opt.libel3",
"CEL1922.opt.libel4",
"CEL1922.opt.libel5",
"CEL1922.opt.libel6",
"CEL1922.opt.libel7",
"CEL1922.opt.libel8"
],
"spleentypes": [
"CEL1922.opt.none",
"CEL1922.opt.libel1",
"CEL1922.opt.libel2",
"CEL1922.opt.libel3",
"CEL1922.opt.libel4",
"CEL1922.opt.libel5",
"CEL1922.opt.libel6",
"CEL1922.opt.libel7",
"CEL1922.opt.libel8"
],
"anomalytypes": [
"CEL1922.opt.none",
"CEL1922.opt.entropie",
"CEL1922.opt.communicationaveclesmorts",
"CEL1922.opt.illusion",
"CEL1922.opt.suggestion",
"CEL1922.opt.tarotdivinatoire",
"CEL1922.opt.telekinesie",
"CEL1922.opt.telepathie",
"CEL1922.opt.voyageastral"
],
"ame": {
"res": 0,
"actuel": 0,
"artifice": {
"value": 0
},
"attraction": {
"value": 0
},
"coercition": {
"value": 0
},
"faveur": {
"value": 0
}
},
"corps": {
"res": 0,
"actuel": 0,
"echauffouree": {
"value": 0
},
"effacement": {
"value": 0
},
"prouesse": {
"value": 0
},
"mobilite": {
"value": 0
}
},
"coeur": {
"res": 0,
"actuel": 0,
"appreciation": {
"value": 0
},
"arts": {
"value": 0
},
"inspiration": {
"value": 0
},
"traque": {
"value": 0
}
},
"esprit": {
"res": 0,
"actuel": 0,
"instruction": {
"value": 0
},
"mtechnologique": {
"value": 0
},
"raisonnement": {
"value": 0
},
"traitement": {
"value": 0
}
},
"aspecttypes": [
"CEL1922.opt.none",
"CEL1922.opt.aspect1",
"CEL1922.opt.aspect2",
"CEL1922.opt.aspect3",
"CEL1922.opt.aspect4",
"CEL1922.opt.aspect5",
"CEL1922.opt.aspect6",
"CEL1922.opt.aspect7",
"CEL1922.opt.aspect8"
]
},
"blessures": {
"lvl": 0,
"blessure_1": {
"check": false,
"bonus": 0,
"malus": 0
},
"blessure_2": {
"check": false,
"bonus": 0,
"malus": 0
},
"blessure_3": {
"check": false,
"bonus": 0,
"malus": -1
},
"blessure_4": {
"check": false,
"bonus": 0,
"malus": -1
},
"blessure_5": {
"check": false,
"bonus": 0,
"malus": -2
},
"blessure_6": {
"check": false,
"bonus": 0,
"malus": -2
},
"blessure_7": {
"check": false,
"bonus": 0,
"malus": -3
},
"blessure_8": {
"check": false,
"bonus": 0,
"malus": -999
}
},
"destin": {
"lvl": 0,
"destin_1": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_2": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_3": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_4": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_5": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_6": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_7": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_8": {
"check": false,
"bonus": 0,
"malus": 0
}
},
"spleen": {
"lvl": 0,
"spleen_1": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_2": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_3": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_4": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_5": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_6": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_7": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_8": {
"check": false,
"bonus": 0,
"malus": 0
}
}
},
"prototypeToken": {
"name": "Ajax",
"displayName": 0,
"actorLink": false,
"appendNumber": false,
"prependAdjective": false,
"texture": {
"src": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/ajax.Token.webp?1719437847752",
"scaleX": 1,
"scaleY": 1,
"offsetX": 0,
"offsetY": 0,
"rotation": 0,
"anchorX": 0.5,
"anchorY": 0.5,
"fit": "contain",
"tint": "#ffffff",
"alphaThreshold": 0.75
},
"width": 1,
"height": 1,
"lockRotation": false,
"rotation": 0,
"alpha": 1,
"disposition": -1,
"displayBars": 0,
"bar1": {
"attribute": null
},
"bar2": {
"attribute": null
},
"light": {
"alpha": 0.5,
"angle": 360,
"bright": 0,
"coloration": 1,
"dim": 0,
"attenuation": 0.5,
"luminosity": 0.5,
"saturation": 0,
"contrast": 0,
"shadows": 0,
"animation": {
"type": null,
"speed": 5,
"intensity": 5,
"reverse": false
},
"darkness": {
"min": 0,
"max": 1
},
"negative": false,
"priority": 0,
"color": null
},
"sight": {
"enabled": true,
"range": 30,
"angle": 360,
"visionMode": "basic",
"color": null,
"attenuation": 0.1,
"brightness": 0,
"saturation": 0,
"contrast": 0
},
"detectionModes": [],
"flags": {},
"randomImg": false,
"occludable": {
"radius": 0
},
"ring": {
"enabled": false,
"colors": {
"ring": null,
"background": null
},
"effects": 1,
"subject": {
"scale": 1,
"texture": null
}
},
"turnMarker": {
"mode": 1,
"animation": null,
"src": null,
"disposition": false
},
"movementAction": null
},
"items": [],
"effects": [],
"flags": {},
"_stats": {
"systemId": "celestopol1922",
"systemVersion": "0.0.7bêta",
"coreVersion": "13.348",
"createdTime": 1719437808862,
"modifiedTime": 1719437944369,
"lastModifiedBy": "6VFjkRpqiseDFIh9",
"compendiumSource": null,
"duplicateSource": null,
"exportSource": {
"worldId": "celestopol-1922",
"uuid": "Actor.QcGcXhb9FvHCb3uf",
"coreVersion": "13.351",
"systemId": "celestopol1922",
"systemVersion": "1.2.0"
}
},
"ownership": {
"default": 0
}
}
@@ -0,0 +1,296 @@
{
"_id": "04f6df7b17f747c6",
"name": "BAO WANG",
"type": "character",
"img": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/systems/celestopol1922/images/pj/bao_wang.png?1719410935795",
"system": {
"concept": "LESCROC",
"description": "<h1>BAO WANG : LESCROC </h1><p></p><p><span class=\"fontstyle0\">Ancien employé du casino flottant la Libellule, Bao Wang officiait comme videur.</span></p><p></p><p><span class=\"fontstyle0\">Après une adolescence de petite frappe dans les faubourgs de Shanghai, il parvint à sintroduire dans un obus-traversier pour rejoindre Célestopol, autant attiré par les perspectives offertes par la cité lunaire que par le besoin de se faire oublier des services de police de sa ville natale.</span></p><p></p><p><span class=\"fontstyle0\">Problème : Bao répugne à se battre et préfère largement la finesse à la violence. De son ancienne vie, il conserve un goût prononcé pour le jeu et la gente féminine. Par ailleurs, Bao a également un certain penchant pour les cabarets clandestins dans lesquels il aime à se travestir à loccasion. Cest dans lun de ces lieux interlopes de la cité que le jeune Chinois a rencontré Ernest. Ils ont sympathisé et le vétéran a su voir un certain potentiel chez Bao. Ce dernier, passablement désœuvré et fauché, accepta sans trop y croire dintégrer lagence du Lys blanc.</span></p><p></p><p><span class=\"fontstyle0\">Son sens de la débrouillardise et son passé houleux parfois bien utile lui octroient des compétences uniques et font désormais de lui un agent indispensable. Le jeune homme sinvestit dailleurs sincèrement dans son travail. Toujours tiré à quatre épingles, Bao est reconnu parmi ses coéquipiers comme le plus nonchalant du groupe.</span> <br style=\"font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;orphans:2;text-align:-webkit-auto;text-indent:0px;text-transform:none;white-space:normal;widows:2;word-spacing:0px;-webkit-text-size-adjust:auto;-webkit-text-stroke-width:0px\" /></p>",
"metier": "LESCROC",
"faction": "",
"blessures": {
"lvl": 0
},
"destin": {
"lvl": 0
},
"spleen": {
"lvl": 0
},
"stats": {
"ame": {
"label": "ame",
"res": 2,
"artifice": {
"label": "artifice",
"value": 4
},
"attraction": {
"label": "attraction",
"value": 2
},
"coercition": {
"label": "coercition",
"value": 2
},
"faveur": {
"label": "faveur",
"value": 2
}
},
"corps": {
"label": "corps",
"res": 4,
"echauffouree": {
"label": "echauffouree",
"value": 0
},
"effacement": {
"label": "effacement",
"value": 4
},
"mobilite": {
"label": "mobilite",
"value": 2
},
"prouesse": {
"label": "prouesse",
"value": 2
}
},
"coeur": {
"label": "coeur",
"res": 0,
"appreciation": {
"label": "appreciation",
"value": 2
},
"arts": {
"label": "arts",
"value": 0
},
"inspiration": {
"label": "inspiration",
"value": 1
},
"traque": {
"label": "traque",
"value": 3
}
},
"esprit": {
"label": "esprit",
"res": 0,
"instruction": {
"label": "instruction",
"value": 1
},
"mtechnologique": {
"label": "mtechnologique",
"value": 2
},
"raisonnement": {
"label": "raisonnement",
"value": 1
},
"traitement": {
"label": "traitement",
"value": 2
}
}
},
"anomaly": {
"type": "entropie",
"value": 1
},
"attributs": {
"entregent": {
"value": 0,
"max": 0
},
"fortune": {
"value": 0,
"max": 0
},
"reve": {
"value": 0,
"max": 0
},
"vision": {
"value": 0,
"max": 0
}
},
"historique": "<h1>BAO WANG : LESCROC </h1><p></p><p><span class=\"fontstyle0\">Ancien employé du casino flottant la Libellule, Bao Wang officiait comme videur.</span></p><p></p><p><span class=\"fontstyle0\">Après une adolescence de petite frappe dans les faubourgs de Shanghai, il parvint à sintroduire dans un obus-traversier pour rejoindre Célestopol, autant attiré par les perspectives offertes par la cité lunaire que par le besoin de se faire oublier des services de police de sa ville natale.</span></p><p></p><p><span class=\"fontstyle0\">Problème : Bao répugne à se battre et préfère largement la finesse à la violence. De son ancienne vie, il conserve un goût prononcé pour le jeu et la gente féminine. Par ailleurs, Bao a également un certain penchant pour les cabarets clandestins dans lesquels il aime à se travestir à loccasion. Cest dans lun de ces lieux interlopes de la cité que le jeune Chinois a rencontré Ernest. Ils ont sympathisé et le vétéran a su voir un certain potentiel chez Bao. Ce dernier, passablement désœuvré et fauché, accepta sans trop y croire dintégrer lagence du Lys blanc.</span></p><p></p><p><span class=\"fontstyle0\">Son sens de la débrouillardise et son passé houleux parfois bien utile lui octroient des compétences uniques et font désormais de lui un agent indispensable. Le jeune homme sinvestit dailleurs sincèrement dans son travail. Toujours tiré à quatre épingles, Bao est reconnu parmi ses coéquipiers comme le plus nonchalant du groupe.</span> <br style=\"font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;orphans:2;text-align:-webkit-auto;text-indent:0px;text-transform:none;white-space:normal;widows:2;word-spacing:0px;-webkit-text-size-adjust:auto;-webkit-text-stroke-width:0px\" /></p>",
"descriptionPhysique": "",
"descriptionPsychologique": "",
"initiative": 0,
"factions": {
"pinkerton": 0,
"police": 0,
"okhrana": 0,
"lunanovatek": 0,
"oto": 0,
"syndicats": 0,
"vorovskoymir": 0,
"cour": 0,
"perso": 0,
"libel": "",
"perso2": 0,
"libel2": ""
}
},
"items": [
{
"_id": "23315ed101e248c8",
"name": "Entropie 1",
"img": "https://assets.forge-vtt.com/bazaar/core/icons/svg/item-bag.svg",
"effects": [],
"flags": {},
"sort": 0,
"type": "anomaly",
"system": {
"subtype": "entropie",
"level": 1,
"usesRemaining": 1,
"technique": "<p><span class=\"fontstyle0\">Bao peut relancer le dé de la Lune une fois lors dun même scénario et choisit de conserver le résultat quil préfère (cette faculté ne fonctionne pas sur les tests de chance).</span></p>",
"narratif": "<p><span class=\"fontstyle0\">Bao peut influer sur le hasard de manière mineure. </span><span class=\"fontstyle2\">Exemple : <em>avoir une bonne main en jouant au poker à la distribution, que le feu soit au vert en tournant au coin de la rue, etc.</em></span></p>"
}
},
{
"_id": "4edb4b80b9514a7b",
"name": "Belle gueule 2",
"img": "https://assets.forge-vtt.com/bazaar/core/icons/svg/item-bag.svg",
"effects": [],
"flags": {},
"sort": 0,
"type": "aspect",
"system": {
"valeur": 2,
"description": ""
}
},
{
"_id": "153b0a094ca4462e",
"name": "Aime le jeu 1",
"img": "https://assets.forge-vtt.com/bazaar/core/icons/svg/item-bag.svg",
"effects": [],
"flags": {},
"sort": 0,
"type": "aspect",
"system": {
"valeur": 1,
"description": ""
}
},
{
"_id": "cbdc76f66bd041a0",
"name": "Nouvel Équipement",
"img": "https://assets.forge-vtt.com/bazaar/core/icons/svg/item-bag.svg",
"effects": [],
"flags": {},
"sort": 0,
"type": "equipment",
"system": {
"description": ""
}
}
],
"effects": [],
"folder": null,
"flags": {},
"prototypeToken": {
"name": "BAO WANG",
"displayName": 0,
"actorLink": false,
"appendNumber": false,
"prependAdjective": false,
"texture": {
"src": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/bao_wang.Token.webp?1719410935795",
"scaleX": 1,
"scaleY": 1,
"offsetX": 0,
"offsetY": 0,
"rotation": 0,
"tint": "#ffffff",
"anchorX": 0.5,
"anchorY": 0.5,
"fit": "contain",
"alphaThreshold": 0.75
},
"width": 1,
"height": 1,
"lockRotation": false,
"rotation": 0,
"alpha": 1,
"disposition": -1,
"displayBars": 0,
"bar1": {
"attribute": null
},
"bar2": {
"attribute": null
},
"light": {
"alpha": 0.5,
"angle": 360,
"bright": 0,
"coloration": 1,
"dim": 0,
"attenuation": 0.5,
"luminosity": 0.5,
"saturation": 0,
"contrast": 0,
"shadows": 0,
"animation": {
"type": null,
"speed": 5,
"intensity": 5,
"reverse": false
},
"darkness": {
"min": 0,
"max": 1
},
"color": null,
"negative": false,
"priority": 0
},
"sight": {
"enabled": false,
"range": 0,
"angle": 360,
"visionMode": "basic",
"attenuation": 0.1,
"brightness": 0,
"saturation": 0,
"contrast": 0,
"color": null
},
"detectionModes": [],
"flags": {},
"randomImg": false,
"occludable": {
"radius": 0
},
"ring": {
"enabled": false,
"colors": {
"ring": null,
"background": null
},
"effects": 1,
"subject": {
"scale": 1,
"texture": null
}
},
"turnMarker": {
"mode": 1,
"animation": null,
"src": null,
"disposition": false
},
"movementAction": null
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,143 @@
{
"_id": "fabe178df844475b",
"name": "Citoyen",
"type": "npc",
"img": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/citoyen.Avatar.webp?1719438184882",
"system": {
"concept": "",
"description": "",
"metier": "",
"faction": "",
"blessures": {
"lvl": 0
},
"destin": {
"lvl": 0
},
"spleen": {
"lvl": 0
},
"stats": {
"ame": {
"label": "ame",
"res": 0,
"actuel": 0
},
"corps": {
"label": "corps",
"res": 0,
"actuel": 0
},
"coeur": {
"label": "coeur",
"res": 0,
"actuel": 0
},
"esprit": {
"label": "esprit",
"res": 0,
"actuel": 0
}
},
"npcType": "standard",
"historique": ""
},
"items": [],
"effects": [],
"folder": null,
"flags": {},
"prototypeToken": {
"name": "Citoyen",
"displayName": 0,
"actorLink": false,
"appendNumber": false,
"prependAdjective": false,
"texture": {
"src": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/citoyen.Token.webp?1719438184882",
"scaleX": 1,
"scaleY": 1,
"offsetX": 0,
"offsetY": 0,
"rotation": 0,
"anchorX": 0.5,
"anchorY": 0.5,
"fit": "contain",
"tint": "#ffffff",
"alphaThreshold": 0.75
},
"width": 1,
"height": 1,
"lockRotation": false,
"rotation": 0,
"alpha": 1,
"disposition": -1,
"displayBars": 0,
"bar1": {
"attribute": null
},
"bar2": {
"attribute": null
},
"light": {
"alpha": 0.5,
"angle": 360,
"bright": 0,
"coloration": 1,
"dim": 0,
"attenuation": 0.5,
"luminosity": 0.5,
"saturation": 0,
"contrast": 0,
"shadows": 0,
"animation": {
"type": null,
"speed": 5,
"intensity": 5,
"reverse": false
},
"darkness": {
"min": 0,
"max": 1
},
"negative": false,
"priority": 0,
"color": null
},
"sight": {
"enabled": true,
"range": 30,
"angle": 360,
"visionMode": "basic",
"color": null,
"attenuation": 0.1,
"brightness": 0,
"saturation": 0,
"contrast": 0
},
"detectionModes": [],
"flags": {},
"randomImg": false,
"occludable": {
"radius": 0
},
"ring": {
"enabled": false,
"colors": {
"ring": null,
"background": null
},
"effects": 1,
"subject": {
"scale": 1,
"texture": null
}
},
"turnMarker": {
"mode": 1,
"animation": null,
"src": null,
"disposition": false
},
"movementAction": null
}
}
@@ -0,0 +1,459 @@
{
"folder": "5aDs3Gbi2cHy35X9",
"name": "Citoyen",
"type": "npc",
"img": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/citoyen.Avatar.webp?1719438184882",
"system": {
"concept": "",
"anomaly": "0",
"anomalyval": 0,
"anomalymax": "0",
"initiative": 0,
"description": "",
"prefs": {
"typeofthrow": {
"check": true,
"choice": "0"
}
},
"prompt": {
"typeofthrow": {
"check": true,
"choice": "0"
},
"configure": {
"numberofdice": 0,
"aspect": 0,
"bonus": 0,
"bonusauspiciousdice": 0,
"typeofthrow": 0,
"aspectskill": 0,
"bonusmalusskill": 0,
"aspectspeciality": 0,
"rolldifficulty": 0,
"bonusmalusspeciality": 0
}
},
"skill": {
"skilltypes": [
"CEL1922.opt.ame",
"CEL1922.opt.attraction",
"CEL1922.opt.artifice",
"CEL1922.opt.coercition",
"CEL1922.opt.faveur",
"CEL1922.opt.corps",
"CEL1922.opt.echauffouree",
"CEL1922.opt.effacement",
"CEL1922.opt.prouesse",
"CEL1922.opt.mobilite",
"CEL1922.opt.coeur",
"CEL1922.opt.appreciation",
"CEL1922.opt.arts",
"CEL1922.opt.inspiration",
"CEL1922.opt.traque",
"CEL1922.opt.esprit",
"CEL1922.opt.instruction",
"CEL1922.opt.mtechnologique",
"CEL1922.opt.raisonnement",
"CEL1922.opt.traitement"
],
"moondicetypes": [
"CEL1922.opt.nouvellelune",
"CEL1922.opt.premiercroissant",
"CEL1922.opt.premierquartier",
"CEL1922.opt.lunegibbeuse",
"CEL1922.opt.lunevoutee",
"CEL1922.opt.derniercroissant",
"CEL1922.opt.dernierquartier",
"CEL1922.opt.pleinelune"
],
"woundstypes": [
"CEL1922.opt.none",
"CEL1922.opt.anodin",
"CEL1922.opt.derisoire",
"CEL1922.opt.negligeable",
"CEL1922.opt.superficiel",
"CEL1922.opt.leger",
"CEL1922.opt.modere",
"CEL1922.opt.grave",
"CEL1922.opt.dramatique"
],
"woundsmalus": [
0,
0,
0,
-1,
-1,
-2,
-2,
-3,
-999
],
"woundsrecup": [
"CEL1922.opt.none",
"CEL1922.1 minute",
"CEL1922.1 minute",
"CEL1922.10 minutes",
"CEL1922.10 minutes",
"CEL1922.30 minutes",
"CEL1922.30 minutes",
"CEL1922.1 day",
"CEL1922.Out of Fiction"
],
"destinytypes": [
"CEL1922.opt.none",
"CEL1922.opt.libel1",
"CEL1922.opt.libel2",
"CEL1922.opt.libel3",
"CEL1922.opt.libel4",
"CEL1922.opt.libel5",
"CEL1922.opt.libel6",
"CEL1922.opt.libel7",
"CEL1922.opt.libel8"
],
"spleentypes": [
"CEL1922.opt.none",
"CEL1922.opt.libel1",
"CEL1922.opt.libel2",
"CEL1922.opt.libel3",
"CEL1922.opt.libel4",
"CEL1922.opt.libel5",
"CEL1922.opt.libel6",
"CEL1922.opt.libel7",
"CEL1922.opt.libel8"
],
"anomalytypes": [
"CEL1922.opt.none",
"CEL1922.opt.entropie",
"CEL1922.opt.communicationaveclesmorts",
"CEL1922.opt.illusion",
"CEL1922.opt.suggestion",
"CEL1922.opt.tarotdivinatoire",
"CEL1922.opt.telekinesie",
"CEL1922.opt.telepathie",
"CEL1922.opt.voyageastral"
],
"ame": {
"res": 0,
"actuel": 0,
"artifice": {
"value": 0
},
"attraction": {
"value": 0
},
"coercition": {
"value": 0
},
"faveur": {
"value": 0
}
},
"corps": {
"res": 0,
"actuel": 0,
"echauffouree": {
"value": 0
},
"effacement": {
"value": 0
},
"prouesse": {
"value": 0
},
"mobilite": {
"value": 0
}
},
"coeur": {
"res": 0,
"actuel": 0,
"appreciation": {
"value": 0
},
"arts": {
"value": 0
},
"inspiration": {
"value": 0
},
"traque": {
"value": 0
}
},
"esprit": {
"res": 0,
"actuel": 0,
"instruction": {
"value": 0
},
"mtechnologique": {
"value": 0
},
"raisonnement": {
"value": 0
},
"traitement": {
"value": 0
}
},
"aspecttypes": [
"CEL1922.opt.none",
"CEL1922.opt.aspect1",
"CEL1922.opt.aspect2",
"CEL1922.opt.aspect3",
"CEL1922.opt.aspect4",
"CEL1922.opt.aspect5",
"CEL1922.opt.aspect6",
"CEL1922.opt.aspect7",
"CEL1922.opt.aspect8"
]
},
"blessures": {
"lvl": 0,
"blessure_1": {
"check": false,
"bonus": 0,
"malus": 0
},
"blessure_2": {
"check": false,
"bonus": 0,
"malus": 0
},
"blessure_3": {
"check": false,
"bonus": 0,
"malus": -1
},
"blessure_4": {
"check": false,
"bonus": 0,
"malus": -1
},
"blessure_5": {
"check": false,
"bonus": 0,
"malus": -2
},
"blessure_6": {
"check": false,
"bonus": 0,
"malus": -2
},
"blessure_7": {
"check": false,
"bonus": 0,
"malus": -3
},
"blessure_8": {
"check": false,
"bonus": 0,
"malus": -999
}
},
"destin": {
"lvl": 0,
"destin_1": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_2": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_3": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_4": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_5": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_6": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_7": {
"check": false,
"bonus": 0,
"malus": 0
},
"destin_8": {
"check": false,
"bonus": 0,
"malus": 0
}
},
"spleen": {
"lvl": 0,
"spleen_1": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_2": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_3": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_4": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_5": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_6": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_7": {
"check": false,
"bonus": 0,
"malus": 0
},
"spleen_8": {
"check": false,
"bonus": 0,
"malus": 0
}
}
},
"prototypeToken": {
"name": "Citoyen",
"displayName": 0,
"actorLink": false,
"appendNumber": false,
"prependAdjective": false,
"texture": {
"src": "https://assets.forge-vtt.com/630dd9fa56bd61d804eb1dec/tokenizer/celestopol/citoyen.Token.webp?1719438184882",
"scaleX": 1,
"scaleY": 1,
"offsetX": 0,
"offsetY": 0,
"rotation": 0,
"anchorX": 0.5,
"anchorY": 0.5,
"fit": "contain",
"tint": "#ffffff",
"alphaThreshold": 0.75
},
"width": 1,
"height": 1,
"lockRotation": false,
"rotation": 0,
"alpha": 1,
"disposition": -1,
"displayBars": 0,
"bar1": {
"attribute": null
},
"bar2": {
"attribute": null
},
"light": {
"alpha": 0.5,
"angle": 360,
"bright": 0,
"coloration": 1,
"dim": 0,
"attenuation": 0.5,
"luminosity": 0.5,
"saturation": 0,
"contrast": 0,
"shadows": 0,
"animation": {
"type": null,
"speed": 5,
"intensity": 5,
"reverse": false
},
"darkness": {
"min": 0,
"max": 1
},
"negative": false,
"priority": 0,
"color": null
},
"sight": {
"enabled": true,
"range": 30,
"angle": 360,
"visionMode": "basic",
"color": null,
"attenuation": 0.1,
"brightness": 0,
"saturation": 0,
"contrast": 0
},
"detectionModes": [],
"flags": {},
"randomImg": false,
"occludable": {
"radius": 0
},
"ring": {
"enabled": false,
"colors": {
"ring": null,
"background": null
},
"effects": 1,
"subject": {
"scale": 1,
"texture": null
}
},
"turnMarker": {
"mode": 1,
"animation": null,
"src": null,
"disposition": false
},
"movementAction": null
},
"items": [],
"effects": [],
"flags": {},
"_stats": {
"systemId": "celestopol1922",
"systemVersion": "0.0.7bêta",
"coreVersion": "13.348",
"createdTime": 1719438039685,
"modifiedTime": 1719438184895,
"lastModifiedBy": "6VFjkRpqiseDFIh9",
"compendiumSource": null,
"duplicateSource": null,
"exportSource": {
"worldId": "celestopol-1922",
"uuid": "Actor.H4qPWYC8kbacuBfm",
"coreVersion": "13.351",
"systemId": "celestopol1922",
"systemVersion": "1.2.0"
}
},
"ownership": {
"default": 0
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

+416 -2
View File
@@ -39,6 +39,7 @@ import {
} from "./module/applications/_module.mjs" } from "./module/applications/_module.mjs"
const DAMAGE_APPLICATION_FLAG = "damageApplication" const DAMAGE_APPLICATION_FLAG = "damageApplication"
const MOON_EFFECT_FLAG = "moonEffectApplied"
const FACTION_ASPECT_STATE_SETTING = "factionAspectState" const FACTION_ASPECT_STATE_SETTING = "factionAspectState"
const PREGENS_IMPORTED_SETTING = "pregensImported" const PREGENS_IMPORTED_SETTING = "pregensImported"
const WELCOME_SCENE_IMPORTED_SETTING = "welcomeSceneImported" const WELCOME_SCENE_IMPORTED_SETTING = "welcomeSceneImported"
@@ -66,6 +67,7 @@ Hooks.once("init", () => {
SYSTEM, SYSTEM,
rollMoonStandalone: (actor = null) => CelestopolRoll.rollMoonStandalone(actor), rollMoonStandalone: (actor = null) => CelestopolRoll.rollMoonStandalone(actor),
manageFactionAspects: (actor = null) => _manageFactionAspects(actor), manageFactionAspects: (actor = null) => _manageFactionAspects(actor),
resetFactionAspects: () => _resetFactionAspects(),
getFactionAspectState: () => _getFactionAspectState(), getFactionAspectState: () => _getFactionAspectState(),
getFactionAspectSummary: (actor = null) => _getFactionAspectSummary(actor), getFactionAspectSummary: (actor = null) => _getFactionAspectSummary(actor),
getFactionDisplayLabel: (value) => _getFactionDisplayLabel(value), getFactionDisplayLabel: (value) => _getFactionDisplayLabel(value),
@@ -173,6 +175,9 @@ Hooks.once("ready", async () => {
if (foundry.utils.hasProperty(changed, `flags.${SYSTEM_ID}.${DAMAGE_APPLICATION_FLAG}`)) { if (foundry.utils.hasProperty(changed, `flags.${SYSTEM_ID}.${DAMAGE_APPLICATION_FLAG}`)) {
_updateRenderedChatMessageState(message) _updateRenderedChatMessageState(message)
} }
if (foundry.utils.hasProperty(changed, `flags.${SYSTEM_ID}.${MOON_EFFECT_FLAG}`)) {
_updateRenderedMoonEffectState(message)
}
}) })
_activateExistingChatCards() _activateExistingChatCards()
@@ -357,6 +362,259 @@ function _registerHandlebarsHelpers() {
}) })
} }
/* ─── Migration depuis l'ancien système ─────────────────────────────────── */
/** Mapping des types d'anomalies ancien→nouveau */
const _OLD_ANOMALY_TYPES = [
"none", "entropie", "communicationaveclesmorts", "illusion",
"suggestion", "tarotdivinatoire", "telekinesie", "telepathie", "voyageastral",
]
const _OLD_SKILLS = {
ame: ["artifice", "attraction", "coercition", "faveur"],
corps: ["echauffouree", "effacement", "mobilite", "prouesse"],
coeur: ["appreciation", "arts", "inspiration", "traque"],
esprit: ["instruction", "mtechnologique", "raisonnement", "traitement"],
}
/** Infère le type d'anomalie depuis le nom de l'item (ex: "Entropie 1" → "entropie"). */
function _anomalyTypeFromName(name) {
let n = name.toLowerCase().replace(/\s*\d+\s*$/, "").replace(/\s+/g, "")
const accents = [["é","e"],["è","e"],["ê","e"],["ë","e"],["à","a"],["â","a"],
["î","i"],["ï","i"],["ô","o"],["û","u"],["ù","u"],["ü","u"],["ç","c"]]
for (const [s,d] of accents) n = n.replaceAll(s, d)
return _OLD_ANOMALY_TYPES.find(k => k !== "none" && (k.includes(n) || n.includes(k))) ?? "none"
}
/** Convertit les stats d'un PJ (skill → stats). */
function _convertStatsCharacter(oldSkill) {
const stats = {}
for (const stat of ["ame","corps","coeur","esprit"]) {
const os = oldSkill[stat] ?? {}
const ns = { label: stat, res: Number(os.res ?? 0) }
for (const sk of _OLD_SKILLS[stat]) {
const val = Number(os[sk]?.value ?? 0) || 0
ns[sk] = { label: sk, value: val }
}
stats[stat] = ns
}
return stats
}
/** Convertit les stats d'un PNJ (skill → stats avec actuel). */
function _convertStatsNPC(oldSkill) {
const stats = {}
for (const stat of ["ame","corps","coeur","esprit"]) {
const res = Number(oldSkill[stat]?.res ?? 0)
stats[stat] = { label: stat, res, actuel: res }
}
return stats
}
/** Convertit les attributs du format plat vers {value, max}. */
function _convertAttributs(a = {}) {
return {
entregent: { value: Number(a.entregent ?? 0), max: Number(a.entregentmax ?? 0) },
fortune: { value: Number(a.fortune ?? 0), max: Number(a.fortunemax ?? 0) },
reve: { value: Number(a.reve ?? 0), max: Number(a.revemax ?? 0) },
vision: { value: Number(a.vision ?? 0), max: Number(a.visionmax ?? 0) },
}
}
/** Convertit un item de l'ancien format. Retourne null si ignoré. */
function _convertItem(item, warnings) {
const os = item.system ?? {}
const name = item.name ?? "Sans nom"
const base = {
name,
img: item.img ?? "icons/svg/item-bag.svg",
effects: [],
flags: {},
sort: 0,
}
if (item.type === "anomaly") {
const level = Math.max(1, Math.min(4, Number(os.value ?? 1) || 1))
const subtype = _anomalyTypeFromName(name)
if (subtype === "none")
warnings.push(`Impossible de déterminer le type d'anomalie depuis "${name}"`)
return { ...base, type: "anomaly", system: {
subtype, level, usesRemaining: level,
technique: os.technique ?? "", narratif: os.narratif ?? "",
}}
}
if (item.type === "aspect") {
return { ...base, type: "aspect", system: {
valeur: Number(os.value ?? 0) || 0,
description: os.narratif ?? os.technique ?? "",
}}
}
if (item.type === "item") {
const sub = (os.subtype ?? "").toLowerCase()
if (sub === "weapon") {
if (os.damage) warnings.push(`"${name}" : dégâts "${os.damage}" à saisir manuellement`)
return { ...base, type: "weapon", system: {
type: "melee", degats: "0", portee: "contact", equipped: false,
description: os.technique ?? os.narratif ?? "",
}}
}
if (sub === "armor") {
if (os.protection) warnings.push(`"${name}" : protection "${os.protection}" à saisir manuellement`)
return { ...base, type: "armure", system: {
protection: 1, malus: 1, equipped: false,
description: os.technique ?? os.narratif ?? "",
}}
}
return { ...base, type: "equipment", system: {
description: os.technique ?? os.narratif ?? "",
}}
}
warnings.push(`Type d'item inconnu "${item.type}" pour "${name}", ignoré`)
return null
}
/** Convertit un acteur complet de l'ancien format vers le nouveau. */
function _convertOldActor(old) {
const warnings = []
const os = old.system ?? {}
const osk = os.skill ?? {}
const type = old.type ?? "character"
// Anomalie : résolution depuis l'index stocké dans os.anomaly
const anomalyIdx = Number(os.anomaly ?? 0)
const anomalyTypes = osk.anomalytypes ?? _OLD_ANOMALY_TYPES.map(k => `CEL1922.opt.${k}`)
const rawAnomalyKey = (anomalyTypes[anomalyIdx] ?? "").split(".").pop() ?? "none"
const anomalyType = _OLD_ANOMALY_TYPES.includes(rawAnomalyKey) ? rawAnomalyKey : "none"
const sys = {
concept: os.concept ?? "",
metier: os.metier ?? os.concept ?? "",
faction: os.faction ?? "",
blessures: { lvl: Number(os.blessures?.lvl ?? 0) },
destin: { lvl: Number(os.destin?.lvl ?? 0) },
spleen: { lvl: Number(os.spleen?.lvl ?? 0) },
}
if (type === "character") {
sys.stats = _convertStatsCharacter(osk)
sys.anomaly = { type: anomalyType, value: Number(os.anomalyval ?? 0) }
sys.attributs = _convertAttributs(os.attributs)
sys.historique = os.description ?? ""
sys.descriptionPhysique = ""
sys.descriptionPsychologique = ""
sys.initiative = 0
sys.factions = os.factions ?? {}
} else {
sys.stats = _convertStatsNPC(osk)
sys.npcType = os.npcType ?? "standard"
sys.historique = os.description ?? ""
}
const items = (old.items ?? []).map(it => _convertItem(it, warnings)).filter(Boolean)
const actor = {
name: old.name ?? "Personnage sans nom",
type,
img: old.img ?? "icons/svg/mystery-man.svg",
system: sys,
items,
effects: [],
folder: null,
flags: {},
prototypeToken: old.prototypeToken ?? {},
}
return { actor, warnings }
}
/** Ouvre la dialog DialogV2 de migration et gère l'import de l'acteur. */
async function _openMigrationDialog() {
const content = `
<div class="cel-migration-dialog" style="padding:0.5em 0">
<p style="margin-bottom:0.8em">${game.i18n.localize("CELESTOPOL.Migration.instructions")}</p>
<div style="display:flex;gap:0.5em;align-items:center">
<label style="font-weight:bold;white-space:nowrap">
${game.i18n.localize("CELESTOPOL.Migration.fileLabel")}
</label>
<input type="file" id="cel-migration-file" accept=".json" style="flex:1">
</div>
</div>`
await foundry.applications.api.DialogV2.wait({
window: { title: game.i18n.localize("CELESTOPOL.Migration.title") },
classes: ["fvtt-celestopol"],
content,
buttons: [
{
label: game.i18n.localize("CELESTOPOL.Migration.importBtn"),
icon: "fas fa-file-import",
action: "import",
default: true,
callback: (_event, _btn, dialog) => {
const fileInput = dialog.element.querySelector("#cel-migration-file")
return fileInput?.files?.[0] ?? null
},
},
{
label: game.i18n.localize("Cancel"),
icon: "fas fa-times",
action: "cancel",
callback: () => null,
},
],
submit: async (result) => {
if (!result) return
const text = await result.text()
let old
try { old = JSON.parse(text) }
catch {
ui.notifications.error(game.i18n.localize("CELESTOPOL.Migration.errorParse"))
return
}
const { actor, warnings } = _convertOldActor(old)
try {
const created = await Actor.create(actor)
ui.notifications.info(game.i18n.format("CELESTOPOL.Migration.success", {
name: created.name, count: actor.items.length,
}))
if (warnings.length) {
console.warn(`Célestopol Migration | ${created.name} — avertissements :`)
warnings.forEach(w => console.warn(" ⚠", w))
ui.notifications.warn(game.i18n.format("CELESTOPOL.Migration.warnings", { count: warnings.length }))
}
} catch(err) {
console.error("Célestopol Migration | Échec de création de l'acteur :", err)
ui.notifications.error(game.i18n.localize("CELESTOPOL.Migration.errorCreate"))
}
},
})
}
/**
* Classe de menu de paramètre pour la migration.
* Étend ApplicationV2 (requis par registerMenu) mais surcharge render()
* pour déclencher directement la dialog de migration.
*/
class CelestopolMigrationMenu extends foundry.applications.api.ApplicationV2 {
static DEFAULT_OPTIONS = {
id: "celestopol-migration",
window: { title: "CELESTOPOL.Migration.title" },
classes: ["fvtt-celestopol"],
position: { width: 480 },
}
/** Surcharge : ignore le rendu AppV2 et ouvre directement la dialog. */
async render(...args) {
await _openMigrationDialog()
return this
}
}
/* ─── Settings ───────────────────────────────────────────────────────────── */ /* ─── Settings ───────────────────────────────────────────────────────────── */
function _registerSettings() { function _registerSettings() {
@@ -393,6 +651,16 @@ function _registerSettings() {
type: Boolean, type: Boolean,
default: false, default: false,
}) })
// Entrée de menu : migration depuis l'ancien système
game.settings.registerMenu(SYSTEM_ID, "migrateOldSystem", {
name: "CELESTOPOL.Setting.migrateOldSystem.name",
hint: "CELESTOPOL.Setting.migrateOldSystem.hint",
label: "CELESTOPOL.Setting.migrateOldSystem.label",
icon: "fas fa-file-import",
type: CelestopolMigrationMenu,
restricted: true,
})
} }
async function _createWelcomeChatMessage() { async function _createWelcomeChatMessage() {
@@ -548,8 +816,9 @@ function _activateExistingChatCards() {
document.querySelectorAll(".message[data-message-id]").forEach(messageEl => { document.querySelectorAll(".message[data-message-id]").forEach(messageEl => {
const messageId = messageEl.dataset.messageId const messageId = messageEl.dataset.messageId
const message = game.messages.get(messageId) const message = game.messages.get(messageId)
const root = messageEl.querySelector(".celestopol.chat-roll") if (!message) return
if (!message || !root) return const root = messageEl.querySelector(".celestopol.chat-roll, .celestopol-roll.moon-standalone-card")
if (!root) return
_activateChatCardListeners(message, root) _activateChatCardListeners(message, root)
}) })
} }
@@ -559,12 +828,19 @@ function _activateChatCardListeners(message, html) {
if (!root) return if (!root) return
_renderWeaponDamageState(message, root) _renderWeaponDamageState(message, root)
_renderMoonEffectState(message, root)
root.querySelectorAll('[data-action="apply-weapon-damage"]').forEach(button => { root.querySelectorAll('[data-action="apply-weapon-damage"]').forEach(button => {
if (button.dataset.bound === "true") return if (button.dataset.bound === "true") return
button.dataset.bound = "true" button.dataset.bound = "true"
button.addEventListener("click", event => _onApplyWeaponDamageClick(event, message)) button.addEventListener("click", event => _onApplyWeaponDamageClick(event, message))
}) })
root.querySelectorAll('[data-action="apply-moon-effect"]').forEach(button => {
if (button.dataset.bound === "true") return
button.dataset.bound = "true"
button.addEventListener("click", event => _onApplyMoonEffectClick(event, message))
})
} }
async function _onApplyWeaponDamageClick(event, message) { async function _onApplyWeaponDamageClick(event, message) {
@@ -746,6 +1022,126 @@ async function _applyWeaponDamage({ actorId, actorUuid = null, incomingWounds, c
return { actorName: actor.name, appliedWounds, armorProtection } return { actorName: actor.name, appliedWounds, armorProtection }
} }
/* ─── Dé de la Lune — contreparties ─────────────────────────────────────── */
function _getMoonEffectState(message) {
return message?.getFlag(SYSTEM_ID, MOON_EFFECT_FLAG) ?? null
}
function _renderMoonEffectState(message, root) {
const state = _getMoonEffectState(message)
const actionsDiv = root.querySelector(".moon-effect-actions")
if (!actionsDiv) return
if (!state?.applied) return
const NEGATIVE_EFFECTS = new Set(["lose-anomaly", "gain-spleen", "lose-destin"])
// Désactiver tous les boutons et afficher le statut
actionsDiv.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = true })
let statusEl = actionsDiv.querySelector(".moon-effect-applied-status")
if (!statusEl) {
statusEl = document.createElement("span")
actionsDiv.append(statusEl)
}
statusEl.className = "moon-effect-applied-status" + (NEGATIVE_EFFECTS.has(state.effect) ? " is-negative" : "")
statusEl.textContent = state.effectLabel
? game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: state.effectLabel })
: game.i18n.localize("CELESTOPOL.Moon.effectApplied")
}
function _updateRenderedMoonEffectState(message) {
const msgEl = document.querySelector(`.message[data-message-id="${message.id}"]`)
if (!msgEl) return
const root = msgEl.querySelector(".celestopol.chat-roll, .celestopol-roll.moon-standalone-card")
if (!root) return
_renderMoonEffectState(message, root)
}
async function _onApplyMoonEffectClick(event, message) {
event.preventDefault()
const state = _getMoonEffectState(message)
if (state?.applied) return
const button = event.currentTarget
const effect = button.dataset.effect
const actionsDiv = button.closest(".moon-effect-actions")
const actorId = actionsDiv?.dataset.moonActorId ?? ""
const actorUuid = actionsDiv?.dataset.moonActorUuid ?? ""
// Désactiver immédiatement pour éviter les double-clics
actionsDiv?.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = true })
const actor = await CelestopolRoll.resolveActor({ actorId, actorUuid })
if (!actor) {
ui.notifications.warn(game.i18n.localize("CELESTOPOL.Moon.actorNotFound"))
actionsDiv?.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = false })
return
}
const effectLabel = await _applyMoonEffect(actor, effect)
if (effectLabel === null) {
actionsDiv?.querySelectorAll(".moon-effect-btn").forEach(btn => { btn.disabled = false })
return
}
await message.setFlag(SYSTEM_ID, MOON_EFFECT_FLAG, { applied: true, effect, effectLabel })
}
async function _applyMoonEffect(actor, effect) {
const i18n = key => game.i18n.localize(`CELESTOPOL.Moon.${key}`)
const anomaly = actor.items.find(i => i.type === "anomaly")
switch (effect) {
case "regain-anomaly": {
if (!anomaly) { ui.notifications.warn(i18n("noAnomaly")); return null }
const max = anomaly.system?.level ?? 0
const cur = anomaly.system?.usesRemaining ?? 0
if (cur >= max) { ui.notifications.warn(i18n("anomalyFull")); return null }
await anomaly.update({ "system.usesRemaining": Math.min(max, cur + 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectRegainAnomaly") }))
return i18n("effectRegainAnomaly")
}
case "lose-spleen": {
const cur = actor.system?.spleen?.lvl ?? 0
if (cur <= 0) { ui.notifications.warn(i18n("spleenEmpty")); return null }
await actor.update({ "system.spleen.lvl": Math.max(0, cur - 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectLoseSpleen") }))
return i18n("effectLoseSpleen")
}
case "gain-destin": {
const cur = actor.system?.destin?.lvl ?? 0
await actor.update({ "system.destin.lvl": Math.min(8, cur + 2) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectGainDestin") }))
return i18n("effectGainDestin")
}
case "lose-destin": {
const cur = actor.system?.destin?.lvl ?? 0
await actor.update({ "system.destin.lvl": Math.max(0, cur - 2) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectLoseDestin") }))
return i18n("effectLoseDestin")
}
case "lose-anomaly": {
if (!anomaly) { ui.notifications.warn(i18n("noAnomaly")); return null }
const cur = anomaly.system?.usesRemaining ?? 0
if (cur <= 0) { ui.notifications.warn(i18n("anomalyEmpty")); return null }
await anomaly.update({ "system.usesRemaining": Math.max(0, cur - 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectLoseAnomaly") }))
return i18n("effectLoseAnomaly")
}
case "gain-spleen": {
const cur = actor.system?.spleen?.lvl ?? 0
if (cur >= 8) { ui.notifications.warn(i18n("spleenFull")); return null }
await actor.update({ "system.spleen.lvl": Math.min(8, cur + 1) })
ui.notifications.info(game.i18n.format("CELESTOPOL.Moon.effectApplied", { label: i18n("effectGainSpleen") }))
return i18n("effectGainSpleen")
}
default:
return null
}
}
function _getDefaultFactionAspectState() { function _getDefaultFactionAspectState() {
return { return {
pointsMax: 8, pointsMax: 8,
@@ -823,6 +1219,24 @@ async function _setFactionAspectState(state) {
return cleanState return cleanState
} }
async function _resetFactionAspects() {
if (!game.user.isGM) {
ui.notifications.warn(game.i18n.localize("CELESTOPOL.FactionAspect.gmOnly"))
return
}
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: { title: game.i18n.localize("CELESTOPOL.FactionAspect.resetTitle") },
content: `<p>${game.i18n.localize("CELESTOPOL.FactionAspect.resetConfirm")}</p>`,
yes: { label: game.i18n.localize("CELESTOPOL.FactionAspect.resetConfirmYes"), icon: "fas fa-redo" },
no: { label: game.i18n.localize("Cancel"), icon: "fas fa-times" },
rejectClose: false,
})
if (!confirmed) return
const state = _getFactionAspectState()
await _setFactionAspectState({ ...state, activatedAspects: [] })
ui.notifications.info(game.i18n.localize("CELESTOPOL.FactionAspect.resetSuccess"))
}
function _refreshFactionAspectSheets() { function _refreshFactionAspectSheets() {
for (const actor of game.actors.contents) { for (const actor of game.actors.contents) {
if (actor.type !== "character") continue if (actor.type !== "character") continue
+56 -3
View File
@@ -58,7 +58,25 @@
"instruction": "Instruction", "instruction": "Instruction",
"mtechnologique": "Merveilleux technologique", "mtechnologique": "Merveilleux technologique",
"raisonnement": "Raisonnement", "raisonnement": "Raisonnement",
"traitement": "Traitement" "traitement": "Traitement",
"tooltip": {
"artifice": "Art du badinage et de la conversation subtile. Permet de se glisser dans une discussion pour glaner des renseignements ou noyer des informations mensongères. Favorise la manipulation et l'incitation plutôt que la contrainte.",
"attraction": "Capacité à orienter les émotions d'un interlocuteur. Sert à plaire, séduire, mais aussi à passer inaperçu lors d'une soirée mondaine.",
"coercition": "Art d'intimider par le regard ou les mots. Couvre également la capacité à donner des ordres dans un contexte militaire ou hiérarchique.",
"faveur": "Rapport de force oral : convaincre, persuader, négocier. S'appuie sur un discours argumentatif pour imposer son point de vue ou emporter l'adhésion.",
"echauffouree": "Techniques de combat à mains nues, avec une arme improvisée, une arme blanche ou des armes à feu et à distance.",
"effacement": "Capacité à être discret et à ne pas se faire repérer. Couvre le camouflage et l'escamotage. Requiert souvent de demeurer immobile.",
"mobilite": "Réflexes et vivacité. Sert pour la conduite, le pilotage, l'équitation, et représente l'initiative d'un protagoniste.",
"prouesse": "Efforts sportifs et physiques : escalade, natation, sprint, force brute et endurance.",
"appreciation": "Observer son environnement de façon exhaustive. Permet de repérer des intrus, des pièges, des guets-apens et des indices.",
"arts": "Domaines artistiques au sens large : musique, littérature, théâtre, prestidigitation. Permet de captiver un auditoire ou de créer des œuvres.",
"inspiration": "Intuition et inconscient : écouter sa petite voix intérieure sans démarche logique préalable. Permet aussi de lire le comportement d'une personne.",
"traque": "Filer un individu ou un groupe, pister et s'orienter. Ouvre également vers les techniques de survie.",
"instruction": "Savoirs encyclopédiques : sciences humaines, sciences dures, sciences sociales et linguistique. Chaque tranche de 2 points permet de maîtriser une langue supplémentaire.",
"mtechnologique": "Technologies extraordinaires de Célestopol : mécanique, automates, ingénierie au sélénium, horlogerie, serrurerie et artisanat.",
"raisonnement": "Capacités cognitives : déduction froide, logique pragmatique, analyse des faits. Utile pour percevoir des liens dans une enquête.",
"traitement": "Techniques médicales et thérapeutiques : premiers secours, chirurgie, pharmacopée, psychanalyse et psychothérapie."
}
}, },
"Anomaly": { "Anomaly": {
"type": "Type d'anomalie", "type": "Type d'anomalie",
@@ -171,7 +189,12 @@
"renforts": "Renforts", "renforts": "Renforts",
"renseignements": "Renseignements", "renseignements": "Renseignements",
"ressources": "Ressources", "ressources": "Ressources",
"surveillance": "Surveillance" "surveillance": "Surveillance",
"resetButton": "Réinitialiser",
"resetTitle": "Réinitialiser les Aspects de faction",
"resetConfirm": "Voulez-vous réinitialiser tous les Aspects de faction mobilisés ? Cette action efface la réserve de scénario en cours.",
"resetConfirmYes": "Réinitialiser",
"resetSuccess": "Aspects de faction réinitialisés pour le nouveau scénario."
}, },
"Track": { "Track": {
"blessures": "Blessures", "blessures": "Blessures",
@@ -350,7 +373,22 @@
"mauvaiseFortune": "🔴 Mauvaise Fortune", "mauvaiseFortune": "🔴 Mauvaise Fortune",
"chanceInterpret": "Chance", "chanceInterpret": "Chance",
"narrativeInterpret": "Narratif", "narrativeInterpret": "Narratif",
"quantiteHint": "Valeur" "quantiteHint": "Valeur",
"applyChoose": "Choisissez la contrepartie :",
"effectNarrativeOnly": "(Narratif — sans effet mécanique)",
"effectRegainAnomaly": "🌟 Regain d'1 Anomalie",
"effectLoseSpleen": "💚 Perte d'1 Spleen",
"effectGainDestin": "⭐ Gain de 2 Destin",
"effectLoseDestin": "⭐ Perte de 2 Destin",
"effectLoseAnomaly": "❌ Perte d'1 Anomalie",
"effectGainSpleen": "💔 Gain d'1 Spleen",
"effectApplied": "Contrepartie appliquée : {label}",
"noAnomaly": "Ce personnage n'a pas d'anomalie",
"anomalyFull": "L'anomalie est déjà au maximum d'utilisations",
"anomalyEmpty": "L'anomalie n'a plus d'utilisation disponible",
"spleenEmpty": "Le Spleen est déjà à 0",
"spleenFull": "Le Spleen est déjà au maximum",
"actorNotFound": "Personnage introuvable"
}, },
"Difficulty": { "Difficulty": {
"unknown": "Aucun seuil", "unknown": "Aucun seuil",
@@ -415,8 +453,23 @@
"rollMoonDieByDefault": { "rollMoonDieByDefault": {
"name": "Lancer le dé de la lune par défaut", "name": "Lancer le dé de la lune par défaut",
"hint": "Cocher automatiquement 'Lancer le dé de la lune' dans les fenêtres de jet" "hint": "Cocher automatiquement 'Lancer le dé de la lune' dans les fenêtres de jet"
},
"migrateOldSystem": {
"name": "Migration depuis l'ancien système",
"hint": "Importer un personnage exporté depuis l'ancien système Célestopol 1922 (celestopol1922).",
"label": "Migrer un personnage…"
} }
}, },
"Migration": {
"title": "Migration ancien système Célestopol",
"instructions": "Sélectionnez un fichier JSON exporté depuis l'ancien système Célestopol 1922. Le personnage sera converti et créé automatiquement dans la liste des acteurs.",
"fileLabel": "Fichier JSON :",
"importBtn": "Convertir et importer",
"success": "'{name}' importé avec succès ({count} item(s)).",
"warnings": "{count} avertissement(s) — consultez la console (F12) pour le détail.",
"errorParse": "Impossible de lire le fichier JSON. Vérifiez qu'il s'agit bien d'un export Célestopol valide.",
"errorCreate": "Échec de la création de l'acteur. Consultez la console (F12) pour le détail."
},
"Welcome": { "Welcome": {
"title": "Bienvenue dans Célestopol 1922", "title": "Bienvenue dans Célestopol 1922",
"intro": "Bienvenue dans le système FoundryVTT de Célestopol 1922.", "intro": "Bienvenue dans le système FoundryVTT de Célestopol 1922.",
@@ -32,6 +32,7 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
supprimerXpLog: CelestopolCharacterSheet.#onSupprimerXpLog, supprimerXpLog: CelestopolCharacterSheet.#onSupprimerXpLog,
rollMoonDie: CelestopolCharacterSheet.#onRollMoonDie, rollMoonDie: CelestopolCharacterSheet.#onRollMoonDie,
manageFactionAspects: CelestopolCharacterSheet.#onManageFactionAspects, manageFactionAspects: CelestopolCharacterSheet.#onManageFactionAspects,
resetFactionAspects: CelestopolCharacterSheet.#onResetFactionAspects,
}, },
} }
@@ -245,6 +246,10 @@ export default class CelestopolCharacterSheet extends CelestopolActorSheet {
await game.celestopol?.manageFactionAspects(this.document) await game.celestopol?.manageFactionAspects(this.document)
} }
static async #onResetFactionAspects() {
await game.celestopol?.resetFactionAspects()
}
/** Ouvre un dialogue pour dépenser de l'XP. */ /** Ouvre un dialogue pour dépenser de l'XP. */
static async #onDepenseXp() { static async #onDepenseXp() {
const actor = this.document const actor = this.document
+16 -16
View File
@@ -31,28 +31,28 @@ export const STATS = {
/** Domaines groupées par attribut. */ /** Domaines groupées par attribut. */
export const SKILLS = { export const SKILLS = {
ame: { ame: {
artifice: { id: "artifice", label: "CELESTOPOL.Skill.artifice", stat: "ame", resThreshold: 5 }, artifice: { id: "artifice", label: "CELESTOPOL.Skill.artifice", tooltip: "CELESTOPOL.Skill.tooltip.artifice", stat: "ame", resThreshold: 5 },
attraction: { id: "attraction", label: "CELESTOPOL.Skill.attraction", stat: "ame", resThreshold: 2 }, attraction: { id: "attraction", label: "CELESTOPOL.Skill.attraction", tooltip: "CELESTOPOL.Skill.tooltip.attraction", stat: "ame", resThreshold: 2 },
coercition: { id: "coercition", label: "CELESTOPOL.Skill.coercition", stat: "ame", resThreshold: 3 }, coercition: { id: "coercition", label: "CELESTOPOL.Skill.coercition", tooltip: "CELESTOPOL.Skill.tooltip.coercition", stat: "ame", resThreshold: 3 },
faveur: { id: "faveur", label: "CELESTOPOL.Skill.faveur", stat: "ame", resThreshold: 6 }, faveur: { id: "faveur", label: "CELESTOPOL.Skill.faveur", tooltip: "CELESTOPOL.Skill.tooltip.faveur", stat: "ame", resThreshold: 6 },
}, },
corps: { corps: {
echauffouree: { id: "echauffouree", label: "CELESTOPOL.Skill.echauffouree", stat: "corps", resThreshold: 6 }, echauffouree: { id: "echauffouree", label: "CELESTOPOL.Skill.echauffouree", tooltip: "CELESTOPOL.Skill.tooltip.echauffouree", stat: "corps", resThreshold: 6 },
effacement: { id: "effacement", label: "CELESTOPOL.Skill.effacement", stat: "corps", resThreshold: 3 }, effacement: { id: "effacement", label: "CELESTOPOL.Skill.effacement", tooltip: "CELESTOPOL.Skill.tooltip.effacement", stat: "corps", resThreshold: 3 },
mobilite: { id: "mobilite", label: "CELESTOPOL.Skill.mobilite", stat: "corps", resThreshold: 2 }, mobilite: { id: "mobilite", label: "CELESTOPOL.Skill.mobilite", tooltip: "CELESTOPOL.Skill.tooltip.mobilite", stat: "corps", resThreshold: 2 },
prouesse: { id: "prouesse", label: "CELESTOPOL.Skill.prouesse", stat: "corps", resThreshold: 5 }, prouesse: { id: "prouesse", label: "CELESTOPOL.Skill.prouesse", tooltip: "CELESTOPOL.Skill.tooltip.prouesse", stat: "corps", resThreshold: 5 },
}, },
coeur: { coeur: {
appreciation: { id: "appreciation", label: "CELESTOPOL.Skill.appreciation", stat: "coeur", resThreshold: 6 }, appreciation: { id: "appreciation", label: "CELESTOPOL.Skill.appreciation", tooltip: "CELESTOPOL.Skill.tooltip.appreciation", stat: "coeur", resThreshold: 6 },
arts: { id: "arts", label: "CELESTOPOL.Skill.arts", stat: "coeur", resThreshold: 2 }, arts: { id: "arts", label: "CELESTOPOL.Skill.arts", tooltip: "CELESTOPOL.Skill.tooltip.arts", stat: "coeur", resThreshold: 2 },
inspiration: { id: "inspiration", label: "CELESTOPOL.Skill.inspiration", stat: "coeur", resThreshold: 3 }, inspiration: { id: "inspiration", label: "CELESTOPOL.Skill.inspiration", tooltip: "CELESTOPOL.Skill.tooltip.inspiration", stat: "coeur", resThreshold: 3 },
traque: { id: "traque", label: "CELESTOPOL.Skill.traque", stat: "coeur", resThreshold: 5 }, traque: { id: "traque", label: "CELESTOPOL.Skill.traque", tooltip: "CELESTOPOL.Skill.tooltip.traque", stat: "coeur", resThreshold: 5 },
}, },
esprit: { esprit: {
instruction: { id: "instruction", label: "CELESTOPOL.Skill.instruction", stat: "esprit", resThreshold: 2 }, instruction: { id: "instruction", label: "CELESTOPOL.Skill.instruction", tooltip: "CELESTOPOL.Skill.tooltip.instruction", stat: "esprit", resThreshold: 2 },
mtechnologique: { id: "mtechnologique", label: "CELESTOPOL.Skill.mtechnologique", stat: "esprit", resThreshold: 6 }, mtechnologique: { id: "mtechnologique", label: "CELESTOPOL.Skill.mtechnologique", tooltip: "CELESTOPOL.Skill.tooltip.mtechnologique", stat: "esprit", resThreshold: 6 },
raisonnement: { id: "raisonnement", label: "CELESTOPOL.Skill.raisonnement", stat: "esprit", resThreshold: 5 }, raisonnement: { id: "raisonnement", label: "CELESTOPOL.Skill.raisonnement", tooltip: "CELESTOPOL.Skill.tooltip.raisonnement", stat: "esprit", resThreshold: 5 },
traitement: { id: "traitement", label: "CELESTOPOL.Skill.traitement", stat: "esprit", resThreshold: 3 }, traitement: { id: "traitement", label: "CELESTOPOL.Skill.traitement", tooltip: "CELESTOPOL.Skill.tooltip.traitement", stat: "esprit", resThreshold: 3 },
}, },
} }
+9 -1
View File
@@ -639,6 +639,10 @@ export class CelestopolRoll extends Roll {
moonResultClass: moonResultType?.cssClass ?? "", moonResultClass: moonResultType?.cssClass ?? "",
moonResultLabel: moonResultType ? game.i18n.localize(moonResultType.label) : "", moonResultLabel: moonResultType ? game.i18n.localize(moonResultType.label) : "",
moonResultDesc: moonResultType ? game.i18n.localize(moonResultType.desc) : "", moonResultDesc: moonResultType ? game.i18n.localize(moonResultType.desc) : "",
moonResultTypeId: moonResultType?.id ?? null,
moonActorId: (actorType === "character") ? (this.options.actorId ?? null) : null,
moonActorUuid: (actorType === "character") ? (this.options.actorUuid ?? null) : null,
moonActorIsCharacter: actorType === "character",
isPrivate, isPrivate,
tooltip: isPrivate ? "" : await this.getTooltip(), tooltip: isPrivate ? "" : await this.getTooltip(),
} }
@@ -698,6 +702,7 @@ export class CelestopolRoll extends Roll {
const resultType = face ? SYSTEM.MOON_RESULT_TYPES[face.result] ?? null : null const resultType = face ? SYSTEM.MOON_RESULT_TYPES[face.result] ?? null : null
const isGoodFortune = result <= 4 const isGoodFortune = result <= 4
const actorIsCharacter = actor?.type === "character"
const templateData = { const templateData = {
result, result,
moonFaceSymbol: face?.symbol ?? "", moonFaceSymbol: face?.symbol ?? "",
@@ -705,8 +710,12 @@ export class CelestopolRoll extends Roll {
moonResultLabel: resultType ? game.i18n.localize(resultType.label) : "", moonResultLabel: resultType ? game.i18n.localize(resultType.label) : "",
moonResultDesc: resultType ? game.i18n.localize(resultType.desc) : "", moonResultDesc: resultType ? game.i18n.localize(resultType.desc) : "",
moonResultClass: resultType?.cssClass ?? "", moonResultClass: resultType?.cssClass ?? "",
moonResultTypeId: resultType?.id ?? null,
isGoodFortune, isGoodFortune,
actorName: actor?.name ?? null, actorName: actor?.name ?? null,
moonActorIsCharacter: actorIsCharacter,
moonActorId: actorIsCharacter ? (actor.id ?? null) : null,
moonActorUuid: actorIsCharacter ? (actor.uuid ?? null) : null,
} }
const content = await foundry.applications.handlebars.renderTemplate( const content = await foundry.applications.handlebars.renderTemplate(
@@ -721,7 +730,6 @@ export class CelestopolRoll extends Roll {
await ChatMessage.create({ await ChatMessage.create({
content, content,
speaker, speaker,
rolls: [roll],
style: CONST.CHAT_MESSAGE_STYLES.OTHER, style: CONST.CHAT_MESSAGE_STYLES.OTHER,
}) })
} }
+5 -5
View File
@@ -231,7 +231,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
difficulty: this.prefs.difficulty, difficulty: this.prefs.difficulty,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
}) })
} }
@@ -343,7 +343,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"), armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: false, isRangedDefense: false,
@@ -376,7 +376,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"), armorMalus: this.getArmorMalusForRoll("corps", "echauffouree"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: false, isRangedDefense: false,
@@ -415,7 +415,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "mobilite"), armorMalus: this.getArmorMalusForRoll("corps", "mobilite"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: true, isRangedDefense: true,
@@ -449,7 +449,7 @@ export default class CelestopolCharacter extends foundry.abstract.TypeDataModel
armorMalus: this.getArmorMalusForRoll("corps", "mobilite"), armorMalus: this.getArmorMalusForRoll("corps", "mobilite"),
woundLevel: this.blessures.lvl, woundLevel: this.blessures.lvl,
rollMoonDie: this.prefs.rollMoonDie ?? false, rollMoonDie: this.prefs.rollMoonDie ?? false,
destGaugeFull: this.destin.lvl > 0, destGaugeFull: this.destin.lvl >= 8,
fortuneValue: this.attributs.fortune.value, fortuneValue: this.attributs.fortune.value,
isCombat: true, isCombat: true,
isRangedDefense: true, isRangedDefense: true,
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000074 MANIFEST-000097
+7 -3
View File
@@ -1,3 +1,7 @@
2026/04/14-10:43:54.304360 7fddcbfff6c0 Recovering log #72 2026/04/27-22:18:49.718901 7fed937fe6c0 Recovering log #95
2026/04/14-10:43:54.314599 7fddcbfff6c0 Delete type=3 #70 2026/04/27-22:18:49.728863 7fed937fe6c0 Delete type=3 #93
2026/04/14-10:43:54.314647 7fddcbfff6c0 Delete type=0 #72 2026/04/27-22:18:49.728935 7fed937fe6c0 Delete type=0 #95
2026/04/27-22:29:30.180780 7feb10fff6c0 Level-0 table #100: started
2026/04/27-22:29:30.180810 7feb10fff6c0 Level-0 table #100: 0 bytes OK
2026/04/27-22:29:30.187367 7feb10fff6c0 Delete type=0 #98
2026/04/27-22:29:30.210881 7feb10fff6c0 Manual compaction at level-0 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end)
+7 -8
View File
@@ -1,8 +1,7 @@
2026/04/14-00:55:24.427256 7f68497ed6c0 Recovering log #68 2026/04/27-22:04:32.581280 7fed927fc6c0 Recovering log #91
2026/04/14-00:55:24.442232 7f68497ed6c0 Delete type=3 #66 2026/04/27-22:04:32.591253 7fed927fc6c0 Delete type=3 #89
2026/04/14-00:55:24.442302 7f68497ed6c0 Delete type=0 #68 2026/04/27-22:04:32.591326 7fed927fc6c0 Delete type=0 #91
2026/04/14-00:56:01.490011 7f6833fff6c0 Level-0 table #73: started 2026/04/27-22:06:50.324351 7feb10fff6c0 Level-0 table #96: started
2026/04/14-00:56:01.490050 7f6833fff6c0 Level-0 table #73: 0 bytes OK 2026/04/27-22:06:50.324370 7feb10fff6c0 Level-0 table #96: 0 bytes OK
2026/04/14-00:56:01.496026 7f6833fff6c0 Delete type=0 #71 2026/04/27-22:06:50.330761 7feb10fff6c0 Delete type=0 #94
2026/04/14-00:56:01.502797 7f6833fff6c0 Manual compaction at level-0 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end) 2026/04/27-22:06:50.339938 7feb10fff6c0 Manual compaction at level-0 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end)
2026/04/14-00:56:01.513341 7f6833fff6c0 Manual compaction at level-1 from '!journal!eNYstmPK0mMmVJYC' @ 72057594037927935 : 1 .. '!journal.pages!eNYstmPK0mMmVJYC.r9h1ggd3G9hiqYJX' @ 0 : 0; will stop at (end)
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000127 MANIFEST-000157
+14 -3
View File
@@ -1,3 +1,14 @@
2026/04/14-10:43:54.279048 7fddd97be6c0 Recovering log #124 2026/04/27-22:18:49.690384 7fed92ffd6c0 Recovering log #154
2026/04/14-10:43:54.288686 7fddd97be6c0 Delete type=3 #122 2026/04/27-22:18:49.702685 7fed92ffd6c0 Delete type=3 #152
2026/04/14-10:43:54.288755 7fddd97be6c0 Delete type=0 #124 2026/04/27-22:18:49.702754 7fed92ffd6c0 Delete type=0 #154
2026/04/27-22:29:30.170390 7feb10fff6c0 Level-0 table #160: started
2026/04/27-22:29:30.173958 7feb10fff6c0 Level-0 table #160: 3524 bytes OK
2026/04/27-22:29:30.180662 7feb10fff6c0 Delete type=0 #158
2026/04/27-22:29:30.201177 7feb10fff6c0 Manual compaction at level-0 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 133 : 1
2026/04/27-22:29:30.201186 7feb10fff6c0 Compacting 1@0 + 1@1 files
2026/04/27-22:29:30.204413 7feb10fff6c0 Generated table #161@0: 9 keys, 6617 bytes
2026/04/27-22:29:30.204438 7feb10fff6c0 Compacted 1@0 + 1@1 files => 6617 bytes
2026/04/27-22:29:30.210527 7feb10fff6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/04/27-22:29:30.210659 7feb10fff6c0 Delete type=2 #156
2026/04/27-22:29:30.210789 7feb10fff6c0 Delete type=2 #160
2026/04/27-22:29:30.210920 7feb10fff6c0 Manual compaction at level-0 from '!items!null' @ 133 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
+14 -15
View File
@@ -1,15 +1,14 @@
2026/04/14-00:55:24.391968 7f6848fec6c0 Recovering log #119 2026/04/27-22:04:32.549946 7fed937fe6c0 Recovering log #149
2026/04/14-00:55:24.406978 7f6848fec6c0 Delete type=3 #117 2026/04/27-22:04:32.561235 7fed937fe6c0 Delete type=3 #147
2026/04/14-00:55:24.407044 7f6848fec6c0 Delete type=0 #119 2026/04/27-22:04:32.561293 7fed937fe6c0 Delete type=0 #149
2026/04/14-00:56:01.480723 7f6833fff6c0 Level-0 table #125: started 2026/04/27-22:06:50.330846 7feb10fff6c0 Level-0 table #155: started
2026/04/14-00:56:01.483872 7f6833fff6c0 Level-0 table #125: 3524 bytes OK 2026/04/27-22:06:50.333934 7feb10fff6c0 Level-0 table #155: 3524 bytes OK
2026/04/14-00:56:01.489828 7f6833fff6c0 Delete type=0 #123 2026/04/27-22:06:50.339817 7feb10fff6c0 Delete type=0 #153
2026/04/14-00:56:01.502786 7f6833fff6c0 Manual compaction at level-0 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at (end) 2026/04/27-22:06:50.339951 7feb10fff6c0 Manual compaction at level-0 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 129 : 1
2026/04/14-00:56:01.502828 7f6833fff6c0 Manual compaction at level-1 from '!items!anomCommMorts001' @ 72057594037927935 : 1 .. '!items!null' @ 0 : 0; will stop at '!items!null' @ 105 : 1 2026/04/27-22:06:50.339958 7feb10fff6c0 Compacting 1@0 + 1@1 files
2026/04/14-00:56:01.502835 7f6833fff6c0 Compacting 1@1 + 1@2 files 2026/04/27-22:06:50.343129 7feb10fff6c0 Generated table #156@0: 9 keys, 6617 bytes
2026/04/14-00:56:01.506551 7f6833fff6c0 Generated table #126@1: 9 keys, 6617 bytes 2026/04/27-22:06:50.343143 7feb10fff6c0 Compacted 1@0 + 1@1 files => 6617 bytes
2026/04/14-00:56:01.506586 7f6833fff6c0 Compacted 1@1 + 1@2 files => 6617 bytes 2026/04/27-22:06:50.349117 7feb10fff6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2026/04/14-00:56:01.512723 7f6833fff6c0 compacted to: files[ 0 0 1 0 0 0 0 ] 2026/04/27-22:06:50.349224 7feb10fff6c0 Delete type=2 #151
2026/04/14-00:56:01.513072 7f6833fff6c0 Delete type=2 #121 2026/04/27-22:06:50.349379 7feb10fff6c0 Delete type=2 #155
2026/04/14-00:56:01.513274 7f6833fff6c0 Delete type=2 #125 2026/04/27-22:06:50.368353 7feb10fff6c0 Manual compaction at level-0 from '!items!null' @ 129 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
2026/04/14-00:56:01.519560 7f6833fff6c0 Manual compaction at level-1 from '!items!null' @ 105 : 1 .. '!items!null' @ 0 : 0; will stop at (end)
Binary file not shown.
Binary file not shown.
View File
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000035 MANIFEST-000058
+7 -3
View File
@@ -1,3 +1,7 @@
2026/04/14-10:43:54.291004 7fddd8fbd6c0 Recovering log #33 2026/04/27-22:18:49.704865 7fed93fff6c0 Recovering log #56
2026/04/14-10:43:54.301929 7fddd8fbd6c0 Delete type=3 #31 2026/04/27-22:18:49.714938 7fed93fff6c0 Delete type=3 #54
2026/04/14-10:43:54.301981 7fddd8fbd6c0 Delete type=0 #33 2026/04/27-22:18:49.714987 7fed93fff6c0 Delete type=0 #56
2026/04/27-22:29:30.194650 7feb10fff6c0 Level-0 table #61: started
2026/04/27-22:29:30.194677 7feb10fff6c0 Level-0 table #61: 0 bytes OK
2026/04/27-22:29:30.201065 7feb10fff6c0 Delete type=0 #59
2026/04/27-22:29:30.210910 7feb10fff6c0 Manual compaction at level-0 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end)
+7 -8
View File
@@ -1,8 +1,7 @@
2026/04/14-00:55:24.409141 7f68497ed6c0 Recovering log #29 2026/04/27-22:04:32.565909 7fed92ffd6c0 Recovering log #52
2026/04/14-00:55:24.424702 7f68497ed6c0 Delete type=3 #27 2026/04/27-22:04:32.576099 7fed92ffd6c0 Delete type=3 #50
2026/04/14-00:55:24.424755 7f68497ed6c0 Delete type=0 #29 2026/04/27-22:04:32.576173 7fed92ffd6c0 Delete type=0 #52
2026/04/14-00:56:01.473754 7f6833fff6c0 Level-0 table #34: started 2026/04/27-22:06:50.318454 7feb10fff6c0 Level-0 table #57: started
2026/04/14-00:56:01.473797 7f6833fff6c0 Level-0 table #34: 0 bytes OK 2026/04/27-22:06:50.318473 7feb10fff6c0 Level-0 table #57: 0 bytes OK
2026/04/14-00:56:01.480607 7f6833fff6c0 Delete type=0 #32 2026/04/27-22:06:50.324288 7feb10fff6c0 Delete type=0 #55
2026/04/14-00:56:01.502772 7f6833fff6c0 Manual compaction at level-0 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end) 2026/04/27-22:06:50.339928 7feb10fff6c0 Manual compaction at level-0 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end)
2026/04/14-00:56:01.502817 7f6833fff6c0 Manual compaction at level-1 from '!actors!6RZ6IzJUHm4dB5Ut' @ 72057594037927935 : 1 .. '!folders!MbFQgPdF6Gtbj5AU' @ 0 : 0; will stop at (end)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
View File
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000074 MANIFEST-000100
+7 -3
View File
@@ -1,3 +1,7 @@
2026/04/14-10:43:54.317254 7fddd9fbf6c0 Recovering log #72 2026/04/27-22:18:49.731702 7fed93fff6c0 Recovering log #98
2026/04/14-10:43:54.326872 7fddd9fbf6c0 Delete type=3 #70 2026/04/27-22:18:49.741999 7fed93fff6c0 Delete type=3 #96
2026/04/14-10:43:54.326932 7fddd9fbf6c0 Delete type=0 #72 2026/04/27-22:18:49.742065 7fed93fff6c0 Delete type=0 #98
2026/04/27-22:29:30.187494 7feb10fff6c0 Level-0 table #103: started
2026/04/27-22:29:30.187529 7feb10fff6c0 Level-0 table #103: 0 bytes OK
2026/04/27-22:29:30.194521 7feb10fff6c0 Delete type=0 #101
2026/04/27-22:29:30.210897 7feb10fff6c0 Manual compaction at level-0 from '!scenes!0iGCRqkdJKjmmbl4' @ 72057594037927935 : 1 .. '!scenes.levels!X3XJg7raEXtOFOtj.defaultLevel0000' @ 0 : 0; will stop at (end)
+7 -8
View File
@@ -1,8 +1,7 @@
2026/04/14-00:55:24.444791 7f684a7ef6c0 Recovering log #68 2026/04/27-22:04:32.595481 7fed93fff6c0 Recovering log #94
2026/04/14-00:55:24.460229 7f684a7ef6c0 Delete type=3 #66 2026/04/27-22:04:32.606129 7fed93fff6c0 Delete type=3 #92
2026/04/14-00:55:24.460280 7f684a7ef6c0 Delete type=0 #68 2026/04/27-22:04:32.606193 7fed93fff6c0 Delete type=0 #94
2026/04/14-00:56:01.496164 7f6833fff6c0 Level-0 table #73: started 2026/04/27-22:06:50.312356 7feb10fff6c0 Level-0 table #99: started
2026/04/14-00:56:01.496194 7f6833fff6c0 Level-0 table #73: 0 bytes OK 2026/04/27-22:06:50.312415 7feb10fff6c0 Level-0 table #99: 0 bytes OK
2026/04/14-00:56:01.502678 7f6833fff6c0 Delete type=0 #71 2026/04/27-22:06:50.318377 7feb10fff6c0 Delete type=0 #97
2026/04/14-00:56:01.502807 7f6833fff6c0 Manual compaction at level-0 from '!scenes!Jr7lGxYk2RETlXRv' @ 72057594037927935 : 1 .. '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 0 : 0; will stop at (end) 2026/04/27-22:06:50.339915 7feb10fff6c0 Manual compaction at level-0 from '!scenes!0iGCRqkdJKjmmbl4' @ 72057594037927935 : 1 .. '!scenes.levels!X3XJg7raEXtOFOtj.defaultLevel0000' @ 0 : 0; will stop at (end)
2026/04/14-00:56:01.513358 7f6833fff6c0 Manual compaction at level-1 from '!scenes!Jr7lGxYk2RETlXRv' @ 72057594037927935 : 1 .. '!scenes.tokens.delta.items!Jr7lGxYk2RETlXRv.6urwC5SVcou6UOAG.CTg4yBE12iMee1RU.BYT1CrA37R3Og0nu' @ 0 : 0; will stop at (end)
Binary file not shown.
Binary file not shown.
View File
+44 -44
View File
@@ -24,7 +24,7 @@
min-width: 54px; min-width: 54px;
label { label {
font-size: 0.58em; font-size: 0.6em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--cel-orange-light); color: var(--cel-orange-light);
@@ -34,12 +34,12 @@
.stat-value, .attr-display { .stat-value, .attr-display {
color: var(--cel-orange); color: var(--cel-orange);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.05em; font-size: 1.2em;
font-weight: bold; font-weight: bold;
line-height: 1.2; line-height: 1.2;
} }
.attr-sep { color: rgba(196,154,26,0.5); margin: 0 1px; font-size: 0.85em; } .attr-sep { color: rgba(196,154,26,0.5); margin: 0 1px; font-size: 0.8em; }
input.attr-val, input.attr-max { input.attr-val, input.attr-max {
width: 24px; width: 24px;
@@ -49,7 +49,7 @@
border-bottom: 1px solid var(--cel-orange-light); border-bottom: 1px solid var(--cel-orange-light);
color: var(--cel-orange); color: var(--cel-orange);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1em; font-size: 1.1em;
font-weight: bold; font-weight: bold;
} }
} }
@@ -60,7 +60,7 @@
.armor-malus-value { .armor-malus-value {
color: #e06040; color: #e06040;
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.05em; font-size: 1.2em;
font-weight: bold; font-weight: bold;
} }
label { color: #e06040; opacity: 0.8; } label { color: #e06040; opacity: 0.8; }
@@ -92,7 +92,7 @@
.stat-name { .stat-name {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-weight: bold; font-weight: bold;
font-size: 1em; font-size: 1.1em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
} }
@@ -121,7 +121,7 @@
border: 1px solid var(--cel-orange); border: 1px solid var(--cel-orange);
border-radius: 4px; border-radius: 4px;
background: rgba(224, 123, 0, 0.08); background: rgba(224, 123, 0, 0.08);
font-size: 0.78em; font-size: 0.8em;
cursor: default; cursor: default;
.res-die-icon { .res-die-icon {
@@ -164,7 +164,7 @@
justify-content: space-between; justify-content: space-between;
padding: 3px 8px; padding: 3px 8px;
border-bottom: 1px solid rgba(122,92,32,0.18); border-bottom: 1px solid rgba(122,92,32,0.18);
font-size: 0.85em; font-size: 0.8em;
// Alternating cream-dark rows for legibility // Alternating cream-dark rows for legibility
&:nth-child(even) { background: var(--cel-cream-dark); } &:nth-child(even) { background: var(--cel-cream-dark); }
@@ -279,7 +279,7 @@
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-weight: bold; font-weight: bold;
text-transform: uppercase; text-transform: uppercase;
font-size: 1.1em; font-size: 1.2em;
letter-spacing: 0.04em; letter-spacing: 0.04em;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -293,7 +293,7 @@
height: 14px; height: 14px;
border-radius: 50%; border-radius: 50%;
border: 1px solid currentColor; border: 1px solid currentColor;
font-size: 0.65em; font-size: 0.7em;
font-family: var(--cel-font-body); font-family: var(--cel-font-body);
font-weight: bold; font-weight: bold;
text-transform: none; text-transform: none;
@@ -349,7 +349,7 @@
gap: 6px; gap: 6px;
padding: 4px 8px; padding: 4px 8px;
background: rgba(139,115,85,0.1); background: rgba(139,115,85,0.1);
font-size: 0.85em; font-size: 0.8em;
label { color: var(--cel-border); } label { color: var(--cel-border); }
input[type="number"] { width: 40px; .cel-input-std(); } input[type="number"] { width: 40px; .cel-input-std(); }
} }
@@ -380,7 +380,7 @@
.faction-aspect-summary-title { .faction-aspect-summary-title {
color: var(--cel-green); color: var(--cel-green);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1em; font-size: 1.1em;
letter-spacing: 0.04em; letter-spacing: 0.04em;
text-transform: uppercase; text-transform: uppercase;
line-height: 1.05; line-height: 1.05;
@@ -393,7 +393,7 @@
color: var(--cel-orange); color: var(--cel-orange);
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
font-size: 0.84em; font-size: 0.8em;
white-space: nowrap; white-space: nowrap;
} }
@@ -413,7 +413,7 @@
.label { .label {
display: block; display: block;
font-size: 0.66em; font-size: 0.7em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.03em; letter-spacing: 0.03em;
color: var(--cel-border); color: var(--cel-border);
@@ -423,7 +423,7 @@
.value { .value {
color: var(--cel-orange); color: var(--cel-orange);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.02em; font-size: 1.1em;
line-height: 1; line-height: 1;
} }
} }
@@ -448,7 +448,7 @@
.faction-aspect-active-title { .faction-aspect-active-title {
margin-bottom: 4px; margin-bottom: 4px;
color: var(--cel-border); color: var(--cel-border);
font-size: 0.68em; font-size: 0.7em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
line-height: 1.1; line-height: 1.1;
@@ -477,20 +477,20 @@
.name { .name {
color: var(--cel-green); color: var(--cel-green);
font-size: 0.88em; font-size: 0.9em;
} }
.value { .value {
color: var(--cel-orange); color: var(--cel-orange);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.9em; font-size: 1em;
} }
} }
.faction-aspect-empty { .faction-aspect-empty {
color: #666; color: #666;
font-style: italic; font-style: italic;
font-size: 0.84em; font-size: 0.8em;
} }
} }
@@ -505,7 +505,7 @@
background-image: url("../assets/ui/fond_cadrille.jpg"); background-image: url("../assets/ui/fond_cadrille.jpg");
background-blend-mode: soft-light; background-blend-mode: soft-light;
color: var(--cel-orange); color: var(--cel-orange);
th { padding: 5px 8px; font-family: var(--cel-font-title); font-size: 1.05em; letter-spacing: 0.06em; text-transform: uppercase; } th { padding: 5px 8px; font-family: var(--cel-font-title); font-size: 1.2em; letter-spacing: 0.06em; text-transform: uppercase; }
} }
.faction-row { .faction-row {
@@ -542,7 +542,7 @@
} }
.faction-count { .faction-count {
font-size: 0.85em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
color: var(--cel-orange); color: var(--cel-orange);
min-width: 16px; min-width: 16px;
@@ -569,7 +569,7 @@
border-bottom: 1px solid rgba(122,92,32,0.25); border-bottom: 1px solid rgba(122,92,32,0.25);
color: var(--cel-green); color: var(--cel-green);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.05em; font-size: 1.2em;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
} }
@@ -578,7 +578,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 4px; gap: 4px;
font-size: 0.88em; font-size: 0.9em;
} }
.factions-legend-row { .factions-legend-row {
@@ -634,7 +634,7 @@
} }
.item-tag { .item-tag {
font-size: 0.75em; font-size: 0.8em;
padding: 1px 7px; padding: 1px 7px;
border-radius: 10px; border-radius: 10px;
background: rgba(12,76,12,0.15); background: rgba(12,76,12,0.15);
@@ -661,7 +661,7 @@
justify-content: center; justify-content: center;
min-width: 20px; min-width: 20px;
min-height: 20px; min-height: 20px;
font-size: 1.08rem; font-size: 1.1rem;
line-height: 1; line-height: 1;
} }
} }
@@ -684,7 +684,7 @@
} }
.equip-empty { .equip-empty {
font-size: 0.85em; font-size: 0.8em;
font-style: italic; font-style: italic;
color: var(--cel-border); color: var(--cel-border);
padding: 4px 8px; padding: 4px 8px;
@@ -736,7 +736,7 @@
.biography-portrait-empty { .biography-portrait-empty {
padding: 14px; padding: 14px;
color: var(--cel-border); color: var(--cel-border);
font-size: 0.82em; font-size: 0.8em;
font-style: italic; font-style: italic;
text-align: center; text-align: center;
line-height: 1.5; line-height: 1.5;
@@ -769,7 +769,7 @@
border-radius: 4px; border-radius: 4px;
background: linear-gradient(180deg, rgba(255,255,255,0.82), rgba(233,223,201,0.95)); background: linear-gradient(180deg, rgba(255,255,255,0.82), rgba(233,223,201,0.95));
color: var(--cel-green); color: var(--cel-green);
font-size: 0.82em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
@@ -790,7 +790,7 @@
.biography-portrait-hint { .biography-portrait-hint {
margin: 0; margin: 0;
font-size: 0.78em; font-size: 0.8em;
font-style: italic; font-style: italic;
color: var(--cel-border); color: var(--cel-border);
} }
@@ -838,7 +838,7 @@
text-align: center; text-align: center;
.cel-input-std(); .cel-input-std();
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.1em; font-size: 1.2em;
font-weight: bold; font-weight: bold;
color: var(--cel-green); color: var(--cel-green);
} }
@@ -848,7 +848,7 @@
border-color: rgba(122,92,32,0.4); border-color: rgba(122,92,32,0.4);
.xp-depense-value { .xp-depense-value {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.1em; font-size: 1.2em;
font-weight: bold; font-weight: bold;
color: var(--cel-border); color: var(--cel-border);
} }
@@ -858,7 +858,7 @@
background: var(--cel-green); background: var(--cel-green);
border: 1px solid var(--cel-orange); border: 1px solid var(--cel-orange);
color: var(--cel-orange); color: var(--cel-orange);
font-size: 0.78em; font-size: 0.9em;
padding: 5px 12px; padding: 5px 12px;
cursor: pointer; cursor: pointer;
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
@@ -875,14 +875,14 @@
.xp-log-table { .xp-log-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
font-size: 0.82em; font-size: 0.8em;
margin-bottom: 8px; margin-bottom: 8px;
thead tr { thead tr {
background: rgba(12,76,12,0.35); background: rgba(12,76,12,0.35);
th { th {
color: var(--cel-orange-light); color: var(--cel-orange-light);
font-size: 0.75em; font-size: 0.8em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
padding: 3px 6px; padding: 3px 6px;
@@ -918,7 +918,7 @@
.xp-ref { .xp-ref {
margin-top: 6px; margin-top: 6px;
summary { summary {
font-size: 0.78em; font-size: 0.8em;
color: var(--cel-orange-light); color: var(--cel-orange-light);
cursor: pointer; cursor: pointer;
letter-spacing: 0.03em; letter-spacing: 0.03em;
@@ -930,7 +930,7 @@
.xp-ref-table { .xp-ref-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
font-size: 0.82em; font-size: 0.8em;
margin-top: 6px; margin-top: 6px;
thead tr { thead tr {
@@ -941,7 +941,7 @@
} }
th { th {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.9em; font-size: 1em;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
padding: 4px 8px; padding: 4px 8px;
@@ -987,7 +987,7 @@
.anomaly-block-title { .anomaly-block-title {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.85em; font-size: 0.9em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.07em; letter-spacing: 0.07em;
color: var(--cel-orange); color: var(--cel-orange);
@@ -1000,7 +1000,7 @@
text-align: center; text-align: center;
color: var(--cel-border); color: var(--cel-border);
font-style: italic; font-style: italic;
font-size: 0.85em; font-size: 0.8em;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -1030,12 +1030,12 @@
flex: 1; flex: 1;
.anomaly-name { .anomaly-name {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1em; font-size: 1.1em;
color: var(--cel-orange); color: var(--cel-orange);
font-weight: bold; font-weight: bold;
} }
.anomaly-subtype { .anomaly-subtype {
font-size: 0.75em; font-size: 0.8em;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
@@ -1057,7 +1057,7 @@
margin-bottom: 6px; margin-bottom: 6px;
.anomaly-level-label { .anomaly-level-label {
font-size: 0.72em; font-size: 0.7em;
text-transform: uppercase; text-transform: uppercase;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
opacity: 0.7; opacity: 0.7;
@@ -1085,7 +1085,7 @@
flex-wrap: wrap; flex-wrap: wrap;
.anomaly-uses-label { .anomaly-uses-label {
font-size: 0.72em; font-size: 0.7em;
text-transform: uppercase; text-transform: uppercase;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
opacity: 0.7; opacity: 0.7;
@@ -1110,7 +1110,7 @@
background: var(--cel-green); background: var(--cel-green);
border: 1px solid var(--cel-orange); border: 1px solid var(--cel-orange);
color: var(--cel-orange); color: var(--cel-orange);
font-size: 0.72em; font-size: 0.8em;
padding: 2px 8px; padding: 2px 8px;
cursor: pointer; cursor: pointer;
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
+2 -2
View File
@@ -1,13 +1,13 @@
@font-face { @font-face {
font-family: "CopaseticNF"; font-family: "CopaseticNF";
src: url("../assets/fonts/CopaseticNF.otf") format("opentype"); src: url("../assets/fonts/CopaseticNF.woff");
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: "CopaseticNF"; font-family: "CopaseticNF";
src: url("../assets/fonts/CopaseticNF-Bold.otf") format("opentype"); src: url("../assets/fonts/CopaseticNF-Bold.woff");
font-weight: bold; font-weight: bold;
font-style: normal; font-style: normal;
} }
+9 -8
View File
@@ -16,6 +16,7 @@
--cel-border: #7a5c20; // bordure dorée --cel-border: #7a5c20; // bordure dorée
--cel-accent: #6b1e28; // bordeaux profond (échecs, accents) --cel-accent: #6b1e28; // bordeaux profond (échecs, accents)
--cel-text: #2f2413; // texte de corps sur fond clair (parchemin)
--cel-shadow: rgba(10,15,10,0.5); --cel-shadow: rgba(10,15,10,0.5);
@@ -84,7 +85,7 @@
border-bottom: 1px solid rgba(196,154,26,0.5); border-bottom: 1px solid rgba(196,154,26,0.5);
color: var(--cel-orange); color: var(--cel-orange);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.4em; font-size: 1.5em;
font-weight: bold; font-weight: bold;
letter-spacing: 0.06em; letter-spacing: 0.06em;
padding: 2px 4px; padding: 2px 4px;
@@ -93,7 +94,7 @@
.actor-name { .actor-name {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.4em; font-size: 1.5em;
color: var(--cel-orange); color: var(--cel-orange);
letter-spacing: 0.06em; letter-spacing: 0.06em;
margin: 0; margin: 0;
@@ -119,7 +120,7 @@
gap: 4px; gap: 4px;
label { label {
font-size: 0.65em; font-size: 0.7em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
color: var(--cel-orange-light); color: var(--cel-orange-light);
@@ -130,7 +131,7 @@
// Styles identiques play mode et edit mode // Styles identiques play mode et edit mode
span, span,
input[type="text"] { input[type="text"] {
font-size: 0.95em; font-size: 0.9em;
font-family: inherit; font-family: inherit;
font-style: italic; font-style: italic;
color: var(--cel-cream); color: var(--cel-cream);
@@ -172,14 +173,14 @@
min-width: 52px; min-width: 52px;
label { label {
font-size: 0.62em; font-size: 0.6em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
color: var(--cel-orange-light); color: var(--cel-orange-light);
} }
.stat-value { .stat-value {
font-size: 1.4em; font-size: 1.5em;
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
color: var(--cel-orange); color: var(--cel-orange);
font-weight: bold; font-weight: bold;
@@ -241,7 +242,7 @@
padding: 8px 16px; padding: 8px 16px;
color: rgba(240,232,212,0.8); color: rgba(240,232,212,0.8);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.85em; font-size: 0.9em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.07em; letter-spacing: 0.07em;
cursor: pointer; cursor: pointer;
@@ -330,7 +331,7 @@
.wound-value { .wound-value {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.95em; font-size: 1.1em;
font-weight: bold; font-weight: bold;
white-space: nowrap; white-space: nowrap;
line-height: 1.2; line-height: 1.2;
+20 -20
View File
@@ -22,7 +22,7 @@
.anomaly-section-title { .anomaly-section-title {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.78em; font-size: 0.9em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.07em; letter-spacing: 0.07em;
color: var(--cel-green-dark, #0c4c0c); color: var(--cel-green-dark, #0c4c0c);
@@ -39,7 +39,7 @@
min-height: 60px; min-height: 60px;
padding: 4px 6px; padding: 4px 6px;
color: #1a1209; color: #1a1209;
font-size: 0.88em; font-size: 0.9em;
line-height: 1.5; line-height: 1.5;
.editor-content, .prosemirror { color: #1a1209; background: transparent; } .editor-content, .prosemirror { color: #1a1209; background: transparent; }
p { margin: 0 0 4px 0; color: #1a1209; } p { margin: 0 0 4px 0; color: #1a1209; }
@@ -77,7 +77,7 @@
border-bottom: 1px solid var(--cel-orange-light); border-bottom: 1px solid var(--cel-orange-light);
color: var(--cel-orange); color: var(--cel-orange);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.2em; font-size: 1.3em;
font-weight: bold; font-weight: bold;
padding: 2px 4px; padding: 2px 4px;
} }
@@ -114,7 +114,7 @@
background: transparent; background: transparent;
border: 1px solid var(--cel-orange-light); border: 1px solid var(--cel-orange-light);
color: var(--cel-orange); color: var(--cel-orange);
font-size: 0.85em; font-size: 0.8em;
option { background: var(--cel-green-dark); color: var(--cel-cream); } option { background: var(--cel-green-dark); color: var(--cel-cream); }
} }
} }
@@ -123,7 +123,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
label { color: var(--cel-orange-light); font-size: 0.75em; text-transform: uppercase; } label { color: var(--cel-orange-light); font-size: 0.8em; text-transform: uppercase; }
input[type="number"] { input[type="number"] {
width: 40px; width: 40px;
background: transparent; background: transparent;
@@ -147,7 +147,7 @@
padding: 5px 12px; padding: 5px 12px;
color: rgba(240,232,212,0.7); color: rgba(240,232,212,0.7);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.78em; font-size: 0.9em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.07em; letter-spacing: 0.07em;
cursor: pointer; cursor: pointer;
@@ -186,7 +186,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
label { color: var(--cel-orange-light); font-size: 0.72em; text-transform: uppercase; } label { color: var(--cel-orange-light); font-size: 0.7em; text-transform: uppercase; }
input[type="number"] { input[type="number"] {
width: 44px; width: 44px;
background: transparent; background: transparent;
@@ -207,7 +207,7 @@
margin-bottom: 8px; margin-bottom: 8px;
label { label {
display: block; display: block;
font-size: 0.75em; font-size: 0.8em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
color: var(--cel-border); // #7a5c20 — contraste WCAG AA sur fond crème color: var(--cel-border); // #7a5c20 — contraste WCAG AA sur fond crème
@@ -228,7 +228,7 @@
.scores-stat-col { .scores-stat-col {
.scores-stat-name { .scores-stat-name {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.75em; font-size: 0.8em;
color: var(--cel-orange); // gold color: var(--cel-orange); // gold
text-transform: uppercase; text-transform: uppercase;
border-bottom: 1px solid var(--cel-border); border-bottom: 1px solid var(--cel-border);
@@ -266,7 +266,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
label { color: var(--cel-orange-light); font-size: 0.75em; text-transform: uppercase; } label { color: var(--cel-orange-light); font-size: 0.8em; text-transform: uppercase; }
.level-input, .anomaly-level-value { .level-input, .anomaly-level-value {
width: 38px; width: 38px;
background: transparent; background: transparent;
@@ -301,7 +301,7 @@
border: 1px solid rgba(196,154,26,0.4); border: 1px solid rgba(196,154,26,0.4);
color: var(--cel-orange); color: var(--cel-orange);
text-align: center; text-align: center;
font-size: 0.85em; font-size: 0.8em;
} }
} }
@@ -327,7 +327,7 @@
.anomaly-skills-label { .anomaly-skills-label {
color: var(--cel-orange-light, #c49a1a); color: var(--cel-orange-light, #c49a1a);
font-size: 0.72em; font-size: 0.7em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
margin-right: 2px; margin-right: 2px;
@@ -339,7 +339,7 @@
border: 1px solid rgba(196,154,26,0.55); border: 1px solid rgba(196,154,26,0.55);
border-radius: 3px; border-radius: 3px;
padding: 1px 7px; padding: 1px 7px;
font-size: 0.72em; font-size: 0.7em;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
} }
} }
@@ -368,8 +368,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
label { font-size: 0.75em; color: var(--cel-orange-light); white-space: nowrap; } label { font-size: 0.8em; color: var(--cel-orange-light); white-space: nowrap; }
select { background: rgba(0,0,0,0.3); border: 1px solid var(--cel-orange); color: var(--cel-orange); font-family: var(--cel-font-title); border-radius: 3px; padding: 2px 4px; font-size: 0.85em; } select { background: rgba(0,0,0,0.3); border: 1px solid var(--cel-orange); color: var(--cel-orange); font-family: var(--cel-font-title); border-radius: 3px; padding: 2px 4px; font-size: 0.9em; }
} }
} }
.weapon-damage-badge { .weapon-damage-badge {
@@ -380,9 +380,9 @@
border: 1px solid var(--cel-orange); border: 1px solid var(--cel-orange);
border-radius: 6px; border-radius: 6px;
padding: 6px 12px; padding: 6px 12px;
.damage-label { font-size: 0.72em; text-transform: uppercase; color: var(--cel-orange-light); letter-spacing: 0.05em; } .damage-label { font-size: 0.7em; text-transform: uppercase; color: var(--cel-orange-light); letter-spacing: 0.05em; }
.damage-value { font-family: var(--cel-font-title); font-size: 1.6em; font-weight: bold; color: var(--cel-orange); min-width: 28px; text-align: center; } .damage-value { font-family: var(--cel-font-title); font-size: 1.8em; font-weight: bold; color: var(--cel-orange); min-width: 28px; text-align: center; }
.damage-hint { font-size: 0.78em; color: var(--cel-cream); font-style: italic; } .damage-hint { font-size: 0.8em; color: var(--cel-cream); font-style: italic; }
} }
} }
@@ -404,10 +404,10 @@
border-radius: 6px; border-radius: 6px;
padding: 8px 20px; padding: 8px 20px;
min-width: 110px; min-width: 110px;
label { font-size: 0.72em; text-transform: uppercase; color: var(--cel-orange-light); letter-spacing: 0.05em; } label { font-size: 0.7em; text-transform: uppercase; color: var(--cel-orange-light); letter-spacing: 0.05em; }
.armure-stat-value { .armure-stat-value {
input[type="number"], span { input[type="number"], span {
font-family: var(--cel-font-title); font-size: 1.8em; font-weight: bold; color: var(--cel-orange); font-family: var(--cel-font-title); font-size: 2em; font-weight: bold; color: var(--cel-orange);
text-align: center; background: transparent; border: none; width: 40px; text-align: center; background: transparent; border: none; width: 40px;
} }
} }
+1 -1
View File
@@ -2,7 +2,7 @@
.cel-section-header() { .cel-section-header() {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.78em; font-size: 0.9em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.1em; letter-spacing: 0.1em;
// Gold instead of vivid green — Art Déco elegance // Gold instead of vivid green — Art Déco elegance
+21 -21
View File
@@ -14,12 +14,12 @@
color: var(--cel-orange); color: var(--cel-orange);
border-radius: 3px; border-radius: 3px;
padding: 2px 6px; padding: 2px 6px;
font-size: 0.85em; font-size: 0.8em;
} }
.npc-type-badge { .npc-type-badge {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.8em; font-size: 0.9em;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
border-radius: 3px; border-radius: 3px;
@@ -65,14 +65,14 @@
.domain-label-primary { .domain-label-primary {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-weight: bold; font-weight: bold;
font-size: 1.1em; font-size: 1.2em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
color: var(--cel-orange); color: var(--cel-orange);
} }
.domain-label-secondary { .domain-label-secondary {
font-size: 0.75em; font-size: 0.8em;
color: rgba(220,170,80,0.7); color: rgba(220,170,80,0.7);
font-style: italic; font-style: italic;
text-transform: uppercase; text-transform: uppercase;
@@ -88,7 +88,7 @@
input.domain-value-input { input.domain-value-input {
width: 40px; width: 40px;
.cel-input-std(); .cel-input-std();
font-size: 1.2em; font-size: 1.3em;
text-align: center; text-align: center;
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
} }
@@ -116,7 +116,7 @@
.domain-value { .domain-value {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1.4em; font-size: 1.5em;
font-weight: bold; font-weight: bold;
color: var(--cel-orange); color: var(--cel-orange);
min-width: 20px; min-width: 20px;
@@ -124,7 +124,7 @@
} }
.domain-value-base { .domain-value-base {
font-size: 0.75em; font-size: 0.8em;
color: rgba(220,170,80,0.6); color: rgba(220,170,80,0.6);
font-style: italic; font-style: italic;
} }
@@ -151,7 +151,7 @@
padding: 5px 10px; padding: 5px 10px;
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-weight: bold; font-weight: bold;
font-size: 0.9em; font-size: 1em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
border-bottom: 1px solid rgba(196,154,26,0.4); border-bottom: 1px solid rgba(196,154,26,0.4);
@@ -197,7 +197,7 @@
color: var(--cel-orange); color: var(--cel-orange);
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-weight: bold; font-weight: bold;
font-size: 0.9em; font-size: 1em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
@@ -222,13 +222,13 @@
.faction-name { .faction-name {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
color: var(--cel-orange); color: var(--cel-orange);
font-size: 0.95em; font-size: 1.1em;
} }
.faction-none { .faction-none {
font-style: italic; font-style: italic;
color: rgba(122,92,32,0.5); color: rgba(122,92,32,0.5);
font-size: 0.85em; font-size: 0.8em;
} }
} }
@@ -242,7 +242,7 @@
border-top: none; border-top: none;
border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px;
label { font-size: 0.85em; color: var(--cel-brown); } label { font-size: 0.8em; color: var(--cel-brown); }
select { flex: 1; .cel-input-std(); } select { flex: 1; .cel-input-std(); }
} }
} }
@@ -269,7 +269,7 @@
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-weight: bold; font-weight: bold;
text-transform: uppercase; text-transform: uppercase;
font-size: 1.1em; font-size: 1.2em;
letter-spacing: 0.04em; letter-spacing: 0.04em;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -284,7 +284,7 @@
height: 14px; height: 14px;
border-radius: 50%; border-radius: 50%;
border: 1px solid currentColor; border: 1px solid currentColor;
font-size: 0.65em; font-size: 0.7em;
font-family: var(--cel-font-body); font-family: var(--cel-font-body);
font-weight: bold; font-weight: bold;
text-transform: none; text-transform: none;
@@ -340,7 +340,7 @@
gap: 6px; gap: 6px;
padding: 4px 8px; padding: 4px 8px;
background: rgba(139,115,85,0.1); background: rgba(139,115,85,0.1);
font-size: 0.85em; font-size: 0.8em;
label { color: var(--cel-border); } label { color: var(--cel-border); }
input[type="number"] { width: 40px; .cel-input-std(); } input[type="number"] { width: 40px; .cel-input-std(); }
} }
@@ -372,7 +372,7 @@
} }
.item-tag { .item-tag {
font-size: 0.75em; font-size: 0.8em;
padding: 1px 7px; padding: 1px 7px;
border-radius: 10px; border-radius: 10px;
background: rgba(12,76,12,0.15); background: rgba(12,76,12,0.15);
@@ -399,14 +399,14 @@
justify-content: center; justify-content: center;
min-width: 20px; min-width: 20px;
min-height: 20px; min-height: 20px;
font-size: 1.08rem; font-size: 1.1rem;
line-height: 1; line-height: 1;
} }
} }
} }
.equip-empty { .equip-empty {
font-size: 0.85em; font-size: 0.8em;
font-style: italic; font-style: italic;
color: var(--cel-border); color: var(--cel-border);
padding: 4px 8px; padding: 4px 8px;
@@ -465,7 +465,7 @@
.biography-portrait-empty { .biography-portrait-empty {
padding: 14px; padding: 14px;
color: var(--cel-border); color: var(--cel-border);
font-size: 0.82em; font-size: 0.8em;
font-style: italic; font-style: italic;
text-align: center; text-align: center;
line-height: 1.5; line-height: 1.5;
@@ -498,7 +498,7 @@
border-radius: 4px; border-radius: 4px;
background: linear-gradient(180deg, rgba(255,255,255,0.82), rgba(233,223,201,0.95)); background: linear-gradient(180deg, rgba(255,255,255,0.82), rgba(233,223,201,0.95));
color: var(--cel-green); color: var(--cel-green);
font-size: 0.82em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
@@ -519,7 +519,7 @@
.biography-portrait-hint { .biography-portrait-hint {
margin: 0; margin: 0;
font-size: 0.78em; font-size: 0.8em;
font-style: italic; font-style: italic;
color: var(--cel-border); color: var(--cel-border);
} }
+201 -116
View File
@@ -30,7 +30,7 @@
.roll-actor { .roll-actor {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange-light, #ddb84a); color: var(--cel-orange-light, #ddb84a);
font-size: 0.78em; font-size: 0.9em;
letter-spacing: 0.07em; letter-spacing: 0.07em;
text-transform: uppercase; text-transform: uppercase;
opacity: 0.9; opacity: 0.9;
@@ -38,7 +38,7 @@
.roll-skill-line { .roll-skill-line {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.25em; font-size: 1.4em;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
margin-top: 2px; margin-top: 2px;
@@ -58,24 +58,24 @@
justify-content: center; justify-content: center;
flex-wrap: wrap; flex-wrap: wrap;
gap: 4px; gap: 4px;
font-size: 0.82em; font-size: 0.9em;
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
.dval, .nb-dice { .dval, .nb-dice {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.7em; font-size: 2em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
} }
.dlabel { font-size: 0.78em; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.75; } .dlabel { font-size: 0.8em; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.75; }
.dminus { color: #f0a0a0; font-weight: bold; } .dminus { color: #f0a0a0; font-weight: bold; }
.deq { opacity: 0.55; } .deq { opacity: 0.55; }
.ddice { color: var(--cel-orange, #e07b00); } .ddice { color: var(--cel-orange, #e07b00); }
} }
.wound-info { .wound-info {
font-size: 0.73em; font-size: 0.8em;
color: #f0a0a0; color: #f0a0a0;
margin-top: 3px; margin-top: 3px;
} }
@@ -117,17 +117,17 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.65em; font-size: 0.7em;
color: white; color: white;
} }
} }
} }
.moon-icon { font-size: 1.2em; flex-shrink: 0; } .moon-icon { font-size: 1.3em; flex-shrink: 0; }
.moon-text { .moon-text {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.88em; font-size: 1em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
} }
} }
@@ -152,7 +152,7 @@
label { label {
flex: 0 0 110px; flex: 0 0 110px;
font-size: 0.78em; font-size: 0.8em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -165,8 +165,8 @@
padding: 3px 7px; padding: 3px 7px;
background: rgba(255,255,255,0.85); background: rgba(255,255,255,0.85);
font-family: inherit; font-family: inherit;
font-size: 0.85em; font-size: 0.9em;
color: #333; color: var(--cel-text, #2f2413);
&:focus { outline: 1px solid var(--cel-orange, #e07b00); } &:focus { outline: 1px solid var(--cel-orange, #e07b00); }
} }
@@ -233,7 +233,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.65em; font-size: 0.7em;
color: white; color: white;
} }
} }
@@ -242,7 +242,7 @@
} }
.destin-icon { .destin-icon {
font-size: 1.1em; font-size: 1.2em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -252,20 +252,20 @@
.destin-main { .destin-main {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.9em; font-size: 1.1em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
display: block; display: block;
} }
.destin-bonus { .destin-bonus {
font-size: 0.72em; font-size: 0.8em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
font-style: italic; font-style: italic;
} }
} }
.destin-count { .destin-count {
font-size: 0.75em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
background: rgba(196,154,26,0.2); background: rgba(196,154,26,0.2);
@@ -275,7 +275,7 @@
white-space: nowrap; white-space: nowrap;
&.no-destin { &.no-destin {
color: #888; color: rgba(0,0,0,0.45);
background: rgba(0,0,0,0.05); background: rgba(0,0,0,0.05);
border-color: rgba(0,0,0,0.1); border-color: rgba(0,0,0,0.1);
} }
@@ -283,7 +283,7 @@
} }
} }
.form-visibility label { color: #888; } .form-visibility label { color: rgba(0,0,0,0.45); }
.form-faction-aspect select { .form-faction-aspect select {
font-weight: bold; font-weight: bold;
@@ -326,7 +326,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 0.75em; font-size: 0.8em;
color: white; color: white;
} }
} }
@@ -338,13 +338,13 @@
flex: 1; flex: 1;
.puiser-main { .puiser-main {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.9em; font-size: 1.1em;
color: var(--cel-accent, #6b1e28); color: var(--cel-accent, #6b1e28);
display: block; display: block;
} }
.puiser-sub { .puiser-sub {
font-size: 0.7em; font-size: 0.7em;
color: #888; color: rgba(0,0,0,0.45);
font-style: italic; font-style: italic;
} }
} }
@@ -405,7 +405,7 @@
} }
.fortune-icon { .fortune-icon {
font-size: 1.1em; font-size: 1.2em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -414,12 +414,12 @@
flex: 1; flex: 1;
.fortune-main { .fortune-main {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.9em; font-size: 1.1em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
display: block; display: block;
} }
.fortune-bonus { .fortune-bonus {
font-size: 0.72em; font-size: 0.8em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
font-style: italic; font-style: italic;
} }
@@ -459,7 +459,7 @@
.preview-formula { .preview-formula {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.6em; font-size: 1.9em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
letter-spacing: 0.04em; letter-spacing: 0.04em;
@@ -469,6 +469,90 @@
// ─── Chat message ───────────────────────────────────────────────────────────── // ─── Chat message ─────────────────────────────────────────────────────────────
// ── Contreparties dé de lune (partagé : chat-roll + moon-standalone-card) ──
.celestopol.chat-roll,
.celestopol-roll.moon-standalone-card {
.moon-effect-actions {
padding: 6px 10px 8px;
border-top: 2px solid rgba(122,92,32,0.18);
background: rgba(12,76,12,0.04);
border-radius: 0 0 3px 3px;
.moon-effect-label {
display: block;
font-family: var(--cel-font-title);
font-size: 0.8em;
font-weight: bold;
color: var(--cel-border, #7a5c20);
text-transform: uppercase;
letter-spacing: 0.07em;
margin-bottom: 6px;
}
.moon-effect-buttons {
display: flex;
flex-wrap: wrap;
gap: 5px;
align-items: center;
}
.moon-effect-btn {
font-family: var(--cel-font-title);
font-size: 0.9em;
font-weight: bold;
padding: 4px 11px;
border-radius: 4px;
cursor: pointer;
transition: filter 0.12s, opacity 0.12s;
line-height: 1.4;
letter-spacing: 0.02em;
// Positif par défaut : vert jade / or
background: var(--cel-green, #1b3828);
color: var(--cel-orange-light, #ddb84a);
border: 1px solid rgba(196,154,26,0.35);
&:hover:not(:disabled) { filter: brightness(1.18); }
&:disabled { opacity: 0.55; cursor: not-allowed; }
&.moon-effect-negative {
background: var(--cel-accent, #6b1e28);
color: var(--cel-cream, #f0e8d4);
border-color: rgba(139,30,46,0.4);
&:hover:not(:disabled) { filter: brightness(1.12); }
}
}
.moon-effect-narrative {
font-size: 0.8em;
color: var(--cel-border, #7a5c20);
font-style: italic;
align-self: center;
padding-left: 2px;
}
.moon-effect-applied-status {
display: inline-flex;
align-items: center;
gap: 4px;
margin-top: 6px;
font-size: 0.9em;
font-family: var(--cel-font-title);
font-style: italic;
padding: 3px 9px;
border-radius: 3px;
color: var(--cel-green, #1b3828);
background: rgba(12,76,12,0.09);
border: 1px solid rgba(12,76,12,0.22);
&.is-negative {
color: var(--cel-accent, #6b1e28);
background: rgba(107,30,40,0.09);
border-color: rgba(107,30,40,0.25);
}
}
}
}
.celestopol.chat-roll { .celestopol.chat-roll {
border: 1px solid var(--cel-border, #7a5c20); border: 1px solid var(--cel-border, #7a5c20);
border-radius: 3px; border-radius: 3px;
@@ -506,11 +590,11 @@
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 0.92em; font-size: 1.1em;
} }
.skill-info { .skill-info {
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
font-size: 0.77em; font-size: 0.8em;
font-style: italic; font-style: italic;
.stat-lbl { color: var(--cel-orange-light, #ddb84a); } .stat-lbl { color: var(--cel-orange-light, #ddb84a); }
.sep { margin: 0 2px; opacity: 0.5; } .sep { margin: 0 2px; opacity: 0.5; }
@@ -540,10 +624,10 @@
border-radius: 4px; border-radius: 4px;
background: white; background: white;
font-weight: bold; font-weight: bold;
font-size: 1.05em; font-size: 1.2em;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
box-shadow: 1px 1px 2px rgba(0,0,0,0.12); box-shadow: 1px 1px 2px rgba(0,0,0,0.12);
color: #222; color: var(--cel-text, #2f2413);
&.max { &.max {
background: var(--cel-green, #0c4c0c); background: var(--cel-green, #0c4c0c);
@@ -569,15 +653,15 @@
padding: 5px 10px 4px; padding: 5px 10px 4px;
background: var(--cel-cream, #f0e8d4); background: var(--cel-cream, #f0e8d4);
border-top: 1px solid rgba(122,92,32,0.2); border-top: 1px solid rgba(122,92,32,0.2);
font-size: 0.83em; font-size: 0.9em;
color: #555; color: #555;
.fl-label { color: #999; font-size: 0.88em; text-transform: uppercase; letter-spacing: 0.04em; margin-right: 2px; } .fl-label { color: rgba(0,0,0,0.4); font-size: 0.9em; text-transform: uppercase; letter-spacing: 0.04em; margin-right: 2px; }
.fl-ndice { color: var(--cel-green, #0c4c0c); font-weight: bold; } .fl-ndice { color: var(--cel-green, #0c4c0c); font-weight: bold; }
.fl-sum { font-weight: bold; color: #333; } .fl-sum { font-weight: bold; color: var(--cel-text, #2f2413); }
.fl-total { .fl-total {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.5em; font-size: 1.7em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
@@ -588,8 +672,8 @@
.fl-asp { color: var(--cel-orange, #e07b00); font-weight: bold; } .fl-asp { color: var(--cel-orange, #e07b00); font-weight: bold; }
.fl-faction { color: var(--cel-green, #0c4c0c); font-weight: bold; } .fl-faction { color: var(--cel-green, #0c4c0c); font-weight: bold; }
.fl-sep { font-weight: bold; color: var(--cel-border, #7a5c20); margin: 0 2px; } .fl-sep { font-weight: bold; color: var(--cel-border, #7a5c20); margin: 0 2px; }
.fl-eq { color: #aaa; } .fl-eq { color: rgba(0,0,0,0.35); }
.fl-op { color: #aaa; } .fl-op { color: rgba(0,0,0,0.35); }
} }
// ── Seuil et marge ── // ── Seuil et marge ──
@@ -600,22 +684,22 @@
padding: 5px 12px 6px; padding: 5px 12px 6px;
background: var(--cel-cream, #f0e8d4); background: var(--cel-cream, #f0e8d4);
border-top: 1px solid rgba(122,92,32,0.2); border-top: 1px solid rgba(122,92,32,0.2);
font-size: 0.82em; font-size: 0.9em;
.vs-wrap { .vs-wrap {
display: flex; display: flex;
align-items: baseline; align-items: baseline;
gap: 5px; gap: 5px;
} }
.vs-label { color: #aaa; text-transform: uppercase; font-size: 0.8em; } .vs-label { color: rgba(0,0,0,0.35); text-transform: uppercase; font-size: 0.8em; }
.diff-label{ font-style: italic; color: var(--cel-green, #0c4c0c); } .diff-label{ font-style: italic; color: var(--cel-green, #0c4c0c); }
.diff-val { color: #888; } .diff-val { color: rgba(0,0,0,0.45); }
.margin-badge { .margin-badge {
padding: 2px 10px; padding: 2px 10px;
border-radius: 12px; border-radius: 12px;
font-weight: bold; font-weight: bold;
font-size: 1.05em; font-size: 1.2em;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
letter-spacing: 0.05em; letter-spacing: 0.05em;
@@ -635,7 +719,7 @@
// ── Destin utilisé ── // ── Destin utilisé ──
.used-info { .used-info {
text-align: center; text-align: center;
font-size: 0.77em; font-size: 0.8em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
padding: 3px 8px; padding: 3px 8px;
background: rgba(196,154,26,0.1); background: rgba(196,154,26,0.1);
@@ -673,7 +757,7 @@
} }
.damage-header { .damage-header {
font-size: 0.72em; font-size: 0.8em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -690,13 +774,13 @@
.damage-value { .damage-value {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.9em; font-size: 2.2em;
line-height: 1; line-height: 1;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
} }
.damage-unit { .damage-unit {
font-size: 0.82em; font-size: 0.9em;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
font-weight: bold; font-weight: bold;
} }
@@ -704,7 +788,7 @@
.damage-breakdown, .damage-breakdown,
.damage-note { .damage-note {
margin-top: 6px; margin-top: 6px;
font-size: 0.76em; font-size: 0.8em;
line-height: 1.4; line-height: 1.4;
color: #5c4630; color: #5c4630;
} }
@@ -730,7 +814,7 @@
background: var(--cel-green, #0c4c0c); background: var(--cel-green, #0c4c0c);
color: var(--cel-orange-light, #ddb84a); color: var(--cel-orange-light, #ddb84a);
padding: 4px 10px; padding: 4px 10px;
font-size: 0.78em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
@@ -745,7 +829,7 @@
margin-top: 8px; margin-top: 8px;
padding: 6px 8px; padding: 6px 8px;
border-radius: 4px; border-radius: 4px;
font-size: 0.76em; font-size: 0.8em;
line-height: 1.4; line-height: 1.4;
&.is-applied { &.is-applied {
@@ -787,7 +871,7 @@
font-family: var(--cel-font-body, serif); font-family: var(--cel-font-body, serif);
.moon-die-face { .moon-die-face {
font-size: 1.8em; font-size: 1.9em;
line-height: 1; line-height: 1;
flex-shrink: 0; flex-shrink: 0;
} }
@@ -800,7 +884,7 @@
} }
.moon-die-phase { .moon-die-phase {
font-size: 0.72em; font-size: 0.8em;
opacity: 0.75; opacity: 0.75;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
@@ -808,14 +892,14 @@
.moon-die-type { .moon-die-type {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1em; font-size: 1.1em;
font-weight: bold; font-weight: bold;
letter-spacing: 0.06em; letter-spacing: 0.06em;
text-transform: uppercase; text-transform: uppercase;
} }
.moon-die-desc { .moon-die-desc {
font-size: 0.72em; font-size: 0.8em;
font-style: italic; font-style: italic;
opacity: 0.85; opacity: 0.85;
line-height: 1.3; line-height: 1.3;
@@ -852,13 +936,13 @@
border-top: 2px solid rgba(0,0,0,0.1); border-top: 2px solid rgba(0,0,0,0.1);
.result-icon { .result-icon {
font-size: 0.85em; font-size: 0.9em;
opacity: 0.85; opacity: 0.85;
letter-spacing: 0.15em; letter-spacing: 0.15em;
} }
.result-label { font-size: 1.2em; line-height: 1.2; } .result-label { font-size: 1.3em; line-height: 1.2; }
.result-desc { .result-desc {
font-size: 0.65em; font-size: 0.7em;
letter-spacing: 0.08em; letter-spacing: 0.08em;
margin-top: 2px; margin-top: 2px;
opacity: 0.8; opacity: 0.8;
@@ -919,22 +1003,22 @@
.welcome-mark { .welcome-mark {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 1.05em; font-size: 1.1em;
line-height: 1; line-height: 1;
} }
.welcome-title { .welcome-title {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 0.98em; font-size: 1.1em;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
} }
.welcome-body { .welcome-body {
padding: 9px 11px 10px; padding: 9px 11px 10px;
color: #3f3623; color: var(--cel-text, #2f2413);
font-size: 0.84em; font-size: 0.9em;
line-height: 1.45; line-height: 1.45;
p { p {
@@ -954,7 +1038,7 @@
display: block; display: block;
margin-bottom: 2px; margin-bottom: 2px;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
font-size: 0.72em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
@@ -997,27 +1081,27 @@
.portrait-message-mark { .portrait-message-mark {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 1.05em; font-size: 1.1em;
line-height: 1; line-height: 1;
} }
.portrait-message-title { .portrait-message-title {
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 0.98em; font-size: 1.1em;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
} }
.portrait-message-body { .portrait-message-body {
padding: 9px 11px 10px; padding: 9px 11px 10px;
color: #3f3623; color: var(--cel-text, #2f2413);
} }
.portrait-message-name { .portrait-message-name {
margin-bottom: 8px; margin-bottom: 8px;
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
font-size: 0.84em; font-size: 0.9em;
font-weight: bold; font-weight: bold;
letter-spacing: 0.04em; letter-spacing: 0.04em;
text-transform: uppercase; text-transform: uppercase;
@@ -1100,7 +1184,7 @@
&:hover { &:hover {
border-color: var(--cel-orange, #e07b00); border-color: var(--cel-orange, #e07b00);
background: linear-gradient(180deg, rgba(224,123,0,0.18), rgba(224,123,0,0.06)); background: linear-gradient(180deg, rgba(224,123,0,0.18), rgba(224,123,0,0.06));
color: #7a3e00; color: var(--cel-border, #7a5c20);
} }
} }
} }
@@ -1124,7 +1208,7 @@
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 0.88em; font-size: 1em;
} }
.faction-aspect-points { .faction-aspect-points {
@@ -1146,7 +1230,7 @@
border: 1px solid rgba(122,92,32,0.18); border: 1px solid rgba(122,92,32,0.18);
strong { strong {
font-size: 0.72em; font-size: 0.8em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -1155,14 +1239,14 @@
em { em {
font-style: normal; font-style: normal;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 1.05em; font-size: 1.2em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
line-height: 1; line-height: 1;
} }
} }
.faction-aspect-source-line { .faction-aspect-source-line {
font-size: 0.78em; font-size: 0.8em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
} }
@@ -1171,7 +1255,7 @@
border-left: 3px solid #b84a2e; border-left: 3px solid #b84a2e;
border-radius: 4px; border-radius: 4px;
background: rgba(184, 74, 46, 0.08); background: rgba(184, 74, 46, 0.08);
color: #8b3e2b; color: var(--cel-accent, #6b1e28);
font-size: 0.8em; font-size: 0.8em;
} }
@@ -1190,7 +1274,7 @@
background: rgba(12, 76, 12, 0.08); background: rgba(12, 76, 12, 0.08);
border: 1px solid rgba(12, 76, 12, 0.18); border: 1px solid rgba(12, 76, 12, 0.18);
color: var(--cel-green, #0c4c0c); color: var(--cel-green, #0c4c0c);
font-size: 0.72em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
} }
@@ -1204,7 +1288,7 @@
label { label {
display: block; display: block;
margin-bottom: 2px; margin-bottom: 2px;
font-size: 0.68em; font-size: 0.7em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
color: var(--cel-border, #7a5c20); color: var(--cel-border, #7a5c20);
@@ -1219,13 +1303,13 @@
border-radius: 3px; border-radius: 3px;
padding: 2px 6px; padding: 2px 6px;
background: rgba(255,255,255,0.9); background: rgba(255,255,255,0.9);
font-size: 0.78em; font-size: 0.8em;
color: #2f2413; color: var(--cel-text, #2f2413);
box-sizing: border-box; box-sizing: border-box;
} }
select option { select option {
color: #2f2413; color: var(--cel-text, #2f2413);
background: #fffaf0; background: #fffaf0;
} }
} }
@@ -1251,7 +1335,7 @@
background: rgba(224,123,0,0.12); background: rgba(224,123,0,0.12);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.72em; font-size: 0.8em;
line-height: 1; line-height: 1;
cursor: help; cursor: help;
vertical-align: middle; vertical-align: middle;
@@ -1273,7 +1357,7 @@
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
margin-bottom: 4px; margin-bottom: 4px;
font-size: 0.82em; font-size: 0.9em;
} }
} }
@@ -1281,7 +1365,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
font-size: 0.74em; font-size: 0.8em;
} }
.faction-aspect-active-list { .faction-aspect-active-list {
@@ -1298,8 +1382,8 @@
padding: 3px 6px; padding: 3px 6px;
border-radius: 4px; border-radius: 4px;
background: rgba(255,255,255,0.7); background: rgba(255,255,255,0.7);
color: #2f2413; color: var(--cel-text, #2f2413);
font-size: 0.76em; font-size: 0.8em;
&.is-relevant { &.is-relevant {
border-left: 3px solid var(--cel-green, #0c4c0c); border-left: 3px solid var(--cel-green, #0c4c0c);
@@ -1307,20 +1391,20 @@
} }
.faction-aspect-active-name { .faction-aspect-active-name {
color: #2f2413; color: var(--cel-text, #2f2413);
font-weight: 600; font-weight: 600;
} }
.faction-aspect-active-value { .faction-aspect-active-value {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
font-size: 0.92em; font-size: 1.1em;
} }
.faction-aspect-empty { .faction-aspect-empty {
color: #666; color: rgba(0,0,0,0.5);
font-style: italic; font-style: italic;
font-size: 0.74em; font-size: 0.8em;
} }
.faction-aspect-remove-block { .faction-aspect-remove-block {
@@ -1349,7 +1433,7 @@
border-left: 3px solid #c0392b; border-left: 3px solid #c0392b;
border-radius: 4px; border-radius: 4px;
color: #f0c0c0; color: #f0c0c0;
font-size: 0.85em; font-size: 0.9em;
.wound-icon { font-size: 1em; } .wound-icon { font-size: 1em; }
} }
} }
@@ -1358,7 +1442,7 @@
.celestopol.chat-roll { .celestopol.chat-roll {
.roll-result-banner.tie { .roll-result-banner.tie {
background: #3a2e1a; background: #3a2e1a;
color: #d4b870; color: var(--cel-orange-light, #ddb84a);
border-top: 2px solid #7a6230; border-top: 2px solid #7a6230;
border-bottom: 2px solid #7a6230; border-bottom: 2px solid #7a6230;
text-shadow: 0 1px 2px rgba(0,0,0,0.6); text-shadow: 0 1px 2px rgba(0,0,0,0.6);
@@ -1369,12 +1453,12 @@
align-items: center; align-items: center;
gap: 0.3em; gap: 0.3em;
margin-bottom: 1px; margin-bottom: 1px;
font-size: 0.85em; font-size: 0.9em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
.weapon-icon-small { font-size: 0.9em; } .weapon-icon-small { font-size: 0.9em; }
.weapon-degats-small { .weapon-degats-small {
font-weight: bold; font-weight: bold;
color: #f0c060; color: var(--cel-border, #7a5c20);
} }
} }
} }
@@ -1391,15 +1475,15 @@
.weapon-icon { font-size: 1em; } .weapon-icon { font-size: 1em; }
.weapon-degats { .weapon-degats {
font-weight: bold; font-weight: bold;
color: #f0c060; color: var(--cel-border, #7a5c20);
font-size: 0.85em; font-size: 0.9em;
} }
} }
.form-corps-pnj { .form-corps-pnj {
.corps-pnj-input { .corps-pnj-input {
width: 70px; width: 70px;
font-size: 1.1em; font-size: 1.3em;
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
@@ -1420,7 +1504,7 @@
label { label {
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
font-size: 0.85em; font-size: 0.9em;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
@@ -1435,7 +1519,7 @@
border: 1px solid rgba(196, 154, 26, 0.5); border: 1px solid rgba(196, 154, 26, 0.5);
border-radius: 3px; border-radius: 3px;
padding: 2px 4px; padding: 2px 4px;
font-size: 0.85em; font-size: 0.9em;
max-width: 200px; max-width: 200px;
} }
} }
@@ -1451,7 +1535,7 @@
align-items: center; align-items: center;
gap: 6px; gap: 6px;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-size: 0.88em; font-size: 0.9em;
font-style: italic; font-style: italic;
i { opacity: 0.8; } i { opacity: 0.8; }
@@ -1465,14 +1549,14 @@
padding: 4px 8px; padding: 4px 8px;
label { label {
color: #e08060; color: var(--cel-accent, #6b1e28);
font-size: 0.85em; font-size: 0.9em;
font-weight: bold; font-weight: bold;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 5px; gap: 5px;
i { color: #e08060; } i { color: var(--cel-accent, #6b1e28); }
} }
select { select {
@@ -1482,13 +1566,13 @@
border: 1px solid rgba(200, 100, 60, 0.4); border: 1px solid rgba(200, 100, 60, 0.4);
border-radius: 3px; border-radius: 3px;
padding: 2px 4px; padding: 2px 4px;
font-size: 0.85em; font-size: 0.9em;
} }
} }
.form-threshold-fixed { .form-threshold-fixed {
.threshold-value { .threshold-value {
font-size: 1.2em; font-size: 1.4em;
font-weight: bold; font-weight: bold;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
@@ -1514,7 +1598,7 @@
input[type="checkbox"] { flex-shrink: 0; } input[type="checkbox"] { flex-shrink: 0; }
.opposition-icon { .opposition-icon {
font-size: 1.2em; font-size: 1.3em;
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
} }
@@ -1525,14 +1609,14 @@
.opposition-main { .opposition-main {
font-weight: bold; font-weight: bold;
font-size: 0.9em; font-size: 1.1em;
font-family: var(--cel-font-title, "CopaseticNF", serif); font-family: var(--cel-font-title, "CopaseticNF", serif);
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
} }
.opposition-sub { .opposition-sub {
font-size: 0.75em; font-size: 0.8em;
opacity: 0.7; color: #8a7060;
font-style: italic; font-style: italic;
} }
} }
@@ -1567,7 +1651,7 @@
.moon-standalone-title { .moon-standalone-title {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 1em; font-size: 1.1em;
font-weight: bold; font-weight: bold;
color: var(--cel-green-dark, #0c4c0c); color: var(--cel-green-dark, #0c4c0c);
text-transform: uppercase; text-transform: uppercase;
@@ -1575,7 +1659,7 @@
} }
.moon-standalone-actor { .moon-standalone-actor {
font-size: 0.85em; font-size: 0.9em;
color: var(--cel-text, #333); color: var(--cel-text, #333);
font-style: italic; font-style: italic;
} }
@@ -1604,7 +1688,7 @@
.moon-standalone-phase { .moon-standalone-phase {
font-family: var(--cel-font-title); font-family: var(--cel-font-title);
font-size: 0.95em; font-size: 1.1em;
font-weight: bold; font-weight: bold;
color: var(--cel-text, #333); color: var(--cel-text, #333);
} }
@@ -1617,8 +1701,8 @@
&.moon-triomphe { border-left-color: var(--cel-green, #0c4c0c); } &.moon-triomphe { border-left-color: var(--cel-green, #0c4c0c); }
&.moon-brio { border-left-color: var(--cel-border, #7a5c20); } &.moon-brio { border-left-color: var(--cel-border, #7a5c20); }
&.moon-contrecoup { border-left-color: #c07800; } &.moon-contrecoup { border-left-color: var(--cel-orange, #c49a1a); }
&.moon-catastrophe{ border-left-color: #8b1e2e; } &.moon-catastrophe{ border-left-color: var(--cel-accent, #6b1e28); }
} }
.moon-interpret-row { .moon-interpret-row {
@@ -1627,15 +1711,15 @@
gap: 8px; gap: 8px;
.moon-interpret-label { .moon-interpret-label {
font-size: 0.72em; font-size: 0.8em;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.07em; letter-spacing: 0.07em;
color: #888; color: rgba(0,0,0,0.45);
white-space: nowrap; white-space: nowrap;
} }
.moon-fortune { .moon-fortune {
font-size: 0.85em; font-size: 0.9em;
font-weight: bold; font-weight: bold;
border-radius: 3px; border-radius: 3px;
padding: 1px 8px; padding: 1px 8px;
@@ -1648,7 +1732,7 @@
&.mauvaise-fortune { &.mauvaise-fortune {
background: rgba(139, 30, 46, 0.1); background: rgba(139, 30, 46, 0.1);
color: #8b1e2e; color: var(--cel-accent, #6b1e28);
border: 1px solid rgba(139,30,46,0.3); border: 1px solid rgba(139,30,46,0.3);
} }
} }
@@ -1659,6 +1743,7 @@
margin-top: 2px; margin-top: 2px;
padding: 6px 8px; padding: 6px 8px;
} }
} }
// ── Message d'initiative ────────────────────────────────────────────────────── // ── Message d'initiative ──────────────────────────────────────────────────────
@@ -1698,11 +1783,11 @@
color: var(--cel-orange, #e07b00); color: var(--cel-orange, #e07b00);
font-weight: bold; font-weight: bold;
letter-spacing: 0.05em; letter-spacing: 0.05em;
font-size: 0.92em; font-size: 1.1em;
} }
.skill-info { .skill-info {
color: var(--cel-cream, #f0e8d4); color: var(--cel-cream, #f0e8d4);
font-size: 0.77em; font-size: 0.8em;
font-style: italic; font-style: italic;
} }
} }
@@ -1730,19 +1815,19 @@
} }
.initiative-icon { .initiative-icon {
font-size: 1.1em; font-size: 1.2em;
opacity: 0.9; opacity: 0.9;
font-style: normal; font-style: normal;
} }
.initiative-score { .initiative-score {
font-size: 2.4em; font-size: 2.5em;
font-weight: bold; font-weight: bold;
line-height: 1; line-height: 1;
} }
.initiative-detail { .initiative-detail {
font-size: 0.65em; font-size: 0.7em;
opacity: 0.75; opacity: 0.75;
font-style: italic; font-style: italic;
font-family: var(--cel-font-body, serif); font-family: var(--cel-font-body, serif);
+24 -24
View File
@@ -16,7 +16,7 @@
{{#each (lookup ../skills statId) as |skill skillId|}} {{#each (lookup ../skills statId) as |skill skillId|}}
{{#if @root.isEditMode}} {{#if @root.isEditMode}}
<div class="skill-row edit-mode" data-stat-id="{{statId}}" data-skill-id="{{skillId}}"> <div class="skill-row edit-mode" data-stat-id="{{statId}}" data-skill-id="{{skillId}}">
<span class="skill-name">{{localize skill.label}}</span> <span class="skill-name" data-tooltip="{{localize skill.tooltip}}">{{localize skill.label}}</span>
<div class="skill-checkboxes-container"> <div class="skill-checkboxes-container">
<div class="skill-checkboxes"> <div class="skill-checkboxes">
{{#each (range 8) as |lvl|}} {{#each (range 8) as |lvl|}}
@@ -31,7 +31,7 @@
{{else}} {{else}}
<div class="skill-row rollable" data-stat-id="{{statId}}" data-skill-id="{{skillId}}" <div class="skill-row rollable" data-stat-id="{{statId}}" data-skill-id="{{skillId}}"
title="{{localize 'CELESTOPOL.Roll.clickToRoll'}}"> title="{{localize 'CELESTOPOL.Roll.clickToRoll'}}">
<span class="skill-name">{{localize skill.label}}</span> <span class="skill-name" data-tooltip="{{localize skill.tooltip}}">{{localize skill.label}}</span>
<div class="skill-checkboxes-container"> <div class="skill-checkboxes-container">
<div class="skill-checkboxes"> <div class="skill-checkboxes">
{{#each (range 8) as |lvl|}} {{#each (range 8) as |lvl|}}
@@ -49,8 +49,29 @@
{{/each}} {{/each}}
</div> </div>
{{!-- Items : Anomalie (unique), Aspects, Attributs --}} {{!-- Items : Aspects, Anomalie --}}
<div class="items-section"> <div class="items-section">
{{!-- Aspects --}}
<div class="items-group">
<div class="items-header">
<span>{{localize "CELESTOPOL.Item.aspects"}}</span>
{{#if isEditMode}}
<a data-action="createAspect" title="{{localize 'CELESTOPOL.Item.newAspect'}}"><i class="fas fa-plus"></i></a>
{{/if}}
</div>
{{#each aspects as |item|}}
<div class="item-row" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img src="{{item.img}}" class="item-icon" alt="{{item.name}}">
<span class="item-name">{{item.name}}</span>
<span class="item-value">{{item.system.valeur}}</span>
<div class="item-controls">
<a data-action="edit" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
{{#if ../isEditMode}}<a data-action="delete" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>{{/if}}
</div>
</div>
{{/each}}
</div>
{{!-- Anomalie : bloc proéminent unique --}} {{!-- Anomalie : bloc proéminent unique --}}
<div class="anomaly-block"> <div class="anomaly-block">
<div class="anomaly-block-header"> <div class="anomaly-block-header">
@@ -124,26 +145,5 @@
{{/if}} {{/if}}
</div> </div>
{{!-- Aspects --}}
<div class="items-group">
<div class="items-header">
<span>{{localize "CELESTOPOL.Item.aspects"}}</span>
{{#if isEditMode}}
<a data-action="createAspect" title="{{localize 'CELESTOPOL.Item.newAspect'}}"><i class="fas fa-plus"></i></a>
{{/if}}
</div>
{{#each aspects as |item|}}
<div class="item-row" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img src="{{item.img}}" class="item-icon" alt="{{item.name}}">
<span class="item-name">{{item.name}}</span>
<span class="item-value">{{item.system.valeur}}</span>
<div class="item-controls">
<a data-action="edit" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
{{#if ../isEditMode}}<a data-action="delete" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>{{/if}}
</div>
</div>
{{/each}}
</div>
</div> </div>
</div> </div>
+3
View File
@@ -7,6 +7,9 @@
<a class="faction-aspect-manage" data-action="manageFactionAspects"> <a class="faction-aspect-manage" data-action="manageFactionAspects">
<i class="fa-solid fa-sliders"></i> {{localize "CELESTOPOL.FactionAspect.manage"}} <i class="fa-solid fa-sliders"></i> {{localize "CELESTOPOL.FactionAspect.manage"}}
</a> </a>
<a class="faction-aspect-reset" data-action="resetFactionAspects">
<i class="fa-solid fa-rotate-left"></i> {{localize "CELESTOPOL.FactionAspect.resetButton"}}
</a>
{{/if}} {{/if}}
</div> </div>
+22 -1
View File
@@ -122,7 +122,7 @@
</div> </div>
{{/if}} {{/if}}
{{!-- Résultat du Dé de la Lune (narratif) --}} {{!-- Résultat du Dé de la Lune (narratif + choix de contrepartie) --}}
{{#if hasMoonDie}} {{#if hasMoonDie}}
<div class="moon-die-result {{moonResultClass}}"> <div class="moon-die-result {{moonResultClass}}">
<span class="moon-die-face">{{moonFaceSymbol}}</span> <span class="moon-die-face">{{moonFaceSymbol}}</span>
@@ -132,6 +132,27 @@
<span class="moon-die-desc">{{moonResultDesc}}</span> <span class="moon-die-desc">{{moonResultDesc}}</span>
</div> </div>
</div> </div>
{{#if moonActorIsCharacter}}
<div class="moon-effect-actions" data-moon-actor-id="{{moonActorId}}" data-moon-actor-uuid="{{moonActorUuid}}">
<span class="moon-effect-label">{{localize "CELESTOPOL.Moon.applyChoose"}}</span>
<div class="moon-effect-buttons">
{{#if (eq moonResultTypeId "triomphe")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="regain-anomaly">{{localize "CELESTOPOL.Moon.effectRegainAnomaly"}}</button>
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="lose-spleen">{{localize "CELESTOPOL.Moon.effectLoseSpleen"}}</button>
{{else if (eq moonResultTypeId "brio")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="gain-destin">{{localize "CELESTOPOL.Moon.effectGainDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "contrecoup")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-destin">{{localize "CELESTOPOL.Moon.effectLoseDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "catastrophe")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-anomaly">{{localize "CELESTOPOL.Moon.effectLoseAnomaly"}}</button>
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="gain-spleen">{{localize "CELESTOPOL.Moon.effectGainSpleen"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{/if}}
</div>
</div>
{{/if}}
{{/if}} {{/if}}
{{!-- Bandeau résultat --}} {{!-- Bandeau résultat --}}
+23
View File
@@ -36,4 +36,27 @@
</div> </div>
</div> </div>
{{!-- Choix de la contrepartie --}}
{{#if moonActorIsCharacter}}
<div class="moon-effect-actions" data-moon-actor-id="{{moonActorId}}" data-moon-actor-uuid="{{moonActorUuid}}">
<span class="moon-effect-label">{{localize "CELESTOPOL.Moon.applyChoose"}}</span>
<div class="moon-effect-buttons">
{{#if (eq moonResultTypeId "triomphe")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="regain-anomaly">{{localize "CELESTOPOL.Moon.effectRegainAnomaly"}}</button>
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="lose-spleen">{{localize "CELESTOPOL.Moon.effectLoseSpleen"}}</button>
{{else if (eq moonResultTypeId "brio")}}
<button type="button" class="moon-effect-btn" data-action="apply-moon-effect" data-effect="gain-destin">{{localize "CELESTOPOL.Moon.effectGainDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "contrecoup")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-destin">{{localize "CELESTOPOL.Moon.effectLoseDestin"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{else if (eq moonResultTypeId "catastrophe")}}
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="lose-anomaly">{{localize "CELESTOPOL.Moon.effectLoseAnomaly"}}</button>
<button type="button" class="moon-effect-btn moon-effect-negative" data-action="apply-moon-effect" data-effect="gain-spleen">{{localize "CELESTOPOL.Moon.effectGainSpleen"}}</button>
<span class="moon-effect-narrative">{{localize "CELESTOPOL.Moon.effectNarrativeOnly"}}</span>
{{/if}}
</div>
</div>
{{/if}}
</div> </div>