Workable system, firt step

This commit is contained in:
2026-01-02 20:30:29 +01:00
parent 70d1720176
commit 8a27cef9a4
69 changed files with 6081 additions and 1767 deletions
+572
View File
@@ -0,0 +1,572 @@
[
{
"name": "Affabulation",
"type": "commune",
"description": "Raconter un mensonge pour semer le doute, tromper un interlocuteur et gagner du temps.",
"carteSymbole": "denier"
},
{
"name": "Charme inquisiteur",
"type": "commune",
"description": "Jouer de son charme physique ou du sentiment amoureux pour convaincre.",
"carteSymbole": "denier"
},
{
"name": "Diffamation",
"type": "commune",
"description": "Ridiculiser ou propager des rumeurs pour nuire à un adversaire sans arguments tangibles.",
"carteSymbole": "denier"
},
{
"name": "Fin négociateur",
"type": "commune",
"description": "Convaincre patiemment un interlocuteur ou négocier un prix avec des arguments convaincants.",
"carteSymbole": "denier"
},
{
"name": "Fraternité de comptoir",
"type": "commune",
"description": "S'entourer d'amis occasionnels pour obtenir des rumeurs, des informations ou des services.",
"carteSymbole": "denier"
},
{
"name": "Impassibilité / Comédie",
"type": "commune",
"description": "Dissimuler ses sentiments réels ou simuler une émotion pour tromper son entourage.",
"carteSymbole": "denier"
},
{
"name": "Intimidation / Don d'apaisement",
"type": "commune",
"description": "Jouer sur la peur des autres pour les impressionner ou, inversement, utiliser sa voix pour les calmer.",
"carteSymbole": "denier"
},
{
"name": "Menaces voilées",
"type": "commune",
"description": "Convaincre un adversaire qu'une vengeance ou une armée invisible le menace pour le faire cesser une action.",
"carteSymbole": "denier"
},
{
"name": "Mimétisme social",
"type": "commune",
"description": "Savoir se comporter et se vêtir de manière appropriée dans n'importe quel milieu social.",
"carteSymbole": "denier"
},
{
"name": "Provocation",
"type": "commune",
"description": "Pousser un interlocuteur à bout pour lui faire perdre son sang-froid ou causer un scandale.",
"carteSymbole": "denier"
},
{
"name": "Adrénaline",
"type": "commune",
"description": "Mobiliser des ressources cachées en cas de stress pour obtenir un bonus temporaire aux actions physiques.",
"carteSymbole": "epee"
},
{
"name": "Escalade et autres acrobaties",
"type": "commune",
"description": "Capacité à grimper des façades, marcher sur une corde ou effectuer des sauts périlleux.",
"carteSymbole": "epee"
},
{
"name": "Guérison rapide",
"type": "commune",
"description": "Capacité physique à récupérer plus vite de blessures ou de traumatismes physiques.",
"carteSymbole": "epee"
},
{
"name": "Passe darmes spectaculaire",
"type": "commune",
"description": "Utiliser des mouvements d'armes impressionnants pour intimider ou faire hésiter des opposants.",
"carteSymbole": "epee"
},
{
"name": "Pugilat",
"type": "commune",
"description": "Maîtrise des techniques de combat non létales à mains nues ou avec des objets hétéroclites.",
"carteSymbole": "epee"
},
{
"name": "Résistance à la fatigue",
"type": "commune",
"description": "Capacité à rester éveillé, marcher longtemps ou supporter des veilles prolongées sans craquer.",
"carteSymbole": "epee"
},
{
"name": "Résistance à la souffrance",
"type": "commune",
"description": "Supporter la douleur physique intense, comme courir avec une cheville cassée ou subir une torture.",
"carteSymbole": "epee"
},
{
"name": "Résistance aux poisons et maladies",
"type": "commune",
"description": "Capacité organique à mieux résister aux toxines et à récupérer plus vite d'une pathologie.",
"carteSymbole": "epee"
},
{
"name": "Stoïcisme",
"type": "commune",
"description": "Paraître en pleine forme et impénétrable malgré les coups, la maladie ou la fatigue.",
"carteSymbole": "epee"
},
{
"name": "Survie dans la nature",
"type": "commune",
"description": "Trouver de la nourriture, repérer des traces de prédateurs et s'abriter en milieu sauvage.",
"carteSymbole": "epee"
},
{
"name": "Artisanat (un au choix)",
"type": "commune",
"description": "Maîtrise d'un métier manuel ou artistique (forgeron, peintre, musicien, etc.).",
"carteSymbole": "baton"
},
{
"name": "Camouflage dobjet",
"type": "commune",
"description": "Dissimuler des objets sur soi ou dans une pièce, ou repérer ceux cachés par autrui.",
"carteSymbole": "baton"
},
{
"name": "Cartographie / Orientation",
"type": "commune",
"description": "Comprendre et dessiner des cartes, utiliser des instruments de navigation et s'orienter sur terre comme en mer.",
"carteSymbole": "baton"
},
{
"name": "Don des affaires",
"type": "commune",
"description": "Comptabilité, logistique de caravane et gestion des stocks liés au commerce.",
"carteSymbole": "baton"
},
{
"name": "Espionnage",
"type": "commune",
"description": "Connaissance des techniques de renseignement (boîte aux lettres morte, filature, écoute clandestine).",
"carteSymbole": "baton"
},
{
"name": "Falsification",
"type": "commune",
"description": "Imiter une écriture, fabriquer de faux sceaux et modifier des documents officiels.",
"carteSymbole": "baton"
},
{
"name": "Organisation militaire",
"type": "commune",
"description": "Gérer la cohésion d'une troupe et organiser des hommes, que ce soit une patrouille ou une armée.",
"carteSymbole": "baton"
},
{
"name": "Quidam lambda",
"type": "commune",
"description": "Se fondre dans la foule urbaine pour passer inaperçu ou prendre quelqu'un en filature.",
"carteSymbole": "baton"
},
{
"name": "Stratégie",
"type": "commune",
"description": "Établir des plans de bataille, estimer les forces ennemies et mener des campagnes militaires.",
"carteSymbole": "baton"
},
{
"name": "Symbiose animale",
"type": "commune",
"description": "Créer un rapport de confiance avec les bêtes pour éviter les attaques ou les apprivoiser.",
"carteSymbole": "baton"
},
{
"name": "Connaissance de lInframonde",
"type": "commune",
"description": "Savoir théorique sur la dimension de l'Inframonde, ses portails et ses créatures malveillantes.",
"carteSymbole": "coupe"
},
{
"name": "Connaissance des Arcanes",
"type": "commune",
"description": "Comprendre le fonctionnement et les limites de la magie, ainsi que l'histoire de la thaumaturgie.",
"carteSymbole": "coupe"
},
{
"name": "Corruption de bureaucrate",
"type": "commune",
"description": "Identifier les faiblesses des employés de l'administration pour obtenir des faveurs ou des informations.",
"carteSymbole": "coupe"
},
{
"name": "Enquête / Investigation",
"type": "commune",
"description": "Repérer des détails inhabituels, résoudre des énigmes et comprendre les motivations cachées.",
"carteSymbole": "coupe"
},
{
"name": "Herboristerie",
"type": "commune",
"description": "Trouver des plantes et confectionner des remèdes de base, des poisons simples ou des hallucinogènes.",
"carteSymbole": "coupe"
},
{
"name": "Langage des runes",
"type": "commune",
"description": "Lire et déchiffrer les runes chargées de magie sur des parchemins ou des gravures.",
"carteSymbole": "coupe"
},
{
"name": "Langue (parler, lire et écrire)",
"type": "commune",
"description": "Maîtrise orale et/ou écrite de langues étrangères ou anciennes.",
"carteSymbole": "coupe"
},
{
"name": "Recherche en bibliothèque",
"type": "commune",
"description": "Méthodologie pour trouver des informations dans les archives et déchiffrer des textes anciens.",
"carteSymbole": "coupe"
},
{
"name": "Savoir encyclopédique",
"type": "commune",
"description": "Posséder une grande culture générale sur de multiples sujets théoriques et historiques.",
"carteSymbole": "coupe"
},
{
"name": "Soins basiques",
"type": "commune",
"description": "Donner les premiers secours (lavage, suture, bandages) pour stabiliser un blessé.",
"carteSymbole": "coupe"
},
{
"name": "Excellent joueur",
"type": "peuple",
"peuple": "Centuplide",
"description": "Instinct du jeu, des paris et du bluff permettant de gagner même quand le hasard est seul facteur.",
"carteSymbole": "denier"
},
{
"name": "Violence caniculaire",
"type": "peuple",
"peuple": "Centuplide",
"description": "Utiliser sa force et son agilité reptilienne pour porter des coups d'une violence extrême.",
"carteSymbole": "epee"
},
{
"name": "Itinéraire",
"type": "peuple",
"peuple": "Centuplide",
"description": "Mémoire infaillible des routes et chemins parcourus, empêchant de se perdre en extérieur.",
"carteSymbole": "baton"
},
{
"name": "Conscience collective",
"type": "peuple",
"peuple": "Centuplide",
"description": "Percevoir l'état de santé, le moral et la position approximative des centuplides à proximité.",
"carteSymbole": "coupe"
},
{
"name": "Diplomatie éowin",
"type": "peuple",
"peuple": "Éowin",
"description": "Talent naturel pour servir de médiateur et d'intermédiaire dans les accords ou traités de paix.",
"carteSymbole": "denier"
},
{
"name": "Esquive éowin",
"type": "peuple",
"peuple": "Éowin",
"description": "Agilité exceptionnelle permettant d'éviter les coups plutôt que de les bloquer.",
"carteSymbole": "epee"
},
{
"name": "Compréhension des mécanismes complexes",
"type": "peuple",
"peuple": "Éowin",
"description": "Don instinctif pour comprendre et réparer des mécanismes d'horlogerie, serrures ou moulins.",
"carteSymbole": "baton"
},
{
"name": "Perception empathique",
"type": "peuple",
"peuple": "Éowin",
"description": "Ressentir l'atmosphère générale et les sentiments qui animent une foule ou un groupe.",
"carteSymbole": "coupe"
},
{
"name": "Langage des captifs",
"type": "peuple",
"peuple": "Cendrove",
"description": "Langage corporel sommaire permettant de communiquer des sentiments ou intentions sans parler.",
"carteSymbole": "denier"
},
{
"name": "Symbiose avec l'Entremonde",
"type": "peuple",
"peuple": "Cendrove",
"description": "Capacité spirituelle à entrer dans un état de fureur apportant des bonus aux actions d'Épée.",
"carteSymbole": "epee"
},
{
"name": "Cachette de fortune",
"type": "peuple",
"peuple": "Cendrove",
"description": "Savoir utiliser le terrain pour se cacher soi-même ou des objets de manière quasi indétectable.",
"carteSymbole": "baton"
},
{
"name": "Lecture des astres",
"type": "peuple",
"peuple": "Cendrove",
"description": "Interpréter le mouvement des étoiles pour obtenir des indices sur le futur ou une direction.",
"carteSymbole": "coupe"
},
{
"name": "Expertise politique",
"type": "faction",
"faction": "Administrum",
"description": "Anticiper les bénéficiaires d'une action politique et déceler les ruses lors de signatures d'accords.",
"carteSymbole": "denier"
},
{
"name": "Profil bas",
"type": "faction",
"faction": "Administrum",
"description": "Paraître insignifiant ou laisser entendre que sa fonction garantit une rançon pour éviter les coups.",
"carteSymbole": "epee"
},
{
"name": "Application de la loi impériale",
"type": "faction",
"faction": "Administrum",
"description": "Connaître les lois pour les exécuter ou les contourner légalement avec un argumentaire solide.",
"carteSymbole": "baton"
},
{
"name": "Connaissance de la technologie hamalronienne",
"type": "faction",
"faction": "Administrum",
"description": "Savoir utiliser ou fabriquer des installations technologiques de l'âge d'or (vapeur, hydraulique).",
"carteSymbole": "coupe"
},
{
"name": "Vieilles amitiés",
"type": "faction",
"faction": "Bastion",
"description": "Activer des liens familiaux ou nobiliaires transmis sur plusieurs générations pour obtenir de l'aide.",
"carteSymbole": "denier"
},
{
"name": "Botte secrète",
"type": "faction",
"faction": "Bastion",
"description": "Utiliser une ruse d'escrime spécifique pour surprendre un adversaire et obtenir un bonus.",
"carteSymbole": "epee"
},
{
"name": "Mobilisation",
"type": "faction",
"faction": "Bastion",
"description": "Capacité à lever une troupe de fidèles dans une région donnée grâce à son influence nobiliaire.",
"carteSymbole": "baton"
},
{
"name": "Histoire de la noblesse",
"type": "faction",
"faction": "Bastion",
"description": "Connaissance approfondie de l'héraldique, des lignées, des exploits et des secrets des grandes familles.",
"carteSymbole": "coupe"
},
{
"name": "Serment dhonneur",
"type": "faction", "faction": "Chevaliers de la Rose grise", "description": "Donner sa parole pour gagner en crédibilité, amadouer ou effrayer, au prix de l'obligation de la tenir.",
"carteSymbole": "denier"
},
{
"name": "Duel",
"type": "faction",
"faction": "Chevaliers de la Rose grise",
"description": "Expertise du combat à la loyale, en un contre un au corps à corps.",
"carteSymbole": "epee"
},
{
"name": "Entretien de larmement",
"type": "faction", "faction": "Chevaliers de la Rose grise", "description": "Prendre soin de son matériel de guerre pour bénéficier de bonus lors des futurs combats.",
"carteSymbole": "baton"
},
{
"name": "Allié potentiel",
"type": "faction",
"faction": "Chevaliers de la Rose grise",
"description": "Instinct permettant de sentir si une personne rencontrée peut devenir un allié fiable.",
"carteSymbole": "coupe"
},
{
"name": "Toujours à sa place",
"type": "faction",
"faction": "Confrérie des Servants",
"description": "Capacité à se fondre dans le décor et passer inaperçu quel que soit le milieu.",
"carteSymbole": "denier"
},
{
"name": "Attaque-surprise",
"type": "faction",
"faction": "Confrérie des Servants",
"description": "Usage d'armes cachées, dégainés rapides ou fauchages pour surprendre l'adversaire en combat.",
"carteSymbole": "epee"
},
{
"name": "Doigts agiles",
"type": "faction",
"faction": "Confrérie des Servants",
"description": "Techniques de crochetage, vol de clés ou de documents en toute discrétion.",
"carteSymbole": "baton"
},
{
"name": "Conseil politique",
"type": "faction",
"faction": "Confrérie des Servants",
"description": "Connaissance approfondie des forces en présence et du pouvoir des dignitaires pour conseiller les puissants.",
"carteSymbole": "coupe"
},
{
"name": "Sermon",
"type": "faction",
"faction": "Ecclésiarchie",
"description": "Embraser les foules ou réconforter les âmes par la parole et les gestes religieux.",
"carteSymbole": "denier"
},
{
"name": "Foi inébranlable",
"type": "faction",
"faction": "Ecclésiarchie",
"description": "Utiliser sa conviction religieuse pour lutter ou résister à la peur dans des situations liées à la foi.",
"carteSymbole": "epee"
},
{
"name": "Simonie",
"type": "faction",
"faction": "Ecclésiarchie",
"description": "Maîtriser le commerce légal des biens religieux, reliques ou absolutions.",
"carteSymbole": "baton"
},
{
"name": "Théologie",
"type": "faction",
"faction": "Ecclésiarchie",
"description": "Connaissance des secrets, dogmes et débats religieux pour l'étude ou les procès ecclésiastiques.",
"carteSymbole": "coupe"
},
{
"name": "Extorsion / Racket",
"type": "faction",
"faction": "Fraternité du Poing de fer",
"description": "Obtenir de l'argent ou des privilèges par l'usage de menaces typiques de la pègre.",
"carteSymbole": "denier"
},
{
"name": "Assassinat",
"type": "faction",
"faction": "Fraternité du Poing de fer",
"description": "Éliminer furtivement une cible humanoïde surprise avec des armes discrètes.",
"carteSymbole": "epee"
},
{
"name": "Arnaque",
"type": "faction",
"faction": "Fraternité du Poing de fer",
"description": "Maîtrise de la roublardise, des détournements et des stratagèmes complexes (comme les ruses de siège).",
"carteSymbole": "baton"
},
{
"name": "Langage des signes",
"type": "faction",
"faction": "Fraternité du Poing de fer",
"description": "Système gestuel et écrit secret permettant aux membres de la pègre de communiquer discrètement.",
"carteSymbole": "coupe"
},
{
"name": "Fibre commerçante",
"type": "faction",
"faction": "Guildes marchandes",
"description": "Art de susciter la compassion pour conclure un marché avantageux ou vendre des produits inutiles.",
"carteSymbole": "denier"
},
{
"name": "Instinct de survie",
"type": "faction",
"faction": "Guildes marchandes",
"description": "Utiliser l'environnement (objets, obstacles) pour se protéger d'une attaque au détriment de l'offensive.",
"carteSymbole": "epee"
},
{
"name": "Réseau marchand",
"type": "faction",
"faction": "Guildes marchandes",
"description": "Savoir mobiliser ses filières pour dénicher des objets rares ou organiser des échanges commerciaux.",
"carteSymbole": "baton"
},
{
"name": "Évaluation dun produit",
"type": "faction", "faction": "Guildes marchandes", "description": "Déterminer le prix juste, la rareté et la fonction d'une marchandise.",
"carteSymbole": "coupe"
},
{
"name": "Menace de sorcier",
"type": "faction",
"faction": "Sororité de la Sinistrose",
"description": "Laisser entendre que l'on dispose de pouvoirs pour effrayer un adversaire et le faire céder.",
"carteSymbole": "denier"
},
{
"name": "Magie de combat",
"type": "faction",
"faction": "Sororité de la Sinistrose",
"description": "Canaliser l'adrénaline du danger pour amplifier la puissance des arts magiques lors du lancement d'un sort.",
"carteSymbole": "epee"
},
{
"name": "Alchimie",
"type": "faction",
"faction": "Sororité de la Sinistrose",
"description": "Art de concevoir des potions, onguents et objets magiques à partir de composants naturels.",
"carteSymbole": "baton"
},
{
"name": "Manipulation des Arcanes",
"type": "faction",
"faction": "Sororité de la Sinistrose",
"description": "Détecter les émanations magiques et identifier le type ou la puissance d'un sortilège environnant.",
"carteSymbole": "coupe"
},
{
"name": "Fraternité des trois",
"type": "faction",
"faction": "Triumvirat",
"description": "User de son charisme pour convaincre un autre non-humain de changer de camp ou de s'entraider.",
"carteSymbole": "denier"
},
{
"name": "Art de combat racial",
"type": "faction",
"faction": "Triumvirat",
"description": "Maîtrise d'une technique d'attaque spécifique à sa race (Cendrove, Centuplide ou Éowin).",
"carteSymbole": "epee"
},
{
"name": "Commerce réservé",
"type": "faction",
"faction": "Triumvirat",
"description": "Accéder à des produits rares ou inaccessibles par les réseaux de solidarité primogènes.",
"carteSymbole": "baton"
},
{
"name": "Savoir des races anciennes",
"type": "faction",
"faction": "Triumvirat",
"description": "Connaissance de l'histoire et des secrets des peuples primogènes avant l'arrivée des humains.",
"carteSymbole": "coupe"
}
]
+38
View File
@@ -0,0 +1,38 @@
[
{
"nom": "Administrum",
"description": "Faction composée de sages, d'érudits et de magisters au service de l'impératrice Minarquas. Prônant l'épistémocratie, ils gèrent l'administration, les impôts et les grands travaux pour assurer la stabilité et le progrès éclairé de l'Empire."
},
{
"nom": "Le Bastion",
"description": "Organisation clandestine regroupant les familles nobles les plus conservatrices, principalement en Malantise. Ils défendent farouchement leurs privilèges féodaux, s'opposent au Triumvirat et rêvent de restaurer un ordre social ancien basé sur la hiérarchie des races."
},
{
"nom": "Les Chevaliers de la Rose grise",
"description": "Ordre de guerriers impulsifs et honorables servant le roi du Chenara et l'impératrice. Bien que non exclusivement nobles, ils constituent une troupe d'élite dévouée aux valeurs chevaleresques et au passé glorieux, tout en méprisant les activités marchandes."
},
{
"nom": "La Confrérie des Servants",
"description": "Guilde secrète et neutre qui forme des espions, des assassins et des conseillers politiques de haut niveau. Infiltrés dans toutes les strates du pouvoir sous couvert de domesticité, ses membres sont liés par une loi du silence absolue sous peine de mort."
},
{
"nom": "L'Ecclésiarchie",
"description": "Institution religieuse officielle dédiée au culte d'Hamalron le Bâtisseur. Exclusivement masculine, elle exerce une influence morale et politique immense sur toutes les classes sociales, tout en luttant pour sa suprématie spirituelle et contre l'usage des arcanes."
},
{
"nom": "La Fraternité du Poing de fer",
"description": "Organisation criminelle clandestine contrôlant la pègre des grandes cités. Fondée à l'origine comme une force de résistance contre l'arbitraire des puissants, elle mêle idéalisme et banditisme, regroupant humains et non-humains dans un climat de paranoïa constante."
},
{
"nom": "Les Guildes marchandes",
"description": "Alliance puissante des corporations commerçantes de l'Empire. Motivées par le seul profit et dépourvues d'idéologie fixe, elles utilisent leur immense richesse pour influencer la politique et s'allient opportunistement avec n'importe quel camp selon leurs intérêts financiers."
},
{
"nom": "La Sororité de Sinistrose",
"description": "Culte féminin de magiciennes (Sœurs-Zélotes) dévouées à la matriarche Astasia. Détentrices du monopole de la magie, elles utilisent la séduction et le magnétisme pour influencer les puissants dans le but secret de restaurer la Gynarchie oubliée."
},
{
"nom": "Le Triumvirat",
"description": "Corps politique et armé défendant les intérêts des peuples primogènes (cendroves, centuplides et éowins). Ils luttent pour la justice, l'égalité des droits au sein de l'Empire et s'opposent radicalement à l'esclavage dont leurs races ont longtemps souffert."
}
]
+34
View File
@@ -0,0 +1,34 @@
[
{
"nom": "Hamalroniens",
"description": "Ensemble des peuples humains disséminés partout dans les Cinq Contrées et au-delà [1]. Bien qu'ils possèdent des traits physiques et des coutumes variant selon leur habitat (teint, taille), ils sont reliés par la religion et un système politique basé sur la féodalité [1, 2]."
},
{
"nom": "Centuplides",
"description": "Sous-race majoritaire des draconides, ce sont des hommes-lézards puissants et massifs (1m90 à 2m30) dotés d'une queue musclée [3, 4]. Ils sont célèbres pour leur extraordinaire pouvoir de régénération et leur capacité à s'acclimater physiquement à de nouveaux environnements en quelques années [5]."
},
{
"nom": "Éowins",
"description": "Surnommés le « peuple pacificateur », ce sont de petits êtres asexués (1m à 1m30) créés originellement par les Tharnes [6, 7]. Joyeux et hédonistes, ils sont des médiateurs nés et possèdent un don instinctif pour comprendre et réparer les mécanismes complexes [6, 8]."
},
{
"nom": "Cendroves",
"description": "Humanoïdes élancés aux longues oreilles pointues, ils sont les plus proches des humains par leur structure sociale [9, 10]. Ils se distinguent par une perception du temps fluctuante et la capacité d'entrer en « symbiose avec lEntremonde », un état d'hyperactivité coordonnée déclenché par la colère ou le danger [9, 11]."
},
{
"nom": "Krinals",
"description": "Géants (2m à 2m30) à la peau pâle et au sang bleu vivant dans les steppes glacées du Svenhaagen [12]. Chasseurs et guerriers redoutables, ils méprisent les sciences théoriques, valorisent la puissance personnelle et excellent dans le dressage de créatures massives [13-15]."
},
{
"nom": "Dvärgs",
"description": "Petits humanoïdes difformes et solitaires vivant dans les montagnes [16, 17]. Ils possèdent des pouvoirs magiques liés à la terre, peuvent se fondre dans la roche et consacrent leur existence à sculpter les montagnes qu'ils perçoivent comme une œuvre d'art [17, 18]."
},
{
"nom": "Gnomes nomades",
"description": "Petits êtres souterrains (50 à 60 cm) fuyant le contact avec les autres peuples par peur maladive [19]. Ils ne mangent pas mais absorbent les effluves magiques, sont d'habiles terrassiers et possèdent le pouvoir de fusionner avec la pierre [19]."
},
{
"nom": "Tharnes (Drezaxilons)",
"description": "Ancien peuple d'humanoïdes ailés à la beauté divine et aux connaissances magiques immenses [20]. Autrefois maîtres du monde avant l'arrivée des hommes, ils ont disparu suite à une malédiction de stérilité et une guerre contre les centuplides [6, 21, 22]."
}
]
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

+1488 -476
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -87,6 +87,15 @@ Hooks.once("init", function () {
default: "",
})
game.settings.register("fvtt-hamalron", "tarotDeckState", {
name: "Tarot Deck State",
hint: "Stores the current state of the tarot deck and discard pile",
scope: "world",
config: false,
type: Object,
default: { deck: [], discard: [] },
})
// Activate socket handler
game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent)
+94 -62
View File
@@ -1,4 +1,22 @@
{
"TYPES": {
"Actor": {
"personnage": "Personnage",
"PNJ": "PNJ"
},
"Item": {
"arme": "Arme",
"armure": "Armure",
"competence": "Compétence",
"equipement": "Équipement",
"faction": "Faction",
"langue": "Langue",
"peuple": "Peuple",
"region": "Région",
"sortilege": "Sortilège",
"tarot": "Tarot"
}
},
"HAMALRON": {
"Arme": {
"FIELDS": {
@@ -197,6 +215,12 @@
},
"type": {
"label": "Type"
},
"faction": {
"label": "Faction"
},
"peuple": {
"label": "Peuple"
}
}
},
@@ -337,7 +361,10 @@
}
},
"Delete": "Supprimer",
"Dialog": {},
"Dialog": {
"discardCardTitle": "Défausser la carte",
"discardCardContent": "Voulez-vous vraiment défausser <strong>{cardName}</strong> et tirer une nouvelle carte ?"
},
"Edit": "Éditer",
"Enemy": {
"FIELDS": {
@@ -396,18 +423,23 @@
"appearance": "Apparence",
"armor": "Armure",
"armors": "Armures",
"automaticSuccess": "Réussite Automatique",
"backstory": "Histoire",
"biodata": "Données biologiques",
"biography": "Biographie",
"bonds": "Liens",
"bonus": "Déclencheur XP droit",
"capacity": "Capacité",
"cardBonus": "Bonus de carte",
"cardUsed": "Carte utilisée",
"cards": "Cartes",
"cargo": "Cargaison",
"cartesSucces": "Cartes Succès",
"character": "Personnage",
"characteristics": "Caractéristiques",
"combat": "Combat",
"competence": "Compétence",
"competenceModifier": "Modificateur de compétence",
"competences": "Compétences",
"creature": "Créature",
"current": "Act.",
@@ -416,12 +448,14 @@
"damages": "Dégâts",
"deals": "Accords",
"description": "Description",
"differentSymbol": "Symbole différent",
"difficulty": "Difficulté",
"dislikes": "N'aime pas",
"dragTarotHere": "Glissez-déposez des cartes de tarot ici depuis le répertoire des objets",
"equipment": "Équipement",
"equipments": "Équipements",
"experience": "Expérience",
"faction": "Faction",
"failure": "Échec",
"fears": "Peurs",
"fiendishFailure": "Échec diabolique",
@@ -436,8 +470,9 @@
"knowledge": "Connaissance",
"languages": "Langues",
"likes": "Aime",
"maleficas": "Maléfices",
"sortileges": "Sortilèges",
"malus": "Malus",
"matchingSymbol": "Symbole correspondant",
"max": "Max",
"maximum": "Maximum",
"mind": "Esprit",
@@ -462,10 +497,17 @@
"newTarot": "Nouveau tarot",
"newTrait": "Nouveau trait",
"newWeapon": "Nouvelle arme",
"niveau": "Niveau",
"noTarotCards": "Aucune carte de tarot",
"mustDiscardCard": "Vous devez éliminer une carte",
"discard": "Défausser",
"discardCard": "Défausser cette carte",
"discardAndDraw": "Défausser et tirer",
"drawCard": "Tirer une carte",
"notes": "Notes",
"penalty": "Déclencheur XP inversé",
"perks": "Avantages",
"peuple": "Peuple",
"physical": "Physique",
"positiveEffect": "Effet positif",
"progression": "Progression",
@@ -476,6 +518,7 @@
"rollView": "Vue de jet",
"satanicSuccess": "Succès satanique",
"scars": "Cicatrices",
"selectTarotCard": "Sélectionnez une carte de tarot",
"skill": "Compétence",
"skillRoll": "Jet de compétence",
"skills": "Compétences",
@@ -490,17 +533,24 @@
"stats": "Stats",
"status": "Statut",
"stealth": "Furtivité",
"sousTension": "Sous tension",
"oppose": "Opposé",
"success": "Succès",
"symbole": "Symbole",
"talents": "Talents",
"targetScore": "Score cible",
"tarot": "Tarot",
"tarotHand": "Main de tarot",
"technology": "Technologie",
"tensionModifier": "Modificateur sous tension",
"titleCompetence": "Jet de compétence",
"titleSkill": "Jet de compétence",
"titleStat": "Boîte de dialogue de jet de caractéristique",
"titleWeapon": "Jet d'arme",
"total": "Total",
"totalScore": "Score total",
"totalValue": "Valeur totale",
"cardValue": "Valeur de la carte",
"traits": "Traits",
"trauma": "Traumatisme",
"unknown": "Inconnu",
@@ -510,49 +560,19 @@
"vices": "Vices",
"weapons": "Armes"
},
"Malefica": {
"FIELDS": {
"choiceMaintainDuration": {
"label": "Passif/Durée"
},
"damage": {
"label": "Dégâts"
},
"damageType": {
"label": "Type de dégâts"
},
"description": {
"label": "Description"
},
"domain": {
"label": "Domaine"
},
"duration": {
"label": "Durée"
},
"hasDamage": {
"label": "A des dégâts"
},
"level": {
"label": "Niveau"
},
"maintain": {
"label": "Passif"
},
"range": {
"label": "Portée"
},
"target": {
"label": "Cible"
},
"time": {
"label": "Temps"
}
}
},
"Notifications": {
"speciesTraitDeleted": "Trait d'espèce précédent supprimé : ",
"tarotDeleted": "Carte de Tarot précédente supprimée : "
"tarotDeleted": "Carte de Tarot précédente supprimée : ",
"tarotHandFull": "Vous avez déjà 8 cartes dans votre main. Vous devez en éliminer une avant d'en ajouter une autre.",
"cardDiscarded": "Carte défaussée : ",
"cardUsed": "Carte utilisée : ",
"newCardDrawn": "Nouvelle carte tirée : ",
"tarotCardAlreadyExists": "Cette carte existe déjà dans votre main : ",
"cannotDrawCard": "Vous avez déjà 7 cartes ou plus dans votre main.",
"deckManagerNotAvailable": "Le gestionnaire de deck n'est pas disponible.",
"deckEmpty": "Le deck est vide. Impossible de tirer une carte.",
"cardDiscardedAndDrawn": "Carte défaussée et nouvelle carte tirée : ",
"cardDiscardedNoNew": "Carte défaussée. Le deck est vide, aucune nouvelle carte n'a pu être tirée."
},
"Sortilege": {
"FIELDS": {
@@ -585,26 +605,9 @@
"Roll": {
"cancel": "Annuler",
"roll": "Lancer",
"rollCompetence": "Jet de compétence",
"skill": "Compétence"
},
"TYPES": {
"Actor": {
"personnage": "Personnage",
"PNJ": "PNJ"
},
"Item": {
"arme": "Arme",
"armure": "Armure",
"competence": "Compétence",
"equipement": "Équipement",
"faction": "Faction",
"langue": "Langue",
"peuple": "Peuple",
"region": "Région",
"sortilege": "Sortilège",
"tarot": "Tarot"
}
},
"Tarot": {
"FIELDS": {
"bonus": {
@@ -650,26 +653,55 @@
"valet": "Valet",
"cavalier": "Cavalier",
"reine": "Reine",
"roi": "Roi"
"roi": "Roi",
"lemat": "Le Mat",
"11": "Le Bateleur",
"12": "La Papesse",
"13": "L'Impératrice",
"14": "L'Empereur",
"15": "Le Pape",
"16": "L'Amoureux",
"17": "Le Chariot",
"18": "La Justice",
"19": "L'Ermite",
"20": "La Roue de Fortune",
"21": "La Force",
"22": "Le Pendu"
}
}
},
"TarotDeck": {
"CardsDrawn": "Cartes tirées",
"CardsInDeck": "Cartes dans le jeu",
"CardsInDiscard": "Cartes dans la défausse",
"CollectHands": "Récupérer les mains",
"CollectHandsConfirm": "Récupérer toutes les mains ?",
"CollectHandsWarning": "Cela récupérera toutes les cartes de tarot de tous les personnages joueurs et les réintégrera dans le deck. Les doublons seront supprimés pour garantir un deck de 78 cartes.",
"HandsCollected": "{collected} cartes récupérées. Deck réinitialisé avec {deckSize} cartes uniques.",
"DistributeCards": "Distribuer 8 cartes",
"DistributeConfirm": "Distribuer les cartes ?",
"DistributeWarning": "Cela distribuera 8 cartes du deck à chaque joueur connecté.",
"CardsDistributed": "{cards} cartes distribuées à {players} joueur(s).",
"NotEnoughCards": "Pas assez de cartes dans le deck (minimum 8 requises).",
"DeckEmpty": "Le jeu est vide",
"DeckEmptyWarning": "Le jeu est vide. Veuillez réinitialiser le jeu pour continuer.",
"DeckReset": "Le jeu a été réinitialisé et mélangé",
"DiscardShuffled": "La défausse a été mélangée dans le jeu",
"DrawCard": "Tirer une carte",
"DrawFive": "Tirer 5 cartes",
"DrawOne": "Tirer 1 carte",
"DrawTension": "Tirage sous tension",
"DrawThree": "Tirer 3 cartes",
"GMOnly": "Seul le MJ peut accéder au gestionnaire de jeu de tarot",
"NoCardsFound": "Aucune carte de tarot trouvée dans le monde. Veuillez d'abord créer des objets tarot.",
"NoDiscard": "La défausse est vide",
"NoDrawsYet": "Aucune carte tirée pour l'instant",
"RecentDraws": "Cartes tirées récemment",
"ResetConfirm": "Réinitialiser le jeu ?",
"ResetDeck": "Réinitialiser le jeu",
"ResetWarning": "Cela réinitialisera le jeu et mélangera toutes les cartes. L'historique des cartes tirées sera effacé.",
"SelectDifficulty": "Sélectionner la difficulté",
"ShuffleDiscard": "Mélanger la défausse",
"Title": "Gestionnaire de jeu de tarot",
"TotalCards": "Total des cartes"
},
+105
View File
@@ -0,0 +1,105 @@
/**
* Macro d'import des compétences depuis competences.json
* Crée un dossier "Compétences" et y importe toutes les compétences
*/
async function importCompetences() {
// Charger le fichier JSON
const response = await fetch('systems/fvtt-hamalron/assets/data/competences.json');
const competencesData = await response.json();
ui.notifications.info("Début de l'import des compétences...");
// Créer ou récupérer le dossier pour les compétences
let competencesFolder = game.folders.find(f => f.name === "Compétences" && f.type === "Item");
if (!competencesFolder) {
competencesFolder = await Folder.create({
name: "Compétences",
type: "Item",
color: "#4169e1",
sorting: "a"
});
console.log("Dossier 'Compétences' créé");
} else {
console.log("Dossier 'Compétences' existant trouvé");
}
// Compteurs pour le résumé
let importCount = 0;
let updateCount = 0;
let errorCount = 0;
ui.notifications.info(`Début de l'import de ${competencesData.length} compétences...`);
// Parcourir toutes les compétences
for (const competenceJson of competencesData) {
try {
// Préparer les données de la compétence selon le modèle
const itemData = {
name: competenceJson.name,
type: 'competence',
system: {
description: competenceJson.description,
type: competenceJson.type,
carteSymbole: competenceJson.carteSymbole,
niveau: 'inexperimente', // Valeur par défaut
}
};
// Ajouter les champs optionnels s'ils existent
if (competenceJson.faction) {
itemData.system.faction = competenceJson.faction;
}
if (competenceJson.peuple) {
itemData.system.peuple = competenceJson.peuple;
}
// Vérifier si la compétence existe déjà
const existing = game.items.find(i => i.name === competenceJson.name && i.type === 'competence');
if (existing) {
// Mettre à jour la compétence existante
await existing.update(itemData);
updateCount++;
console.log(`Compétence mise à jour: ${competenceJson.name}`);
} else {
// Créer une nouvelle compétence dans le dossier
await Item.create({
...itemData,
folder: competencesFolder.id
});
importCount++;
console.log(`✓ Créé: ${competenceJson.name}`);
}
} catch (error) {
errorCount++;
console.error(`Erreur lors de l'import de ${competenceJson.name}:`, error);
}
}
// Afficher le résumé
const message = `
<h3>Import des compétences terminé</h3>
<p><strong>Compétences créées:</strong> ${importCount}</p>
<p><strong>Compétences mises à jour:</strong> ${updateCount}</p>
<p><strong>Erreurs:</strong> ${errorCount}</p>
`;
ChatMessage.create({
user: game.user.id,
content: message
});
ui.notifications.info(`Import terminé: ${importCount} créées, ${updateCount} mises à jour, ${errorCount} erreurs.`);
console.log('=== Résumé de l\'import ===');
console.log(`Compétences créées: ${importCount}`);
console.log(`Compétences mises à jour: ${updateCount}`);
console.log(`Erreurs: ${errorCount}`);
}
// Exécuter l'import
importCompetences();
+93
View File
@@ -0,0 +1,93 @@
/**
* Macro d'import des factions depuis factions.json
* Crée un dossier "Factions" et y importe toutes les factions
*/
async function importFactions() {
// Charger le fichier JSON
const response = await fetch('systems/fvtt-hamalron/assets/data/factions.json');
const factionsData = await response.json();
ui.notifications.info("Début de l'import des factions...");
// Créer ou récupérer le dossier pour les factions
let factionsFolder = game.folders.find(f => f.name === "Factions" && f.type === "Item");
if (!factionsFolder) {
factionsFolder = await Folder.create({
name: "Factions",
type: "Item",
color: "#8b0000",
sorting: "a"
});
console.log("Dossier 'Factions' créé");
} else {
console.log("Dossier 'Factions' existant trouvé");
}
// Compteurs pour le résumé
let importCount = 0;
let updateCount = 0;
let errorCount = 0;
ui.notifications.info(`Début de l'import de ${factionsData.length} factions...`);
// Parcourir toutes les factions
for (const factionJson of factionsData) {
try {
// Préparer les données de la faction selon le modèle
const itemData = {
name: factionJson.nom,
type: 'faction',
system: {
description: factionJson.description
}
};
// Vérifier si la faction existe déjà
const existing = game.items.find(i => i.name === factionJson.nom && i.type === 'faction');
if (existing) {
// Mettre à jour la faction existante
await existing.update(itemData);
updateCount++;
console.log(`Faction mise à jour: ${factionJson.nom}`);
} else {
// Créer une nouvelle faction dans le dossier
await Item.create({
...itemData,
folder: factionsFolder.id
});
importCount++;
console.log(`✓ Créé: ${factionJson.nom}`);
}
} catch (error) {
errorCount++;
console.error(`Erreur lors de l'import de ${factionJson.nom}:`, error);
}
}
// Afficher le résumé
const message = `
<h3>Import des factions terminé</h3>
<p><strong>Factions créées:</strong> ${importCount}</p>
<p><strong>Factions mises à jour:</strong> ${updateCount}</p>
<p><strong>Erreurs:</strong> ${errorCount}</p>
`;
ChatMessage.create({
user: game.user.id,
content: message
});
ui.notifications.info(`Import terminé: ${importCount} créées, ${updateCount} mises à jour, ${errorCount} erreurs.`);
console.log('=== Résumé de l\'import ===');
console.log(`Factions créées: ${importCount}`);
console.log(`Factions mises à jour: ${updateCount}`);
console.log(`Erreurs: ${errorCount}`);
}
// Exécuter l'import
importFactions();
+93
View File
@@ -0,0 +1,93 @@
/**
* Macro d'import des peuples depuis peuples.json
* Crée un dossier "Peuples" et y importe tous les peuples
*/
async function importPeuples() {
// Charger le fichier JSON
const response = await fetch('systems/fvtt-hamalron/assets/data/peuples.json');
const peuplesData = await response.json();
ui.notifications.info("Début de l'import des peuples...");
// Créer ou récupérer le dossier pour les peuples
let peuplesFolder = game.folders.find(f => f.name === "Peuples" && f.type === "Item");
if (!peuplesFolder) {
peuplesFolder = await Folder.create({
name: "Peuples",
type: "Item",
color: "#228b22",
sorting: "a"
});
console.log("Dossier 'Peuples' créé");
} else {
console.log("Dossier 'Peuples' existant trouvé");
}
// Compteurs pour le résumé
let importCount = 0;
let updateCount = 0;
let errorCount = 0;
ui.notifications.info(`Début de l'import de ${peuplesData.length} peuples...`);
// Parcourir tous les peuples
for (const peupleJson of peuplesData) {
try {
// Préparer les données du peuple selon le modèle
const itemData = {
name: peupleJson.nom,
type: 'peuple',
system: {
description: peupleJson.description
}
};
// Vérifier si le peuple existe déjà
const existing = game.items.find(i => i.name === peupleJson.nom && i.type === 'peuple');
if (existing) {
// Mettre à jour le peuple existant
await existing.update(itemData);
updateCount++;
console.log(`Peuple mis à jour: ${peupleJson.nom}`);
} else {
// Créer un nouveau peuple dans le dossier
await Item.create({
...itemData,
folder: peuplesFolder.id
});
importCount++;
console.log(`✓ Créé: ${peupleJson.nom}`);
}
} catch (error) {
errorCount++;
console.error(`Erreur lors de l'import de ${peupleJson.nom}:`, error);
}
}
// Afficher le résumé
const message = `
<h3>Import des peuples terminé</h3>
<p><strong>Peuples créés:</strong> ${importCount}</p>
<p><strong>Peuples mis à jour:</strong> ${updateCount}</p>
<p><strong>Erreurs:</strong> ${errorCount}</p>
`;
ChatMessage.create({
user: game.user.id,
content: message
});
ui.notifications.info(`Import terminé: ${importCount} créés, ${updateCount} mis à jour, ${errorCount} erreurs.`);
console.log('=== Résumé de l\'import ===');
console.log(`Peuples créés: ${importCount}`);
console.log(`Peuples mis à jour: ${updateCount}`);
console.log(`Erreurs: ${errorCount}`);
}
// Exécuter l'import
importPeuples();
+250 -35
View File
@@ -1,4 +1,5 @@
import HamalronActorSheet from "./base-actor-sheet.mjs"
import { SYSTEM } from "../../config/system.mjs"
export default class HamalronPersonnageSheet extends HamalronActorSheet {
/** @override */
@@ -20,6 +21,12 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
createRitual: HamalronPersonnageSheet.#onCreateRitual,
createPerk: HamalronPersonnageSheet.#onCreatePerk,
modifyAmmo: HamalronPersonnageSheet.#onModifyAmmo,
modifyResistance: HamalronPersonnageSheet.#onModifyResistance,
discardCard: HamalronPersonnageSheet.#onDiscardCard,
rollCompetence: HamalronPersonnageSheet.#onRollCompetence,
drawCard: HamalronPersonnageSheet.#onDrawCard,
selectCard: HamalronPersonnageSheet.#onSelectCard,
discardAndDraw: HamalronPersonnageSheet.#onDiscardAndDraw,
},
}
@@ -31,18 +38,18 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
tabs: {
template: "templates/generic/tab-navigation.hbs",
},
status: {
competences: {
template: "systems/fvtt-hamalron/templates/personnage-status.hbs",
},
maleficas: {
tarot: {
template: "systems/fvtt-hamalron/templates/personnage-tarot.hbs",
},
sortileges: {
template: "systems/fvtt-hamalron/templates/personnage-sortileges.hbs",
},
equipment: {
template: "systems/fvtt-hamalron/templates/personnage-equipement.hbs",
},
tarot: {
template: "systems/fvtt-hamalron/templates/personnage-tarot.hbs",
},
biography: {
template: "systems/fvtt-hamalron/templates/personnage-biographie.hbs",
},
@@ -50,7 +57,7 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
/** @override */
tabGroups = {
sheet: "status",
sheet: "competences",
}
/**
@@ -59,10 +66,10 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
*/
#getTabs() {
const tabs = {
status: { id: "status", group: "sheet", icon: "fa-solid fa-compass", label: "HAMALRON.Label.status" },
maleficas: { id: "maleficas", group: "sheet", icon: "fa-solid fa-compass", label: "HAMALRON.Label.maleficas" },
equipment: { id: "equipment", group: "sheet", icon: "fa-solid fa-shapes", label: "HAMALRON.Label.equipment" },
competences: { id: "competences", group: "sheet", icon: "fa-solid fa-list-check", label: "HAMALRON.Label.competences" },
tarot: { id: "tarot", group: "sheet", icon: "fa-solid fa-cards", label: "HAMALRON.Label.tarot" },
sortileges: { id: "sortileges", group: "sheet", icon: "fa-solid fa-wand-magic-sparkles", label: "HAMALRON.Label.sortileges" },
equipment: { id: "equipment", group: "sheet", icon: "fa-solid fa-shapes", label: "HAMALRON.Label.equipment" },
biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "HAMALRON.Label.biography" },
}
for (const v of Object.values(tabs)) {
@@ -78,9 +85,6 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
context.tabs = this.#getTabs()
const doc = this.document
context.trait = doc.itemTypes['species-trait']?.[0]
context.upright = doc.itemTypes.tarot.find(t => t.system.orientation === "Upright")
context.downright = doc.itemTypes.tarot.find(t => t.system.orientation === "Downright")
return context
}
@@ -91,30 +95,36 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
context.systemFields = this.document.system.schema.fields
switch (partId) {
case "main":
// Get peuple and faction items (only one of each allowed)
context.peuple = doc.itemTypes.peuple?.[0] || null
context.faction = doc.itemTypes.faction?.[0] || null
context.isEditMode = this.isEditMode
context.isPlayMode = this.isPlayMode
break
case "status":
context.tab = context.tabs.status
context.perks = doc.itemTypes.perk || []
// Sort the perks by system.role and then by the system.level
context.perks.sort((a, b) => {
if (a.system.role === b.system.role) {
return a.system.level.localeCompare(b.system.level)
}
return a.system.role.localeCompare(b.system.role)
case "competences":
context.tab = context.tabs.competences
const allCompetences = doc.itemTypes.competence || []
// Ajouter les données de niveau enrichies à chaque compétence
allCompetences.forEach(c => {
const niveauData = SYSTEM.NIVEAU_COMPETENCES[c.system.niveau]
c.niveauName = niveauData?.name || c.system.niveau
c.niveauModificateur = niveauData?.modificateur ?? 0
})
// Grouper les compétences par type et trier par nom dans chaque groupe
context.competencesCommunes = allCompetences.filter(c => c.system.type === 'commune').sort((a, b) => a.name.localeCompare(b.name))
context.competencesPeuple = allCompetences.filter(c => c.system.type === 'peuple').sort((a, b) => a.name.localeCompare(b.name))
context.competencesFaction = allCompetences.filter(c => c.system.type === 'faction').sort((a, b) => a.name.localeCompare(b.name))
break;
case "maleficas":
context.tab = context.tabs.maleficas
context.maleficas = doc.itemTypes.malefica || []
// Sort the maleficas by system.domain and then by the system.level
context.maleficas.sort((a, b) => {
case "sortileges":
context.tab = context.tabs.sortileges
context.sortileges = doc.itemTypes.sortilege || []
// Sort the sortileges by system.domain and then by the system.level
context.sortileges.sort((a, b) => {
if (a.system.domain === b.system.domain) {
return a.system.level.localeCompare(b.system.level)
}
return a.system.domain.localeCompare(b.system.domain)
})
context.rituals = doc.itemTypes.ritual || []
context.rituals.sort((a, b) => a.name.localeCompare(b.name))
break
case "equipment":
context.tab = context.tabs.equipment
@@ -129,9 +139,23 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
context.tab = context.tabs.tarot
context.tarotCards = doc.itemTypes.tarot || []
context.tarotCards.sort((a, b) => a.name.localeCompare(b.name))
// Enrich descriptions for each tarot card
context.handLimit = 7
context.handSize = context.tarotCards.length
context.isOverLimit = context.handSize > context.handLimit
context.canAddCard = context.handSize < 8
// Marquer les cartes de succès et enrichir les descriptions
for (const card of context.tarotCards) {
card.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(card.system.description, { async: true })
// Vérifier si c'est une carte de succès
if (doc.system.cartesSucces && card.system.type !== "atout") {
card.isSuccessCard = Object.keys(doc.system.cartesSucces).some(symbole => {
const successCardData = doc.system.cartesSucces[symbole]
return card.system.symbole === symbole &&
card.system.valeur === successCardData.value.toString()
})
} else {
card.isSuccessCard = false
}
}
break
case "biography":
@@ -196,6 +220,190 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
await item.update({ "system.ammoQuantity": newAmmo })
}
static async #onModifyResistance(event, target) {
const symbole = target.dataset.symbole
const delta = Number.parseInt(target.dataset.delta)
if (!symbole || isNaN(delta)) {
console.warn(`HamalronPersonnageSheet: Invalid resistance modification parameters`)
return
}
const resistance = this.document.system.resistances[symbole]
if (!resistance) {
console.warn(`HamalronPersonnageSheet: Resistance ${symbole} not found`)
return
}
const newValue = Math.max(0, Math.min(resistance.max, resistance.value + delta))
await this.document.update({ [`system.resistances.${symbole}.value`]: newValue })
}
static async #onDiscardCard(event, target) {
const itemId = $(event.target).data("item-id")
const item = this.document.items.get(itemId)
if (!item || item.type !== "tarot") {
console.warn(`HamalronPersonnageSheet: Tarot card with ID ${itemId} not found`)
return
}
// Supprimer la carte du personnage
await item.delete()
ui.notifications.info(game.i18n.localize("HAMALRON.Notifications.cardDiscarded") + item.name)
}
static async #onSelectCard(event, target) {
const cardWrapper = $(target).closest(".tarot-card-wrapper")
const wasSelected = cardWrapper.hasClass("selected")
// Désélectionner toutes les cartes
$(".tarot-card-wrapper").removeClass("selected")
// Sélectionner la carte cliquée si elle n'était pas déjà sélectionnée
if (!wasSelected) {
cardWrapper.addClass("selected")
}
}
static async #onDiscardAndDraw(event, target) {
const itemId = $(target).data("item-id")
const item = this.document.items.get(itemId)
if (!item || item.type !== "tarot") {
console.warn(`HamalronPersonnageSheet: Tarot card with ID ${itemId} not found`)
return
}
// Dialog de confirmation
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.localize("HAMALRON.Dialog.discardCardTitle"),
},
content: `<p>${game.i18n.format("HAMALRON.Dialog.discardCardContent", { cardName: item.name })}</p>`,
rejectClose: false,
modal: true,
})
if (!confirmed) return
// Récupérer le deck manager
const module = await import("../tarot-deck-manager.mjs")
const HamalronTarotDeckManager = module.default
if (!HamalronTarotDeckManager._instance) {
HamalronTarotDeckManager._instance = new HamalronTarotDeckManager()
}
const deckManager = HamalronTarotDeckManager._instance
if (!deckManager) {
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.deckManagerNotAvailable"))
return
}
// Ajouter la carte à la défausse
deckManager.addToDiscard({
id: item.id,
name: item.name,
img: item.img,
symbole: item.system.symbole,
valeur: item.system.valeur,
type: item.system.type,
description: item.system.description,
})
// Supprimer la carte du personnage
await item.delete()
// Tirer une nouvelle carte si le deck n'est pas vide
if (deckManager.deck.length > 0) {
const newCards = deckManager.drawCards(1)
if (newCards.length > 0) {
const newCard = newCards[0]
// Cas spécial : Le Mat
if (newCard.valeur === "lemat") {
console.log("Le Mat drawn! Executing special rules...")
const { default: HamalronTirageTarot } = await import("../../documents/tirage-tarot.mjs")
await HamalronTirageTarot.handleLeMatEffect(this.document, deckManager)
} else {
const originalItem = game.items.get(newCard.id)
if (originalItem) {
await this.document.createEmbeddedDocuments("Item", [originalItem.toObject()])
ui.notifications.info(game.i18n.localize("HAMALRON.Notifications.cardDiscardedAndDrawn") + newCard.name)
}
}
}
} else {
ui.notifications.info(game.i18n.localize("HAMALRON.Notifications.cardDiscardedNoNew"))
}
deckManager.saveDeckState()
deckManager.render()
}
static async #onDrawCard(event, target) {
const currentTarotCount = this.document.items.filter(i => i.type === "tarot").length
// Vérifier que le joueur a moins de 7 cartes
if (currentTarotCount >= 7) {
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.cannotDrawCard"))
return
}
// Récupérer le deck manager singleton
const module = await import("../tarot-deck-manager.mjs")
const HamalronTarotDeckManager = module.default
// Vérifier si l'instance existe, sinon la créer
if (!HamalronTarotDeckManager._instance) {
HamalronTarotDeckManager._instance = new HamalronTarotDeckManager()
}
const deckManager = HamalronTarotDeckManager._instance
if (!deckManager) {
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.deckManagerNotAvailable"))
return
}
if (deckManager.deck.length === 0) {
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.deckEmpty"))
return
}
// Tirer une nouvelle carte
const newCards = deckManager.drawCards(1)
if (newCards.length > 0) {
const newCard = newCards[0]
// Cas spécial : Le Mat
if (newCard.valeur === "lemat") {
console.log("Le Mat drawn! Executing special rules...")
const { default: HamalronTirageTarot } = await import("../../documents/tirage-tarot.mjs")
await HamalronTirageTarot.handleLeMatEffect(this.document, deckManager)
} else {
// Trouver l'item original pour le dupliquer
const originalItem = game.items.get(newCard.id)
if (originalItem) {
await this.document.createEmbeddedDocuments("Item", [originalItem.toObject()])
ui.notifications.info(game.i18n.localize("HAMALRON.Notifications.newCardDrawn") + newCard.name)
}
}
deckManager.saveDeckState()
deckManager.render()
}
}
static async #onRollCompetence(event, target) {
const itemId = $(target).data("item-id")
const item = this.document.items.get(itemId)
if (!item || item.type !== "competence") {
console.warn(`HamalronPersonnageSheet: Competence with ID ${itemId} not found`)
return
}
await this.document.system.roll("competence", item)
}
/**
* Handles the roll action triggered by user interaction.
*
@@ -239,12 +447,19 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
if (data.type === "Item") {
const item = await fromUuid(data.uuid)
if (item.type === "tarot") {
// Delete the existing tarot item
const existingTarot = this.document.items.find(i => i.type === "tarot" && i.system.orientation === item.system.orientation)
if (existingTarot) {
await existingTarot.delete()
// Display info message
ui.notifications.info(game.i18n.localize("HAMALRON.Notifications.tarotDeleted") + existingTarot.name)
// Check if a card with the same name already exists
const existingCard = this.document.items.find(i => i.type === "tarot" && i.name === item.name)
if (existingCard) {
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.tarotCardAlreadyExists") + item.name)
return
}
const currentTarotCount = this.document.items.filter(i => i.type === "tarot").length
// Check if we already have 8 cards (hard limit)
if (currentTarotCount >= 8) {
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.tarotHandFull"))
return
}
}
if (item.type === "species-trait") {
+347 -7
View File
@@ -4,8 +4,8 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
constructor(options = {}) {
super(options)
this.deck = []
this.drawnCards = []
this.resetDeck()
this.discard = []
this.loadDeckState()
}
/** @override */
@@ -26,6 +26,10 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
resetDeck: HamalronTarotDeckManager.#onResetDeck,
drawCard: HamalronTarotDeckManager.#onDrawCard,
drawMultiple: HamalronTarotDeckManager.#onDrawMultiple,
shuffleDiscard: HamalronTarotDeckManager.#onShuffleDiscard,
collectHands: HamalronTarotDeckManager.#onCollectHands,
distributeCards: HamalronTarotDeckManager.#onDistributeCards,
drawTension: HamalronTarotDeckManager.#onDrawTension,
},
}
@@ -36,12 +40,39 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
},
}
/**
* Save the current deck state to settings
*/
async saveDeckState() {
const state = {
deck: this.deck,
discard: this.discard,
}
await game.settings.set("fvtt-hamalron", "tarotDeckState", state)
console.log("Deck state saved:", state)
}
/**
* Load the deck state from settings
*/
loadDeckState() {
const state = game.settings.get("fvtt-hamalron", "tarotDeckState")
if (state && state.deck && state.deck.length > 0) {
this.deck = state.deck
this.discard = state.discard || []
console.log("Deck state loaded:", state)
} else {
// Si aucun état sauvegardé, initialiser un nouveau deck
this.resetDeck()
}
}
/**
* Reset the deck to a full tarot deck
*/
resetDeck() {
this.deck = []
this.drawnCards = []
this.discard = []
// Créer toutes les cartes du jeu de tarot
const items = game.items.filter(i => i.type === "tarot")
@@ -63,6 +94,7 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
// Mélanger le deck
this.shuffleDeck()
this.saveDeckState()
this.render()
}
@@ -90,7 +122,6 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
const drawn = []
for (let i = 0; i < count && this.deck.length > 0; i++) {
const card = this.deck.shift()
this.drawnCards.push(card)
drawn.push(card)
}
@@ -130,10 +161,10 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
const context = await super._prepareContext(options)
context.deckCount = this.deck.length
context.drawnCount = this.drawnCards.length
context.totalCards = this.deck.length + this.drawnCards.length
context.discardCount = this.discard.length
context.totalCards = this.deck.length + this.discard.length
context.hasCards = this.deck.length > 0
context.drawnCards = this.drawnCards.slice(-5).reverse() // Show last 5 drawn cards
context.hasDiscard = this.discard.length > 0
return context
}
@@ -166,6 +197,9 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
const cards = this.drawCards(1)
if (cards.length > 0) {
await this.sendCardsToChat(cards)
// Ajouter les cartes directement à la défausse
cards.forEach(card => this.addToDiscard(card))
this.saveDeckState()
this.render()
}
}
@@ -180,10 +214,316 @@ export default class HamalronTarotDeckManager extends HandlebarsApplicationMixin
const cards = this.drawCards(count)
if (cards.length > 0) {
await this.sendCardsToChat(cards)
// Ajouter les cartes directement à la défausse
cards.forEach(card => this.addToDiscard(card))
this.saveDeckState()
this.render()
}
}
/**
* Add a card to the discard pile
* @param {Object} card - Card to add to discard
*/
addToDiscard(card) {
// Vérifier que la carte n'est pas déjà dans la défausse
const cardExists = this.discard.some(c => c.id === card.id)
if (!cardExists) {
this.discard.push(card)
this.saveDeckState()
this.render()
}
}
/**
* Collect all tarot cards from player characters and return them to the deck
* @param {Event} event
* @param {HTMLElement} target
*/
static async #onCollectHands(event, target) {
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: { title: game.i18n.localize("HAMALRON.TarotDeck.CollectHandsConfirm") },
content: `<p>${game.i18n.localize("HAMALRON.TarotDeck.CollectHandsWarning")}</p>`,
rejectClose: false,
modal: true,
})
if (!confirmed) return
let totalCollected = 0
// Récupérer tous les acteurs de type personnage (incluant tous, pas seulement ceux avec propriété joueur)
const playerCharacters = game.actors.filter(a => a.type === "personnage")
console.log("Found characters:", playerCharacters.length)
// Collecter toutes les cartes de tarot de tous les personnages
for (const actor of playerCharacters) {
const tarotCards = actor.items.filter(i => i.type === "tarot")
console.log(`Actor ${actor.name} has ${tarotCards.length} tarot cards`)
if (tarotCards.length > 0) {
// Supprimer les cartes de l'acteur
const cardIds = tarotCards.map(c => c.id)
console.log(`Deleting ${cardIds.length} cards from ${actor.name}`)
await actor.deleteEmbeddedDocuments("Item", cardIds)
console.log(`Deleted cards from ${actor.name}`)
totalCollected += tarotCards.length
}
}
// Réinitialiser le deck avec toutes les cartes de tarot disponibles
this.deck = []
this.discard = []
const items = game.items.filter(i => i.type === "tarot")
if (items.length > 0) {
// Créer un Map pour éviter les doublons (utiliser l'ID unique)
const uniqueCards = new Map()
items.forEach(item => {
const key = `${item.system.symbole}_${item.system.valeur}_${item.system.type}`
if (!uniqueCards.has(key)) {
uniqueCards.set(key, {
id: item.id,
name: item.name,
img: item.img,
symbole: item.system.symbole,
valeur: item.system.valeur,
type: item.system.type,
description: item.system.description,
})
}
})
this.deck = Array.from(uniqueCards.values())
}
// Mélanger le deck
this.shuffleDeck()
this.saveDeckState()
ui.notifications.info(
game.i18n.format("HAMALRON.TarotDeck.HandsCollected", {
collected: totalCollected,
deckSize: this.deck.length
})
)
this.render()
}
/**
* Distribute 8 cards to all connected players
* @param {Event} event
* @param {HTMLElement} target
*/
static async #onDistributeCards(event, target) {
if (this.deck.length < 8) {
ui.notifications.warn(game.i18n.localize("HAMALRON.TarotDeck.NotEnoughCards"))
return
}
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: { title: game.i18n.localize("HAMALRON.TarotDeck.DistributeConfirm") },
content: `<p>${game.i18n.localize("HAMALRON.TarotDeck.DistributeWarning")}</p>`,
rejectClose: false,
modal: true,
})
if (!confirmed) return
let distributedCount = 0
let playersCount = 0
// Récupérer tous les utilisateurs connectés (sauf le GM)
const connectedPlayers = game.users.filter(u => u.active && !u.isGM)
for (const user of connectedPlayers) {
// Trouver le personnage du joueur (premier actor de type personnage dont il est propriétaire)
const playerCharacter = game.actors.find(a =>
a.type === "personnage" &&
a.testUserPermission(user, "OWNER")
)
if (playerCharacter) {
// Tirer 8 cartes pour ce personnage
const cardsToDistribute = []
for (let i = 0; i < 8 && this.deck.length > 0; i++) {
const card = this.deck.shift()
cardsToDistribute.push(card)
}
// Créer les items sur l'acteur
for (const card of cardsToDistribute) {
const originalItem = game.items.get(card.id)
if (originalItem) {
await playerCharacter.createEmbeddedDocuments("Item", [originalItem.toObject()])
distributedCount++
// Cas spécial : Le Mat
if (card.valeur === "lemat") {
console.log(`Le Mat distributed to ${playerCharacter.name}! Executing special rules...`)
// Import de TirageTarot pour accéder à la fonction helper
const { default: HamalronTirageTarot } = await import("../documents/tirage-tarot.mjs")
await HamalronTirageTarot.handleLeMatEffect(playerCharacter, this)
}
}
}
playersCount++
}
}
this.saveDeckState()
ui.notifications.info(
game.i18n.format("HAMALRON.TarotDeck.CardsDistributed", {
cards: distributedCount,
players: playersCount
})
)
this.render()
}
/**
* Shuffle discard pile back into deck
* @param {Event} event
* @param {HTMLElement} target
*/
static async #onShuffleDiscard(event, target) {
if (this.discard.length === 0) {
ui.notifications.warn(game.i18n.localize("HAMALRON.TarotDeck.NoDiscard"))
return
}
// Ajouter toutes les cartes de la défausse au deck
this.deck.push(...this.discard)
this.discard = []
// Mélanger le deck
this.shuffleDeck()
this.saveDeckState()
ui.notifications.info(game.i18n.localize("HAMALRON.TarotDeck.DiscardShuffled"))
this.render()
}
/**
* Handle draw tension action
* @param {Event} event
* @param {HTMLElement} target
*/
static async #onDrawTension(event, target) {
// Import system config
const { DIFFICULTY_CHOICES } = await import('../config/system.mjs')
// Créer les options de difficulté
const difficulties = Object.entries(DIFFICULTY_CHOICES)
.filter(([key]) => key !== 'soustension_oppose')
.map(([key, value]) => ({
value: key,
label: value.label
}))
// Créer le contenu HTML du dialogue
const selectOptions = difficulties.map(d =>
`<option value="${d.value}">${d.label}</option>`
).join('')
const content = `
<div class="form-group">
<label>{{localize "HAMALRON.Label.difficulty"}}</label>
<select id="tension-difficulty" style="width: 100%;">
${selectOptions}
</select>
</div>
`
// Afficher le dialogue
const result = await foundry.applications.api.DialogV2.wait({
window: { title: game.i18n.localize("HAMALRON.TarotDeck.SelectDifficulty") },
content: content,
buttons: [
{
action: "draw",
label: game.i18n.localize("HAMALRON.TarotDeck.DrawCard"),
default: true,
callback: (event, button, dialog) => {
const select = button.form.elements["tension-difficulty"]
return select.value
}
},
{
action: "cancel",
label: game.i18n.localize("Cancel")
}
],
rejectClose: false,
modal: true
})
if (!result) return
// Tirer une carte
const cards = this.drawCards(1)
if (cards.length === 0) return
const card = cards[0]
const difficultyKey = result
const difficulty = DIFFICULTY_CHOICES[difficultyKey]
// Récupérer la valeur numérique de la carte
const { TAROT_VALEURS } = await import('../config/system.mjs')
const cardValue = TAROT_VALEURS[card.valeur]?.value || 0
const tensionBonus = difficulty.soustension || 0
const totalScore = cardValue + tensionBonus
// Afficher dans le chat
await this.sendTensionDrawToChat(card, difficulty, cardValue, tensionBonus, totalScore)
// Ajouter à la défausse
this.addToDiscard(card)
this.saveDeckState()
this.render()
}
/**
* Send tension draw to chat
* @param {Object} card - The drawn card
* @param {Object} difficulty - The selected difficulty
* @param {number} cardValue - Card numeric value
* @param {number} tensionBonus - Tension modifier
* @param {number} totalScore - Total score
*/
async sendTensionDrawToChat(card, difficulty, cardValue, tensionBonus, totalScore) {
const speaker = ChatMessage.getSpeaker({ alias: "Maître du Jeu" })
const content = await foundry.applications.handlebars.renderTemplate(
"systems/fvtt-hamalron/templates/chat-tarot-tension.hbs",
{
card: card,
symboleLabel: game.i18n.localize(`HAMALRON.Tarot.FIELDS.symbole.${card.symbole}`),
valeurLabel: game.i18n.localize(`HAMALRON.Tarot.FIELDS.valeur.${card.valeur}`),
typeLabel: game.i18n.localize(`HAMALRON.Tarot.FIELDS.type.${card.type}`),
difficulty: difficulty,
cardValue: cardValue,
tensionBonus: tensionBonus,
totalScore: totalScore
}
)
await ChatMessage.create({
speaker: speaker,
content: content,
type: CONST.CHAT_MESSAGE_TYPES.OTHER,
})
}
/**
* Open the Tarot Deck Manager application
* @returns {HamalronTarotDeckManager}
+52 -1
View File
@@ -23,10 +23,23 @@ export const TAROT_TYPES = {
}
export const TAROT_VALEURS = {
"11": { id: "11", label: "11", value: 11 },
"12": { id: "12", label: "12", value: 12 },
"13": { id: "13", label: "13", value: 13 },
"14": { id: "14", label: "14", value: 14 },
"15": { id: "15", label: "15", value: 15 },
"16": { id: "16", label: "16", value: 16 },
"17": { id: "17", label: "17", value: 17 },
"18": { id: "18", label: "18", value: 18 },
"19": { id: "19", label: "19", value: 19 },
"20": { id: "20", label: "20", value: 20 },
"21": { id: "21", label: "21", value: 21 },
"22": { id: "22", label: "22", value: 22 },
"roi": { id: "roi", label: "Roi", value: 14 },
"reine": { id: "reine", label: "Reine", value: 13 },
"cavalier": { id: "cavalier", label: "Cavalier", value: 12 },
"valet": { id: "valet", label: "Valet", value: 11 },
"lemat": { id: "lemat", label: "Le Mat", value: 23 },
"10": { id: "10", label: "10", value: 10 },
"9": { id: "9", label: "9", value: 9 },
"8": { id: "8", label: "8", value: 8 },
@@ -40,6 +53,7 @@ export const TAROT_VALEURS = {
}
export const DIFFICULTY_CHOICES = {
"soustension_oppose": { id: "soustension_oppose", label: "Sous Tension ou Opposé", standard: null, "soustension": null },
"tresfacile": { id: "tresfacile", label: "Très Facile", standard: 3, "soustension": -4 },
"facile": { id: "facile", label: "Facile", standard: 5, "soustension": -2 },
"moyenne": { id: "moyenne", label: "Moyenne", standard: 7, "soustension": 0 },
@@ -54,7 +68,7 @@ export const WEAPON_TYPES = {
}
export const COMPETENCE_TYPES = {
"generale": { id: "generale", label: "Générale" },
"commune": { id: "commune", label: "Commune" },
"faction": { id: "faction", label: "Faction" },
"peuple": { id: "peuple", label: "Peuple" },
}
@@ -70,6 +84,42 @@ export const SORTILEGE_CATEGORIES = {
"ritual": { id: "ritual", label: "Rituel" },
}
export const NIVEAU_COMPETENCES = {
"inexperimente": {
"name": "Inexpérimenté",
"id": "inexperimente",
"abreviation": "I",
"modificateur": 0,
"cout_acquisition_points": 0,
"description": "Niveau de départ par défaut pour toutes les compétences non apprises."
},
"amateur": {
"name": "Amateur",
"id": "amateur",
"abreviation": "A",
"modificateur": 1,
"cout_acquisition_points": 1,
"description": "Le personnage possède des notions de base dans la compétence."
},
"competent": {
"name": "Compétent",
"id": "competent",
"abreviation": "C",
"modificateur": 3,
"cout_acquisition_points": 3,
"cout_progression_depuis_amateur": 2,
"description": "Le personnage maîtrise la compétence et résiste mieux aux actions adverses."
},
"expert": {
"name": "Expert",
"abreviation": "E",
"modificateur": 5,
"cout_acquisition_points": 5,
"cout_progression_depuis_competent": 2,
"description": "Le personnage est un maître absolu dans son domaine."
}
}
/**
* Include all constant definitions within the SYSTEM global export
* @type {Object}
@@ -84,5 +134,6 @@ export const SYSTEM = {
COMPETENCE_TYPES: COMPETENCE_TYPES,
ENEMY_TYPES: ENEMY_TYPES,
SORTILEGE_CATEGORIES: SORTILEGE_CATEGORIES,
NIVEAU_COMPETENCES: NIVEAU_COMPETENCES,
ASCII
}
+10 -10
View File
@@ -1,14 +1,14 @@
export const defaultItemImg = {
arme: "systems/fvtt-hamalron/assets/icons/arme.webp",
armure: "systems/fvtt-hamalron/assets/icons/armure.webp",
competence: "systems/fvtt-hamalron/assets/icons/competence.webp",
equipement: "systems/fvtt-hamalron/assets/icons/equipement.webp",
faction: "systems/fvtt-hamalron/assets/icons/faction.webp",
langue: "systems/fvtt-hamalron/assets/icons/langue.webp",
peuple: "systems/fvtt-hamalron/assets/icons/peuple.webp",
region: "systems/fvtt-hamalron/assets/icons/region.webp",
sortilege: "systems/fvtt-hamalron/assets/icons/sortilege.webp",
tarot: "systems/fvtt-hamalron/assets/icons/tarot.webp",
arme: "systems/fvtt-hamalron/assets/icons/arme.svg",
armure: "systems/fvtt-hamalron/assets/icons/armure.svg",
competence: "systems/fvtt-hamalron/assets/icons/competence.svg",
equipement: "systems/fvtt-hamalron/assets/icons/equipement.svg",
faction: "systems/fvtt-hamalron/assets/icons/faction.svg",
langue: "systems/fvtt-hamalron/assets/icons/langue.svg",
peuple: "systems/fvtt-hamalron/assets/icons/peuple.svg",
region: "systems/fvtt-hamalron/assets/icons/region.svg",
sortilege: "systems/fvtt-hamalron/assets/icons/sortilege.svg",
tarot: "systems/fvtt-hamalron/assets/icons/tarot.svg",
}
export default class HamalronItem extends Item {
+396 -4
View File
@@ -8,6 +8,57 @@ export default class HamalronTirageTarot {
*/
static CHAT_TEMPLATE = "systems/fvtt-hamalron/templates/chat-message.hbs"
/**
* Handle Le Mat special effect when distributed to a player
* @param {Actor} actor - The actor who received Le Mat
* @param {HamalronTarotDeckManager} deckManager - The deck manager instance
*/
static async handleLeMatEffect(actor, deckManager) {
// 1. Défausser toutes les cartes du joueur
const allTarotCards = actor.items.filter(i => i.type === "tarot")
if (allTarotCards.length > 0) {
const cardIds = allTarotCards.map(c => c.id)
await actor.deleteEmbeddedDocuments("Item", cardIds)
console.log(`Discarded ${cardIds.length} cards from player`)
// Ajouter toutes les cartes à la défausse
for (const card of allTarotCards) {
deckManager.addToDiscard({
id: card.id,
name: card.name,
img: card.img,
symbole: card.system.symbole,
valeur: card.system.valeur,
type: card.system.type,
description: card.system.description,
})
}
}
// 2. Tirer 7 nouvelles cartes pour le joueur
for (let i = 0; i < 7; i++) {
if (deckManager.deck.length > 0) {
const newCards = deckManager.drawCards(1)
if (newCards.length > 0) {
const newCard = newCards[0]
const originalItem = game.items.get(newCard.id)
if (originalItem) {
await actor.createEmbeddedDocuments("Item", [originalItem.toObject()])
}
}
}
}
// 3. Regrouper la défausse et le deck, puis mélanger
deckManager.deck.push(...deckManager.discard)
deckManager.discard = []
deckManager.shuffleDeck()
await deckManager.saveDeckState()
deckManager.render()
ui.notifications.info(`Le Mat ! Toutes vos cartes ont été défaussées et vous recevez 7 nouvelles cartes. Le deck a été mélangé.`)
}
static async prompt(options = {}) {
let formula = `3D6 + 0D6KH - 0D6KH + ${options?.rollItem?.value}`
@@ -15,6 +66,34 @@ export default class HamalronTirageTarot {
switch (options.rollType) {
case "stat":
break
case "competence":
{
// Récupérer les cartes de tarot du personnage
options.tarotCards = actor.items.filter(i => i.type === "tarot")
// Récupérer le modificateur de compétence depuis NIVEAU_COMPETENCES
const niveauData = SYSTEM.NIVEAU_COMPETENCES[options.rollItem.system.niveau]
options.competenceModifier = niveauData ? niveauData.modificateur : 0
// Marquer les cartes de succès
if (options.tarotCards && actor.system.cartesSucces) {
options.tarotCards = options.tarotCards.map(card => {
const isSuccessCard = card.system.type !== "atout" && Object.keys(actor.system.cartesSucces).some(symbole => {
const successCardData = actor.system.cartesSucces[symbole]
return card.system.symbole === symbole &&
card.system.valeur === successCardData.value.toString()
})
// Créer un objet simple avec toutes les propriétés nécessaires
return {
id: card.id,
name: card.name,
img: card.img,
system: card.system,
isSuccessCard: isSuccessCard
}
})
}
}
break
case "damage":
{
let formula = options.rollItem.system.damage
@@ -56,6 +135,7 @@ export default class HamalronTirageTarot {
let dialogContext = {
actorId: options.actorId,
actorName: options.actorName,
actorImage: options.actorImage,
rollType: options.rollType,
rollItem: foundry.utils.duplicate(options.rollItem), // Object only, no class
weapon: options?.weapon,
@@ -69,23 +149,45 @@ export default class HamalronTirageTarot {
difficulty: "0",
nbAdvantages: "0",
nbDisadvantages: "0",
tarotCards: options.tarotCards || [],
competenceModifier: options.competenceModifier || 0,
difficultyChoices: Object.fromEntries(Object.entries(SYSTEM.DIFFICULTY_CHOICES).map(([key, val]) => [key, val.label])),
}
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-hamalron/templates/roll-dialog.hbs", dialogContext)
const title = HamalronRoll.createTitle(options.rollType, options.rollTarget)
const title = HamalronTirageTarot.createTitle(options.rollType, options.rollTarget)
const label = game.i18n.localize("HAMALRON.Roll.roll")
const cancelLabel = game.i18n.localize("HAMALRON.Roll.cancel")
const rollContext = await foundry.applications.api.DialogV2.wait({
window: { title: title },
classes: ["fvtt-hamalron"],
position: { width: 420 },
content,
buttons: [
{
action: "cancel",
label: cancelLabel,
default: false,
},
{
action: "roll",
label: label,
default: true,
disabled: options.rollType === "competence",
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
// Ajouter les données de sélection de carte pour les compétences
if (options.rollType === "competence") {
console.log("DEBUG CALLBACK: options.selectedCardId =", options.selectedCardId, "options.selectedCardValue =", options.selectedCardValue)
output.selectedCardId = options.selectedCardId
output.selectedCardValue = options.selectedCardValue
output.selectedDifficulty = options.selectedDifficulty
output.targetScore = options.targetScore
console.log("DEBUG CALLBACK: output =", output)
}
return output
},
},
@@ -96,11 +198,11 @@ export default class HamalronTirageTarot {
render: (event, dialog) => {
$(".roll-stat-advantages").change(event => {
options.nbAdvantages = Number(event.target.value)
HamalronRoll.updateFullFormula(options)
HamalronTirageTarot.updateFullFormula(options)
})
$(".roll-stat-disadvantages").change(event => {
options.nbDisadvantages = Number(event.target.value)
HamalronRoll.updateFullFormula(options)
HamalronTirageTarot.updateFullFormula(options)
})
$(".select-combat-option").change(event => {
let field = $(event.target).data("field")
@@ -110,14 +212,302 @@ export default class HamalronTirageTarot {
} else {
options.numericModifier -= modifier
}
HamalronRoll.updateFullFormula(options)
HamalronTirageTarot.updateFullFormula(options)
})
// Gestion de la sélection de carte pour les compétences
if (options.rollType === "competence") {
let selectedCardId = null
options.selectedDifficulty = "soustension_oppose"
options.targetScore = null
// Calculer et afficher les valeurs pour chaque carte
const competenceSymbole = options.rollItem.system.carteSymbole
$(".tarot-card-select").each(function () {
const cardSymbole = $(this).data("card-symbole")
const cardValeur = $(this).data("card-valeur")
const cardType = $(this).data("card-type")
const valeurData = SYSTEM.TAROT_VALEURS[cardValeur]
const baseValue = valeurData ? valeurData.value : 0
let calculatedValue = 0
if (cardType === "atout") {
calculatedValue = baseValue
} else if (cardSymbole === competenceSymbole) {
calculatedValue = baseValue
} else {
calculatedValue = Math.ceil(baseValue / 2)
}
$(this).find(".card-values").text(`${baseValue}${calculatedValue}`)
})
// Gestion du changement de difficulté
$(".difficulty-select").change(function () {
const difficultyKey = $(this).val()
options.selectedDifficulty = difficultyKey
const difficultyData = SYSTEM.DIFFICULTY_CHOICES[difficultyKey]
if (difficultyData.standard === null) {
// Sous tension ou opposé - pas de score cible
options.targetScore = null
$("#target-score").text("-")
} else {
options.targetScore = difficultyData.standard
$("#target-score").text(options.targetScore)
}
})
$(".tarot-card-select").click(function () {
// Désélectionner toutes les cartes
$(".tarot-card-select").removeClass("selected")
// Sélectionner la carte cliquée
$(this).addClass("selected")
selectedCardId = $(this).data("card-id")
console.log("DEBUG CLICK: selectedCardId =", selectedCardId)
const cardSymbole = $(this).data("card-symbole")
const cardValeur = $(this).data("card-valeur")
const cardType = $(this).data("card-type")
// Calculer la valeur de la carte
const competenceSymbole = options.rollItem.system.carteSymbole
let cardValue = 0
// Récupérer la valeur numérique de la carte depuis TAROT_VALEURS
const valeurData = SYSTEM.TAROT_VALEURS[cardValeur]
const baseValue = valeurData ? valeurData.value : 0
if (cardType === "atout") {
// Si c'est un atout, prendre directement la valeur
cardValue = baseValue
} else if (cardSymbole === competenceSymbole) {
// Si le symbole correspond, prendre la valeur complète
cardValue = baseValue
} else {
// Sinon, diviser par 2 arrondi au supérieur
cardValue = Math.ceil(baseValue / 2)
}
// Stocker la carte sélectionnée et sa valeur calculée
options.selectedCardId = selectedCardId
options.selectedCardValue = cardValue
console.log("DEBUG CLICK END: options.selectedCardId =", options.selectedCardId, "options.selectedCardValue =", options.selectedCardValue)
// Mettre à jour l'affichage
$("#card-value-display").text(`+ ${cardValue}`)
$("#total-value").text(options.competenceModifier + cardValue)
// Activer le bouton de lancement
$("button[data-action='roll']").prop("disabled", false)
})
// Permettre de désélectionner en cliquant à nouveau
$(".tarot-card-select").dblclick(function () {
$(this).removeClass("selected")
options.selectedCardId = null
options.selectedCardValue = 0
$("#card-value-display").text("+ 0")
$("#total-value").text(options.competenceModifier)
// Désactiver le bouton de lancement
$("button[data-action='roll']").prop("disabled", true)
})
}
}
})
// If the user cancels the dialog, exit
if (rollContext === null) return
// Fusionner les données du dialogue dans options
Object.assign(options, rollContext)
// Gestion spéciale pour les compétences (pas de dés)
if (options.rollType === "competence") {
const totalValue = options.competenceModifier + (options.selectedCardValue || 0)
// Récupérer la carte sélectionnée si elle existe
let selectedCard = null
let cardSymboleMatch = false
let isAutomaticSuccess = false
if (options.selectedCardId) {
selectedCard = actor.items.get(options.selectedCardId)
if (selectedCard) {
cardSymboleMatch = selectedCard.system.symbole === options.rollItem.system.carteSymbole
// Vérifier si c'est une carte de succès (les atouts ne peuvent jamais être des cartes de succès)
if (actor.system.cartesSucces && selectedCard.system.type !== "atout") {
isAutomaticSuccess = Object.keys(actor.system.cartesSucces).some(symbole => {
const successCardData = actor.system.cartesSucces[symbole]
return selectedCard.system.symbole === symbole &&
selectedCard.system.valeur === successCardData.value.toString()
})
}
}
}
// Préparer les données pour le chat
const difficultyData = SYSTEM.DIFFICULTY_CHOICES[options.selectedDifficulty || "moyenne"]
const isSousTensionOppose = options.selectedDifficulty === "soustension_oppose"
const isSuccess = isAutomaticSuccess || totalValue > options.targetScore
// Détecter si la carte est un valet
const isValet = selectedCard?.system.valeur === "valet"
// Détecter si la carte est un cavalier
const isCavalier = selectedCard?.system.valeur === "cavalier"
// Détecter si la carte est une reine
const isReine = selectedCard?.system.valeur === "reine"
// Détecter si la carte est un roi
const isRoi = selectedCard?.system.valeur === "roi"
// Détecter si la carte est un atout
const isAtout = selectedCard?.system.type === "atout"
// Si c'est un cavalier et un échec, transformer en égalité
const isEquality = isCavalier && !isSuccess && !isSousTensionOppose
const chatData = {
cssClass: [SYSTEM.id, "competence-roll"].join(" "),
actingCharImg: options.actorImage,
actingCharName: options.actorName,
actorName: options.actorName,
competence: options.rollItem,
competenceModifier: options.competenceModifier,
selectedCard: selectedCard,
cardBonus: options.selectedCardValue || 0,
cardSymboleMatch: cardSymboleMatch,
totalValue: totalValue,
difficulty: difficultyData.label,
targetScore: options.targetScore,
isSuccess: isSuccess,
isAutomaticSuccess: isAutomaticSuccess,
isSousTensionOppose: isSousTensionOppose,
isValet: isValet,
isCavalier: isCavalier,
isReine: isReine,
isRoi: isRoi,
isAtout: isAtout,
isEquality: isEquality,
}
// Créer le message de chat
const content = await foundry.applications.handlebars.renderTemplate(
"systems/fvtt-hamalron/templates/chat-competence.hbs",
chatData
)
const messageData = {
user: game.user.id,
speaker: ChatMessage.getSpeaker({ actor }),
content: content,
style: CONST.CHAT_MESSAGE_STYLES.OTHER,
}
// Appliquer le mode de visibilité
ChatMessage.applyRollMode(messageData, rollContext.visibility)
await ChatMessage.create(messageData)
// Gérer la carte utilisée
console.log("DEBUG: selectedCard =", selectedCard, "options.selectedCardId =", options.selectedCardId)
if (selectedCard) {
console.log("Managing used card:", selectedCard.name)
// Supprimer la carte de l'acteur
const cardItem = actor.items.get(selectedCard.id)
if (cardItem) {
await actor.deleteEmbeddedDocuments("Item", [selectedCard.id])
console.log("Card deleted from actor")
}
// Récupérer le deck manager singleton
const module = await import("../applications/tarot-deck-manager.mjs")
const HamalronTarotDeckManager = module.default
let deckManager = HamalronTarotDeckManager._instance
// Si le deck manager n'existe pas, le créer
if (!deckManager) {
console.log("Deck manager not initialized, creating new instance...")
deckManager = new HamalronTarotDeckManager()
await deckManager.resetDeck()
}
console.log("Deck manager instance:", deckManager)
if (deckManager) {
console.log("Deck manager is available")
// Ajouter la carte à la défausse
deckManager.addToDiscard({
id: selectedCard.id,
name: selectedCard.name,
img: selectedCard.img,
symbole: selectedCard.system.symbole,
valeur: selectedCard.system.valeur,
type: selectedCard.system.type,
description: selectedCard.system.description,
})
console.log("Card added to discard")
// Tirer une nouvelle carte automatiquement
console.log("Attempting to draw new card. Deck length:", deckManager.deck.length)
if (deckManager.deck.length > 0) {
const newCards = deckManager.drawCards(1)
console.log("Cards drawn:", newCards)
if (newCards.length > 0) {
const newCard = newCards[0]
console.log("New card to add:", newCard)
// Trouver l'item tarot dans game.items
let originalItem = game.items.get(newCard.id)
console.log("Original item found by ID:", originalItem)
// Si pas trouvé dans game.items, chercher dans tous les items disponibles
if (!originalItem) {
console.log("Searching for card in game.items by properties...")
originalItem = game.items.find(i =>
i.type === "tarot" &&
i.name === newCard.name &&
i.system.symbole === newCard.symbole &&
i.system.valeur === newCard.valeur
)
console.log("Original item found by search:", originalItem)
}
if (originalItem) {
// Cas spécial : Le Mat
if (newCard.valeur === "lemat") {
console.log("Le Mat drawn! Executing special rules...")
await HamalronTirageTarot.handleLeMatEffect(actor, deckManager)
} else {
console.log("Creating embedded document for actor...")
await actor.createEmbeddedDocuments("Item", [originalItem.toObject()])
console.log("New card added to actor")
ui.notifications.info(`${game.i18n.localize("HAMALRON.Notifications.newCardDrawn")}: ${newCard.name}`)
}
} else {
console.warn("Original item not found for card:", newCard)
}
} else {
console.log("No cards were drawn (empty result)")
}
} else {
console.log("Deck is empty, cannot draw new card")
}
deckManager.saveDeckState()
deckManager.render()
ui.notifications.info(`${game.i18n.localize("HAMALRON.Notifications.cardUsed")}: ${selectedCard.name}`)
}
}
return null
}
// Code existant pour les autres types de jets
let rollData = foundry.utils.mergeObject(foundry.utils.duplicate(options), rollContext)
rollData.rollMode = rollContext.visibility
rollData.targetScore = 8
@@ -203,6 +593,8 @@ export default class HamalronTirageTarot {
return `${game.i18n.localize("HAMALRON.Label.titleStat")}`
case "weapon":
return `${game.i18n.localize("HAMALRON.Label.titleWeapon")}`
case "competence":
return `${game.i18n.localize("HAMALRON.Label.titleCompetence")}`
default:
return game.i18n.localize("HAMALRON.Label.titleStandard")
}
+4 -2
View File
@@ -6,9 +6,11 @@ export default class HamalronCompetence extends foundry.abstract.TypeDataModel {
const schema = {};
schema.description = new fields.HTMLField({ required: true, textSearch: true })
schema.type = new fields.StringField({ required: true, initial: "generale", choices: Object.fromEntries(Object.entries(SYSTEM.COMPETENCE_TYPES).map(([key, val]) => [key, val.label])) });
schema.type = new fields.StringField({ required: true, initial: "commune", choices: Object.fromEntries(Object.entries(SYSTEM.COMPETENCE_TYPES).map(([key, val]) => [key, val.label])) });
schema.carteSymbole = new fields.StringField({ required: true, initial: "coupe", choices: Object.fromEntries(Object.entries(SYSTEM.TAROT_SYMBOLES).map(([key, val]) => [key, val.label])) });
schema.niveau = new fields.NumberField({ required: true, initial: 0, min: 0, integer: true });
schema.niveau = new fields.StringField({ required: true, initial: "inexperimente", choices: Object.fromEntries(Object.entries(SYSTEM.NIVEAU_COMPETENCES).map(([key, val]) => [key, val.name])) });
schema.faction = new fields.StringField({ required: false, initial: "" });
schema.peuple = new fields.StringField({ required: false, initial: "" });
return schema;
}
+10 -1
View File
@@ -128,6 +128,15 @@ export default class HamalronUtils {
Handlebars.registerHelper('add', function (a, b) {
return parseInt(a) + parseInt(b);
})
Handlebars.registerHelper('tarotValue', function (valeur) {
// Pour les valeurs numériques simples, retourner directement
const numValue = Number.parseInt(valeur);
if (!Number.isNaN(numValue)) return numValue;
// Pour les figures et atouts, récupérer depuis SYSTEM
const valeurData = SYSTEM.TAROT_VALEURS[valeur];
return valeurData ? valeurData.value : valeur;
});
Handlebars.registerHelper('mul', function (a, b) {
return parseInt(a) * parseInt(b);
@@ -169,7 +178,7 @@ export default class HamalronUtils {
return key === "creature" || key === "daemon";
})
Handlebars.registerHelper('getRomanLevel', function (level) {
if (level=== "highpowers") return "High";
if (level === "highpowers") return "High";
if (level === "mastery") return "Mastery";
level = parseInt(level);
if (level === 0) return "0";
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000002
MANIFEST-000016
+7 -5
View File
@@ -1,5 +1,7 @@
2025/12/25-21:02:35.693464 7f01589ff6c0 Delete type=3 #1
2025/12/25-23:05:15.035540 7f01427fc6c0 Level-0 table #5: started
2025/12/25-23:05:15.035618 7f01427fc6c0 Level-0 table #5: 0 bytes OK
2025/12/25-23:05:15.043074 7f01427fc6c0 Delete type=0 #3
2025/12/25-23:05:15.054249 7f01427fc6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)
2026/01/02-10:10:10.253712 7f93ebfff6c0 Recovering log #15
2026/01/02-10:10:10.307712 7f93ebfff6c0 Delete type=0 #15
2026/01/02-10:10:10.307764 7f93ebfff6c0 Delete type=3 #14
2026/01/02-20:13:00.317288 7f93e9ffb6c0 Level-0 table #19: started
2026/01/02-20:13:00.317383 7f93e9ffb6c0 Level-0 table #19: 0 bytes OK
2026/01/02-20:13:00.324182 7f93e9ffb6c0 Delete type=0 #17
2026/01/02-20:13:00.343771 7f93e9ffb6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)
+3
View File
@@ -0,0 +1,3 @@
2025/12/28-22:58:25.963740 7f4a83fff6c0 Recovering log #12
2025/12/28-22:58:25.975413 7f4a83fff6c0 Delete type=3 #10
2025/12/28-22:58:25.975552 7f4a83fff6c0 Delete type=0 #12
Binary file not shown.
Binary file not shown.
+692 -53
View File
@@ -1,87 +1,726 @@
&.ask-roll {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.1);
}
.fvtt-hamalron {
&.ask-roll {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.1);
}
.hamalron-tarot-draw {
padding: 0.5rem;
&.competence-roll {
background: #e8e8e8;
border: 2px solid #999;
border-radius: 0.5rem;
overflow: hidden;
.tarot-draw-header {
margin-bottom: 1rem;
.competence-roll-header {
background: rgba(255, 255, 255, 0.5);
padding: 0.5rem;
border-bottom: 2px solid #999;
.tarot-draw-title {
.actor-info-compact {
display: flex;
align-items: center;
gap: 0.5rem;
.actor-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid #667eea;
object-fit: cover;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.actor-details {
flex: 1;
.competence-name {
margin: 0 0 0.25rem 0;
font-size: 1rem;
color: #667eea;
font-weight: bold;
}
.competence-meta {
display: flex;
gap: 0.75rem;
font-size: 0.75rem;
color: var(--color-text-dark-secondary);
.meta-item {
display: flex;
align-items: center;
gap: 0.35rem;
i {
color: #667eea;
font-size: 0.75rem;
}
}
}
}
}
}
.competence-roll-body {
padding: 0.5rem;
.card-used-section {
background: rgba(102, 126, 234, 0.1);
border: 1px solid rgba(102, 126, 234, 0.4);
border-radius: 0.35rem;
padding: 0.4rem;
margin-bottom: 0.5rem;
.card-used-label {
display: flex;
align-items: center;
gap: 0.3rem;
font-size: 0.75rem;
font-weight: bold;
color: #4a5fc1;
margin-bottom: 0.35rem;
i {
font-size: 0.75rem;
}
}
.card-used-content {
display: flex;
align-items: center;
gap: 0.4rem;
.card-thumbnail {
width: 40px;
height: 40px;
border-radius: 0.25rem;
border: 1px solid rgba(102, 126, 234, 0.5);
object-fit: cover;
}
.card-info {
display: flex;
flex-direction: column;
gap: 0.25rem;
.card-name {
font-weight: bold;
color: var(--color-text-dark-primary);
}
.card-match {
display: flex;
align-items: center;
gap: 0.3rem;
font-size: 0.75rem;
font-style: italic;
&.match-success {
color: #2ecc71;
i {
color: #2ecc71;
}
}
&.match-partial {
color: #f39c12;
i {
color: #f39c12;
}
}
&.match-atout {
color: #9b59b6;
font-weight: bold;
i {
color: #9b59b6;
}
}
i {
font-size: 0.7rem;
}
}
// Styles pour les règles spéciales des cartes
.valet-special-rule,
.cavalier-special-rule,
.reine-special-rule,
.roi-special-rule {
display: flex;
align-items: center;
gap: 0.3rem;
font-size: 0.75rem;
font-weight: bold;
padding: 0.3rem 0.4rem;
border-radius: 0.25rem;
background: rgba(255, 193, 7, 0.15);
border-left: 3px solid #ffc107;
color: #856404;
margin-top: 0.2rem;
i {
font-size: 0.8rem;
color: #ffc107;
}
}
}
}
}
.calculation-section {
background: rgba(0, 0, 0, 0.05);
border-radius: 0.35rem;
padding: 0.4rem;
margin-bottom: 0.5rem;
.calculation-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.2rem 0;
font-size: 0.8rem;
.calc-label {
color: var(--color-text-dark-secondary);
}
.calc-value {
font-weight: bold;
font-size: 0.9rem;
color: var(--color-text-dark-primary);
&.calc-bonus {
color: #2ecc71;
}
&.calc-total {
font-size: 1.1rem;
color: #667eea;
}
}
&.total-row {
padding-top: 0.3rem;
}
}
.calculation-divider {
height: 1px;
background: var(--color-border-dark);
margin: 0.4rem 0;
}
}
.difficulty-section {
.difficulty-info {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.4rem;
background: rgba(0, 0, 0, 0.05);
border-radius: 0.35rem;
font-size: 0.8rem;
i {
color: #f39c12;
}
.difficulty-label {
color: var(--color-text-dark-primary);
font-weight: 500;
}
.difficulty-target {
margin-left: auto;
color: var(--color-text-dark-secondary);
strong {
color: var(--color-text-dark-primary);
font-size: 1rem;
}
}
}
}
}
.competence-roll-footer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin: 0;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--color-border-dark);
font-size: 1.25rem;
color: var(--color-text-dark-primary);
padding: 0.5rem;
font-size: 1.1rem;
font-weight: bold;
border-top: 2px solid #999;
i {
color: #667eea;
.automatic-success-banner {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
width: 100%;
padding: 0.5rem;
background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
color: #8b6914;
font-size: 0.95rem;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.1em;
border-radius: 0.25rem;
box-shadow: 0 2px 8px rgba(255, 215, 0, 0.4);
animation: pulse-banner 2s ease-in-out infinite;
i {
color: #8b6914;
text-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
}
}
&.result-success {
background: rgba(46, 204, 113, 0.2);
color: #2ecc71;
.result-icon i {
color: #2ecc71;
}
}
&.result-failure {
background: rgba(234, 102, 102, 0.2);
color: #ea6666;
.result-icon i {
color: #ea6666;
}
}
&.gm-only-buttons {
background: rgba(102, 126, 234, 0.1);
padding: 0.75rem;
.special-rules-section {
background: rgba(255, 193, 7, 0.15);
border: 2px solid #ffc107;
border-radius: 0.35rem;
padding: 0.5rem;
margin-bottom: 0.75rem;
.special-rule-item {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.3rem 0;
font-weight: bold;
color: #856404;
&:not(:last-child) {
border-bottom: 1px solid rgba(255, 193, 7, 0.3);
margin-bottom: 0.3rem;
padding-bottom: 0.4rem;
}
i {
font-size: 0.9rem;
color: #ffc107;
}
strong {
color: #6c5400;
}
}
}
.gm-buttons {
display: flex;
gap: 0.75rem;
width: 100%;
button {
flex: 1;
padding: 0.5rem 1rem;
border: 2px solid #667eea;
border-radius: 0.35rem;
background: white;
color: #667eea;
font-weight: bold;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
i {
font-size: 0.85rem;
}
&:hover {
background: #667eea;
color: white;
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
&.sous-tension-btn {
border-color: #f39c12;
color: #f39c12;
&:hover {
background: #f39c12;
color: white;
}
}
&.oppose-btn {
border-color: #e74c3c;
color: #e74c3c;
&:hover {
background: #e74c3c;
color: white;
}
}
}
}
}
.result-icon {
font-size: 1.2rem;
}
.result-text {
text-transform: uppercase;
letter-spacing: 0.05em;
}
}
}
.tarot-draw-content {
display: flex;
gap: 1rem;
&.hamalron-tarot-draw {
padding: 0.5rem;
.tarot-card-image {
flex-shrink: 0;
.tarot-draw-header {
margin-bottom: 1rem;
img {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 0.25rem;
border: 2px solid var(--color-border-dark);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
.tarot-draw-title {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 0;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--color-border-dark);
font-size: 1.25rem;
color: var(--color-text-dark-primary);
i {
color: #667eea;
}
}
}
.tarot-card-details {
flex: 1;
.tarot-draw-content {
display: flex;
flex-direction: column;
gap: 0.5rem;
gap: 1rem;
.tarot-detail-row {
display: flex;
gap: 0.5rem;
.tarot-card-image {
flex-shrink: 0;
.detail-label {
font-weight: bold;
color: var(--color-text-dark-secondary);
}
.detail-value {
color: var(--color-text-dark-primary);
img {
width: 150px;
height: 150px;
object-fit: cover;
border-radius: 0.25rem;
border: 2px solid var(--color-border-dark);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
}
.tarot-description {
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--color-border-dark);
.tarot-card-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
.tarot-detail-row {
display: flex;
gap: 0.5rem;
.detail-label {
font-weight: bold;
color: var(--color-text-dark-secondary);
}
.detail-value {
color: var(--color-text-dark-primary);
}
}
.tarot-description {
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--color-border-dark);
.description-label {
font-weight: bold;
color: var(--color-text-dark-secondary);
margin-bottom: 0.25rem;
}
.description-content {
color: var(--color-text-dark-primary);
font-style: italic;
}
}
}
}
}
&.tarot-draw-chat {
background: #e8e8e8;
border: 2px solid #999;
border-radius: 0.5rem;
overflow: hidden;
.tarot-draw-header {
background: rgba(255, 255, 255, 0.5);
padding: 0.5rem;
border-bottom: 2px solid #999;
.draw-info-compact {
display: flex;
align-items: center;
gap: 0.5rem;
.card-thumbnail {
width: 60px;
height: 60px;
border-radius: 0.25rem;
object-fit: cover;
border: 2px solid #999;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
.card-details {
flex: 1;
.card-name {
margin: 0 0 0.25rem 0;
font-size: 1rem;
font-weight: bold;
color: #333;
}
.card-meta {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
font-size: 0.75rem;
.meta-item {
display: flex;
align-items: center;
gap: 0.25rem;
color: #666;
i {
color: #999;
}
}
}
}
}
}
.tarot-draw-body {
padding: 0.5rem;
.description-section {
.description-label {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.8rem;
font-weight: bold;
color: var(--color-text-dark-secondary);
margin-bottom: 0.25rem;
color: #666;
margin-bottom: 0.4rem;
i {
color: #999;
}
}
.description-content {
color: var(--color-text-dark-primary);
font-size: 0.85rem;
color: #555;
font-style: italic;
line-height: 1.4;
padding: 0.4rem;
background: rgba(255, 255, 255, 0.3);
border-radius: 0.25rem;
border-left: 3px solid #999;
}
}
}
}
&.tarot-tension-chat {
background: #e8e8e8;
border: 2px solid #999;
border-radius: 0.5rem;
overflow: hidden;
.tarot-tension-header {
background: rgba(255, 165, 0, 0.2);
padding: 0.5rem;
border-bottom: 2px solid #f39c12;
.tension-info-compact {
display: flex;
align-items: center;
gap: 0.5rem;
.card-thumbnail {
width: 60px;
height: 60px;
border-radius: 0.25rem;
object-fit: cover;
border: 2px solid #f39c12;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
.card-details {
flex: 1;
.card-name {
margin: 0 0 0.25rem 0;
font-size: 1rem;
font-weight: bold;
color: #333;
}
.card-meta {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
font-size: 0.75rem;
.meta-item {
display: flex;
align-items: center;
gap: 0.25rem;
color: #666;
i {
color: #f39c12;
}
}
}
}
}
}
.tarot-tension-body {
padding: 0.5rem;
.difficulty-section {
margin-bottom: 0.75rem;
padding: 0.5rem;
background: rgba(243, 156, 18, 0.1);
border-left: 3px solid #f39c12;
border-radius: 0.25rem;
.difficulty-label {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.75rem;
font-weight: bold;
color: #666;
margin-bottom: 0.25rem;
i {
color: #f39c12;
}
}
.difficulty-value {
font-size: 0.9rem;
font-weight: bold;
color: #333;
}
}
.calculation-section {
.calculation-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.3rem 0.5rem;
margin-bottom: 0.25rem;
background: rgba(255, 255, 255, 0.3);
border-radius: 0.25rem;
.calc-label {
font-size: 0.8rem;
color: #666;
}
.calc-value {
font-size: 0.85rem;
font-weight: bold;
color: #333;
&.positive {
color: #27ae60;
}
&.negative {
color: #e74c3c;
}
}
}
.calculation-total {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem;
margin-top: 0.5rem;
background: rgba(243, 156, 18, 0.15);
border: 2px solid #f39c12;
border-radius: 0.25rem;
.total-label {
font-size: 0.85rem;
font-weight: bold;
color: #666;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.total-value {
font-size: 1.25rem;
font-weight: bold;
color: #f39c12;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
}
}
}
}
}
@keyframes pulse-banner {
0%,
100% {
box-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
}
50% {
box-shadow: 0 0 20px rgba(255, 215, 0, 0.8);
}
}
+4 -4
View File
@@ -1,9 +1,9 @@
@font-face {
font-family: "MinionProRegular";
src: url("../assets/fonts/Minion Pro Regular.ttf") format("truetype");
font-family: "TimesNewRoman";
src: url("../assets/fonts/Times New Roman.ttf") format("truetype");
}
@font-face {
font-family: "SupernaturalKnight";
src: url("../assets/fonts/Supernatural_Knight.ttf") format("truetype");
font-family: "EagleLake";
src: url("../assets/fonts/EagleLake-Regular.ttf") format("truetype");
}
+2 -2
View File
@@ -16,8 +16,8 @@
@import "region.less";
@import "sortilege.less";
@import "tarot.less";
@import "tarot-deck-manager.less";
@import "chat.less";
}
@import "chat.less";
@import "roll.less";
@import "tarot-deck-manager.less";
+7 -4
View File
@@ -2,22 +2,25 @@
--font-size-standard: 0.9rem;
--font-size-result: 1.4rem;
--background-image-base: url("../assets/ui/sheet_background_01.webp");
--font-primary: "MinionProRegular";
--font-secondary: "MinionProRegular";
--font-title: "SupernaturalKnight";
--font-primary: "TimesNewRoman";
--font-secondary: "TimesNewRoman";
--font-title: "EagleLake";
--logo-standard: url("../assets/ui/pentagram_logo.webp");
--title-color: #c9a876;
--title-color: #dea60b;
--background-box: #e0dcdc;
--color-success: rgb(15, 122, 15);
--color-failure: #8b7355;
--color-warning: darkorange;
--color-critical-success: rgb(21, 39, 204);
--color-critical-failure: rgb(141, 32, 231);
--color-sheet-nav: #120c04;
--input-height: 1.2rem;
}
body {
--color-light-1: rgba(182, 178, 178, 0.6);
--color-warm-1: #c9a876;
--input-height: 1.4rem;
}
#logo {
+2 -2
View File
@@ -48,8 +48,8 @@
}
legend {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.2);
font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.1);
font-weight: bold;
letter-spacing: 1px;
}
+221 -90
View File
@@ -1,6 +1,6 @@
.personnage {
.character-content {
.tarot-hand-container {
padding: 1rem;
padding: 0.3rem;
height: 100%;
display: flex;
flex-direction: column;
@@ -9,8 +9,8 @@
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
padding-bottom: 0.75rem;
margin-bottom: 0.2rem;
padding-bottom: 0.2rem;
border-bottom: 2px solid var(--color-border-dark);
h2 {
@@ -20,47 +20,135 @@
}
.tarot-hand-info {
display: flex;
align-items: center;
gap: 1rem;
.card-count {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
gap: 0.3rem;
padding: 0.3rem 0.6rem;
background: rgba(102, 126, 234, 0.2);
border-radius: 0.25rem;
border: 1px solid rgba(102, 126, 234, 0.4);
font-weight: bold;
font-size: 0.85rem;
color: var(--color-text-light-heading);
i {
color: #667eea;
}
&.over-limit {
background: rgba(234, 102, 102, 0.2);
border-color: rgba(234, 102, 102, 0.4);
i {
color: #ea6666;
}
}
}
.hand-warning {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background: rgba(234, 179, 8, 0.2);
border-radius: 0.25rem;
border: 1px solid rgba(234, 179, 8, 0.4);
color: #eab308;
font-weight: bold;
animation: pulse 2s ease-in-out infinite;
i {
color: #eab308;
}
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.7;
}
}
}
}
.tarot-hand-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1.5rem;
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
overflow-y: auto;
padding-right: 0.5rem;
padding: 0.2rem;
justify-content: center;
align-items: flex-start;
.tarot-card-wrapper {
perspective: 1000px;
cursor: grab;
flex-shrink: 0;
position: relative;
&:active {
cursor: grabbing;
}
&.success-card {
.tarot-card {
.tarot-card-inner {
.tarot-card-front {
border: 3px solid #ffd700;
box-shadow:
0 0 15px rgba(255, 215, 0, 0.6),
0 4px 8px rgba(0, 0, 0, 0.3);
}
}
}
.tarot-card-controls {
.success-indicator {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
border-radius: 50%;
background: rgba(255, 215, 0, 0.9);
color: #8b6914;
animation: pulse-gold 2s ease-in-out infinite;
i {
font-size: 0.7rem;
}
}
}
}
&.selected {
.tarot-card {
border: 2px solid #667eea;
box-shadow: 0 0 20px rgba(102, 126, 234, 0.6);
}
.card-actions {
display: flex !important;
}
}
.tarot-card {
position: relative;
width: 100%;
height: 400px;
width: 110px;
height: 190px;
transition: transform 0.3s ease;
&:hover {
transform: translateY(-5px);
transform: translateY(-10px) scale(1.05);
z-index: 10;
}
.tarot-card-inner {
@@ -83,57 +171,55 @@
border-radius: 0.5rem;
display: flex;
flex-direction: column;
padding: 0.75rem;
padding: 0.4rem;
.tarot-card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 0.75rem;
.tarot-card-name {
margin: 0;
font-size: 1.1rem;
font-weight: bold;
color: #667eea;
flex: 1;
line-height: 1.3;
}
position: absolute;
top: 0.25rem;
right: 0.25rem;
z-index: 2;
.tarot-card-controls {
display: flex;
gap: 0.25rem;
opacity: 0;
transition: opacity 0.2s ease;
.card-control {
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border-radius: 0.25rem;
background: rgba(0, 0, 0, 0.3);
color: var(--color-text-light-heading);
width: 20px;
height: 20px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.7);
color: white;
transition: all 0.2s ease;
&:hover {
background: rgba(102, 126, 234, 0.5);
color: white;
&.delete-control:hover {
background: rgba(234, 102, 102, 0.9);
}
&.view-control:hover {
background: rgba(102, 126, 234, 0.9);
}
i {
font-size: 0.75rem;
font-size: 0.7rem;
}
}
}
}
&:hover .tarot-card-header .tarot-card-controls {
opacity: 1;
}
.tarot-card-image {
width: 100%;
height: 150px;
margin-bottom: 0.75rem;
border-radius: 0.25rem;
height: 125px;
border-radius: 0.25rem 0.25rem 0 0;
overflow: hidden;
border: 1px solid var(--color-border-dark);
background: rgba(0, 0, 0, 0.3);
img {
@@ -143,37 +229,44 @@
}
}
.tarot-card-name {
padding: 0.5rem;
background: rgba(0, 0, 0, 0.3);
border-bottom: 1px solid var(--color-border-dark);
h4 {
margin: 0;
font-size: 0.85rem;
font-weight: bold;
color: #667eea;
text-align: center;
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.tarot-card-info {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 0.75rem;
padding: 0.5rem;
background: rgba(0, 0, 0, 0.2);
.card-info-row {
.card-info-compact {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.4rem 0.5rem;
background: rgba(0, 0, 0, 0.2);
border-radius: 0.25rem;
font-size: 0.875rem;
flex-direction: column;
gap: 0.4rem;
font-size: 0.75rem;
.info-label {
.card-symbole {
display: flex;
align-items: center;
gap: 0.35rem;
color: var(--color-text-dark-secondary);
font-weight: 500;
gap: 0.3rem;
font-weight: bold;
justify-content: center;
i {
font-size: 0.75rem;
opacity: 0.7;
font-size: 0.6rem;
}
}
.info-value {
color: var(--color-text-light-heading);
font-weight: bold;
&.symbole-coupe {
color: #3498db;
@@ -191,46 +284,84 @@
color: #2ecc71;
}
}
.card-valeur {
text-align: center;
color: #ffffff;
font-weight: bold;
font-size: 1rem;
background: rgba(0, 0, 0, 0.4);
padding: 0.3rem 0.5rem;
border-radius: 0.25rem;
}
}
}
.tarot-card-description {
flex: 1;
overflow-y: auto;
padding: 0.5rem;
background: rgba(0, 0, 0, 0.2);
border-radius: 0.25rem;
border: 1px solid var(--color-border-dark);
.card-actions {
display: none;
margin-top: 0.5rem;
.description-text {
font-size: 0.8rem;
line-height: 1.4;
color: var(--color-text-dark-primary);
.discard-and-draw-button {
width: 100%;
padding: 0.5rem;
background: rgba(102, 126, 234, 0.3);
border: 1px solid rgba(102, 126, 234, 0.6);
border-radius: 0.25rem;
color: #9ab4ff;
font-size: 0.75rem;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 0.3rem;
p {
margin: 0 0 0.5rem 0;
i {
font-size: 0.7rem;
}
&:last-child {
margin-bottom: 0;
&:hover {
background: rgba(102, 126, 234, 0.5);
border-color: rgba(102, 126, 234, 0.8);
color: #aac4ff;
transform: translateY(-1px);
}
&:active {
transform: translateY(0);
}
}
}
&::-webkit-scrollbar {
width: 4px;
}
.discard-button {
margin-top: 0.5rem;
padding: 0.4rem 0.5rem;
background: rgba(234, 102, 102, 0.3);
border: 1px solid rgba(234, 102, 102, 0.6);
border-radius: 0.25rem;
color: #ea6666;
font-size: 0.7rem;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 0.3rem;
&::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.2);
border-radius: 2px;
}
&::-webkit-scrollbar-thumb {
background: rgba(102, 126, 234, 0.5);
border-radius: 2px;
i {
font-size: 0.65rem;
}
&:hover {
background: rgba(102, 126, 234, 0.7);
background: rgba(234, 102, 102, 0.5);
border-color: rgba(234, 102, 102, 0.8);
color: #ff6666;
transform: translateY(-1px);
}
&:active {
transform: translateY(0);
}
}
}
+290 -116
View File
@@ -6,11 +6,17 @@
.sheet-tabs {
background-color: var(--color-light-1);
font-family: var(--font-title);
a {
color: var(--color-sheet-nav);
font-size: 0.9rem;
}
}
.character-main {
/*background-color: var(--color-light-1);*/
display: flex;
justify-content: center;
.character-pc {
display: flex;
@@ -18,7 +24,7 @@
flex: 1;
.character-left {
min-width: 180px;
min-width: 220px;
display: flex;
flex-direction: column;
@@ -62,15 +68,9 @@
.character-right {
display: flex;
flex-direction: column;
gap: 5px;
gap: 2px;
.character-definition {
.character-definition-pronouns {
input {
min-width: 21.2rem;
max-width: 21.2rem;
}
}
.form-group {
display: flex;
align-items: center;
@@ -97,6 +97,32 @@
margin-right: 1rem;
margin-bottom: auto;
}
.item-controls {
display: flex;
align-items: center;
gap: 0.5rem;
flex: 1;
.item-name {
flex: 1;
min-width: 0;
}
.control {
flex-shrink: 0;
cursor: pointer;
opacity: 0.7;
transition: opacity 0.2s;
&:hover {
opacity: 1;
}
i {
font-size: 0.9rem;
}
}
}
}
.character-name {
display: flex;
@@ -113,40 +139,146 @@
}
.character-pc-play {
min-width: 500px;
min-width: 660px;
}
.character-pc-edit {
min-width: 500px;
min-width: 660px;
}
.character-stats {
/*background-color: var(--color-light-1);*/
display: flex;
flex-direction: column;
gap: 5px;
gap: 2px;
flex: 1;
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.2rem;
}
.character-stat {
display: flex;
align-items: center;
.icon-stat {
width: 24px;
height: 24px;
margin-right: 4px;
justify-content: space-between;
gap: 0.2rem;
padding: 0.1rem 0.2rem;
background: rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
.stat-label {
flex: 1;
min-width: 0;
&.rollable:hover,
&.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
i {
margin-right: 0.25rem;
}
}
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
.stat-values {
display: flex;
align-items: center;
gap: 0.25rem;
flex-shrink: 0;
input {
width: 3rem;
text-align: center;
}
.stat-value {
width: 3rem;
text-align: center;
display: inline-block;
}
.separator {
font-weight: bold;
color: var(--color-text-dark-secondary);
}
}
.rollable {
min-width: 3.5rem;
max-width: 3.5rem;
}
}
.character-resistances {
display: flex;
flex-direction: column;
gap: 2px;
flex: 1;
.resistances-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.2rem;
}
.resistance-stat {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.2rem;
padding: 0.1rem 0.2rem;
background: rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
.stat-label {
flex: 1;
min-width: 0;
}
input {
min-width: 2.5rem;
max-width: 2.5rem;
.stat-values {
display: flex;
align-items: center;
gap: 0.2rem;
flex-shrink: 0;
input {
width: 3rem;
text-align: center;
}
.stat-value {
width: 3rem;
text-align: center;
display: inline-block;
}
.resistance-control {
cursor: pointer;
opacity: 0.8;
transition: all 0.2s ease;
padding: 0.15rem 0.35rem;
background: rgba(0, 0, 0, 0.1);
border-radius: 3px;
color: var(--color-text-dark-primary);
&:hover {
opacity: 1;
background: rgba(0, 100, 200, 0.2);
transform: scale(1.1);
}
&:active {
transform: scale(0.95);
}
i {
font-size: 0.7rem;
}
}
.separator {
font-weight: bold;
color: var(--color-text-dark-secondary);
}
}
}
}
@@ -160,16 +292,145 @@
}
}
.tab.character-status .main-div {
.tab.character-competences .main-div {
/*background-color: var(--color-light-1);*/
display: grid;
grid-template-columns: 1fr;
gap: 8px;
legend {
a {
font-size: calc(var(--font-size-standard) * 1.4);
padding-left: 5px;
}
}
.competences-group {
margin-bottom: 12px;
background: rgba(0, 0, 0, 0.03);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 4px;
padding: 8px;
.competences-type-header {
font-weight: bold;
font-size: calc(var(--font-size-standard) * 1.1);
color: var(--color-text-dark-primary);
margin-bottom: 8px;
padding: 4px 8px;
border-left: 3px solid var(--color-border-dark-primary);
}
}
.competences {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 6px;
.competence {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 6px;
background: rgba(255, 255, 255, 0.6);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 3px;
transition: all 0.2s ease;
&:hover {
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.item-img {
width: 28px;
height: 28px;
border-radius: 3px;
flex-shrink: 0;
}
.name {
flex: 1;
min-width: 0;
font-weight: 500;
a {
color: var(--color-text-dark-primary);
text-decoration: none;
cursor: pointer;
&:hover {
color: var(--color-text-hyperlink);
text-decoration: underline;
}
}
}
.carte {
font-size: 0.85rem;
padding: 2px 6px;
background: rgba(0, 0, 0, 0.08);
border-radius: 3px;
white-space: nowrap;
}
.niveau {
font-size: 0.85rem;
padding: 2px 6px;
background: rgba(0, 100, 200, 0.1);
color: var(--color-text-dark-primary);
border-radius: 3px;
white-space: nowrap;
font-weight: 500;
}
.controls {
display: flex;
gap: 4px;
font-size: 0.85rem;
flex-shrink: 0;
a {
padding: 2px 4px;
color: var(--color-text-dark-secondary);
cursor: pointer;
transition: color 0.2s ease;
&:hover {
color: var(--color-text-dark-primary);
}
}
}
}
}
.add-competence-section {
text-align: center;
padding: 12px;
.add-competence-button {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: rgba(0, 100, 200, 0.1);
border: 1px solid rgba(0, 100, 200, 0.3);
border-radius: 4px;
color: var(--color-text-dark-primary);
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background: rgba(0, 100, 200, 0.2);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
i {
font-size: 1rem;
}
}
}
.mortality {
display: flex;
align-items: center;
@@ -227,53 +488,9 @@
}
}
}
.perks {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 4px;
.perk {
display: flex;
align-items: center;
gap: 4px;
margin-left: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.flavor {
min-width: 24rem;
max-width: 24rem;
}
.role {
min-width: 5rem;
max-width: 5rem;
}
.level {
min-width: 4rem;
max-width: 4rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
}
.tab.character-maleficas .main-div {
.tab.character-sortileges .main-div {
/*background-color: var(--color-light-1);*/
display: grid;
grid-template-columns: 1fr;
@@ -284,7 +501,7 @@
}
}
.maleficas {
.sortileges {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
@@ -322,49 +539,6 @@
}
}
}
.rituals {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 4px;
.ritual {
display: flex;
align-items: center;
gap: 4px;
min-width: 14rem;
max-width: 14rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.ingredients {
min-width: 24rem;
max-width: 24rem;
}
.name {
min-width: 12rem;
max-width: 12rem;
}
.difficulty {
min-width: 2rem;
max-width: 2rem;
}
.threshold {
min-width: 2rem;
max-width: 2rem;
}
.limit {
min-width: 2rem;
max-width: 2rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
}
.tab.character-equipment .main-div {
+223 -1
View File
@@ -19,9 +19,219 @@
.fvtt-hamalron-roll-dialog {
fieldset {
padding: 10px;
padding: 6px;
background-color: var(--color-light-1);
}
.dialog-info {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 0;
.actor-info {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.5rem;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 0.25rem;
.actor-portrait {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid var(--color-dark-6);
object-fit: cover;
}
.actor-name {
font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 0.9);
font-weight: bold;
color: var(--color-dark-1);
}
}
.competence-info {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.25rem 0.5rem;
h3 {
margin: 0;
font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1);
color: var(--title-color);
white-space: nowrap;
}
.competence-details {
display: flex;
gap: 0.5rem;
font-size: calc(var(--font-size-standard) * 0.85);
.competence-symbole,
.competence-niveau {
padding: 0.25rem 0.5rem;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 0.25rem;
font-weight: 500;
}
}
}
}
.tarot-hand {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
gap: 0.5rem;
padding: 0.25rem;
min-height: 90px;
.tarot-card-select {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.15rem;
padding: 0.25rem;
border: 2px solid transparent;
border-radius: 0.35rem;
background-color: rgba(0, 0, 0, 0.05);
cursor: pointer;
transition: all 0.2s ease;
position: relative;
&:hover {
background-color: rgba(0, 0, 0, 0.1);
border-color: var(--color-dark-5);
transform: translateY(-2px) scale(1.3);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
z-index: 10;
}
&.selected {
background-color: rgba(100, 150, 255, 0.2);
border-color: var(--color-success);
box-shadow: 0 0 10px rgba(100, 150, 255, 0.5);
}
&.success-card {
border: 3px solid #ffd700;
background: linear-gradient(
135deg,
rgba(255, 215, 0, 0.1) 0%,
rgba(255, 223, 0, 0.2) 100%
);
box-shadow: 0 0 15px rgba(255, 215, 0, 0.4);
&:hover {
border-color: #ffed4e;
box-shadow: 0 6px 20px rgba(255, 215, 0, 0.6);
}
&.selected {
border-color: #ffd700;
box-shadow: 0 0 20px rgba(255, 215, 0, 0.8);
}
}
.success-indicator {
position: absolute;
top: 2px;
right: 2px;
color: #ffd700;
font-size: 1rem;
text-shadow: 0 0 5px rgba(255, 215, 0, 0.8);
animation: pulse-gold 2s ease-in-out infinite;
}
img {
width: 50px;
height: auto;
border-radius: 0.25rem;
border: 1px solid var(--color-dark-6);
}
.card-name {
font-size: calc(var(--font-size-standard) * 0.75);
text-align: center;
line-height: 1.1;
max-width: 70px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.card-values {
font-size: calc(var(--font-size-standard) * 0.7);
text-align: center;
color: var(--color-dark-3);
font-weight: bold;
margin-top: 0.1rem;
}
}
p {
grid-column: 1 / -1;
text-align: center;
color: var(--color-dark-5);
font-style: italic;
margin: 1rem 0;
}
}
.dialog-result {
.total-display {
display: flex;
justify-content: center;
align-items: center;
gap: 0.1rem;
padding: 0.1rem;
font-family: var(--font-title);
font-size: calc(var(--font-size-standard) * 1.1);
font-weight: bold;
#competence-modifier {
color: var(--color-dark-1);
}
#card-value-display {
color: var(--color-success);
}
#total-value {
padding: 0.1rem 0.2rem;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 0.35rem;
color: var(--title-color);
min-width: 2.1rem;
text-align: center;
}
}
.difficulty-info {
text-align: center;
font-size: calc(var(--font-size-standard) * 0.9);
color: var(--color-dark-2);
margin-top: 0.1rem;
padding: 0.1rem 0;
#target-score {
font-weight: bold;
color: var(--color-dark-1);
}
}
}
.difficulty-select {
width: 100%;
text-align: center;
padding: 0.25rem;
}
}
.dialog-modifier {
@@ -216,3 +426,15 @@
text-shadow: 0 0 10px var(--color-shadow-primary);
}
}
@keyframes pulse-gold {
0%,
100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.8;
}
}
+105 -42
View File
@@ -1,111 +1,174 @@
.tarot-deck-manager {
.tarot-deck-manager-content {
padding: 1rem;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1.5rem;
background: linear-gradient(
135deg,
rgba(102, 126, 234, 0.05) 0%,
rgba(118, 75, 162, 0.05) 100%
);
min-height: 100%;
}
.deck-header {
h2 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
color: var(--color-text-dark-primary);
margin: 0 0 0.75rem 0;
font-size: 1.25rem;
color: #667eea;
text-align: center;
border-bottom: 2px solid var(--color-border-dark);
border-bottom: 2px solid #667eea;
padding-bottom: 0.5rem;
text-transform: uppercase;
letter-spacing: 0.1em;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.deck-stats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-top: 1rem;
gap: 0.5rem;
margin-top: 0.75rem;
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.25rem;
padding: 0.75rem;
background: rgba(0, 0, 0, 0.2);
border-radius: 0.25rem;
border: 1px solid var(--color-border-dark);
padding: 0.5rem;
background: linear-gradient(
135deg,
rgba(102, 126, 234, 0.15) 0%,
rgba(118, 75, 162, 0.15) 100%
);
border-radius: 0.5rem;
border: 2px solid rgba(102, 126, 234, 0.3);
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
&:hover {
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
border-color: rgba(102, 126, 234, 0.5);
}
i {
font-size: 1.5rem;
color: var(--color-text-light-heading);
margin-bottom: 0.25rem;
font-size: 1.25rem;
color: #667eea;
margin-bottom: 0.15rem;
}
.stat-label {
font-size: 0.75rem;
font-size: 0.7rem;
color: var(--color-text-dark-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
text-align: center;
}
.stat-value {
font-size: 1.25rem;
font-weight: bold;
color: var(--color-text-light-heading);
color: #667eea;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
}
}
}
.deck-actions {
display: flex;
flex-direction: column;
gap: 1rem;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
.action-button {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
font-size: 1rem;
padding: 0.6rem 0.75rem;
font-size: 0.85rem;
font-weight: bold;
border: none;
border-radius: 0.25rem;
border-radius: 0.5rem;
cursor: pointer;
transition: all 0.2s ease;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
text-transform: uppercase;
letter-spacing: 0.05em;
i {
font-size: 1.25rem;
font-size: 1.1rem;
}
&:hover:not(:disabled) {
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}
&:active:not(:disabled) {
transform: translateY(-1px);
}
&:disabled {
opacity: 0.5;
opacity: 0.4;
cursor: not-allowed;
filter: grayscale(50%);
}
}
.reset-button {
background: var(--color-border-dark);
color: var(--color-text-light-heading);
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
color: white;
&:hover:not(:disabled) {
background: var(--color-border-dark-tertiary);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
background: linear-gradient(135deg, #c0392b 0%, #e74c3c 100%);
}
}
.draw-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
.collect-hands-button {
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
color: white;
.draw-button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
&:hover:not(:disabled) {
background: linear-gradient(135deg, #2980b9 0%, #3498db 100%);
}
}
&:hover:not(:disabled) {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(102, 126, 234, 0.4);
}
.distribute-cards-button {
background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
color: white;
&:hover:not(:disabled) {
background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%);
}
}
.shuffle-discard-button {
background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%);
color: white;
&:hover:not(:disabled) {
background: linear-gradient(135deg, #e67e22 0%, #f39c12 100%);
}
}
.draw-button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
&:hover:not(:disabled) {
background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
}
}
.draw-tension-button {
background: linear-gradient(135deg, #f39c12 0%, #d35400 100%);
color: white;
&:hover:not(:disabled) {
background: linear-gradient(135deg, #d35400 0%, #f39c12 100%);
}
}
}
-154
View File
@@ -1,154 +0,0 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset class="biodata">
<legend>{{localize "HAMALRON.Label.experience"}}</legend>
<div class="experience">
{{formField systemFields.experience.fields.current value=system.experience.current type="number" rootId=partId
disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.experience.fields.total value=system.experience.total type="number" rootId=partId
disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.experience.fields.training value=system.experience.training type="number" rootId=partId
disabled=isPlayMode}}
</div>
</fieldset>
<fieldset >
<legend>{{localize "HAMALRON.Label.biodata"}}</legend>
<div class="aliases">
{{formField systemFields.biodata.fields.aliases value=system.biodata.aliases rootId=partId disabled=isPlayMode}}
</div>
<div class="biodata">
<div class="experience">
{{formField systemFields.biodata.fields.gender value=system.biodata.gender rootId=partId disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.age value=system.biodata.age rootId=partId disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.height value=system.biodata.height rootId=partId disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.weight value=system.biodata.weight rootId=partId disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.eyes value=system.biodata.eyes rootId=partId disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.hair value=system.biodata.hair rootId=partId disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.home value=system.biodata.home rootId=partId disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.birthplace value=system.biodata.birthplace rootId=partId
disabled=isPlayMode}}
</div>
<div class="experience">
{{formField systemFields.biodata.fields.dod value=system.biodata.dod rootId=partId
disabled=isPlayMode}}
</div>
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.deals"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addDeals"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createDeal"></i></a>{{/if}}
</legend>
<div class="deals">
{{#each deals as |item|}}
<div class="deal" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.backstory"}}</legend>
{{formInput systemFields.backstory enriched=enrichedBackstory value=system.backstory name="system.backstory" toggled=true}}
</fieldset>
<div class="splitted-text">
<fieldset>
<legend>{{localize "HAMALRON.Label.appearance"}}</legend>
{{formInput systemFields.appearance enriched=enrichedAppearance value=system.appearance name="system.appearance"
toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.scars"}}</legend>
{{formInput systemFields.scars enriched=scars value=system.scars name="system.scars"
toggled=true}}
</fieldset>
</div>
<div class="splitted-text">
<fieldset>
<legend>{{localize "HAMALRON.Label.likes"}}</legend>
{{formInput systemFields.likes enriched=enrichedLikes value=system.likes name="system.likes"
toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.dislikes"}}</legend>
{{formInput systemFields.dislikes enriched=enrichedDislikes value=system.dislikes name="system.dislikes"
toggled=true}}
</fieldset>
</div>
<div class="splitted-text">
<fieldset>
<legend>{{localize "HAMALRON.Label.fears"}}</legend>
{{formInput systemFields.fears enriched=enrichedFears value=system.fears name="system.fears"
toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.vices"}}</legend>
{{formInput systemFields.vices enriched=enrichedVices value=system.vices name="system.vices"
toggled=true}}
</fieldset>
</div>
<div class="splitted-text">
<fieldset>
<legend>{{localize "HAMALRON.Label.goals"}}</legend>
{{formInput systemFields.goals enriched=enrichedGoals value=system.goals name="system.goals"
toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.ambitions"}}</legend>
{{formInput systemFields.ambitions enriched=enrichedAmbitions value=system.ambitions name="system.ambitions"
toggled=true}}
</fieldset>
</div>
<div class="splitted-text">
<fieldset>
<legend>{{localize "HAMALRON.Label.values"}}</legend>
{{formInput systemFields.values enriched=enrichedValues value=system.values name="system.values"
toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.bonds"}}</legend>
{{formInput systemFields.bonds enriched=enrichedBonds value=system.bonds name="system.bonds"
toggled=true}}
</fieldset>
</div>
</div>
</section>
-127
View File
@@ -1,127 +0,0 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "HAMALRON.Label.weapons"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createWeapon"></i></a>{{/if}}
</legend>
<div class="weapons">
{{#each weapons as |item|}}
<div class="weapon item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}} - {{upperFirst item.system.weaponType}}" />
<i class="fa-regular fa-dice"></i>
<div class="name rollable" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<!-- <span class="type" data-tooltip="Type">{{upperFirst item.system.weaponType}}</span> -->
<span class="properties" data-tooltip="Properties">{{upperFirst item.system.properties}}</span>
<span class="range" data-tooltip="Range">{{upperFirst item.system.range}}</span>
{{#if (eq item.system.weaponType "melee")}}
<span class="ammoQuantity" > </span>
<span class="ammo" ></span>
{{else}}
<span class="ammoQuantity" data-tooltip="ammoQuantity">
<i class="fa-solid fa-octagon-plus" data-action="modifyAmmo" data-quantity="1" data-item-id="{{item.id}}"></i>
{{item.system.ammoQuantity}}
<i class="fa-solid fa-octagon-minus" data-action="modifyAmmo" data-quantity="-1" data-item-id="{{item.id}}"></i>
</span>
<span class="ammo" data-tooltip="Ammo">{{upperFirst item.system.ammo}}</span>
{{/if}}
<a class="damage rollable" data-tooltip="Damage" data-item-id="{{item.id}}" data-action="roll"
data-roll-type="damage" data-roll-value="{{item.system.damageFormula}}">
<i class="fa-regular fa-dice"></i>
{{item.system.damageFormula}}</a>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.armors"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addArmor"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createArmor"></i></a>{{/if}}
</legend>
<div class="armors">
{{#each armors as |item|}}
<div class="armor item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<span class="bonus" data-tooltip="Bonus">{{item.system.bonus}}</span>
<span class="resilience" data-tooltip="Resilience">{{item.system.resilience}}</span>
<span class="reduction" data-tooltip="Reduction">{{item.system.reduction}}</span>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.equipments"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addEquipment"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createEquipment"></i></a>{{/if}}
</legend>
<div class="equipments">
{{#each equipments as |item|}}
{{!log 'armor' this}}
<div class="equipment" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<span class="quantity" data-tooltip="Quantity">{{item.system.quantity}}</span>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset class="limboes">
<legend>Limboes and Ammo</legend>
<div class="limboes-line">
<div class="ammo-item">
<input type="text" class="limboes-name" value="{{system.limboes}}" name="system.limboes"/>
<span class="limboes-quantity">Limboes</span>
</div>
<div class="ammo-item">
<input type="text" class="ammo" value="{{system.ammo}}" name="system.ammo"/>
<span class="limboes-quantity">Ammo</span>
</div>
{{#each system.ammoArray as |ammo key|}}
<div class="ammo-item">
<input type="text" class="ammo-quantity" value="{{ammo.value}}" min="0" name="system.ammoArray.{{key}}.value" />
<span class="ammo-name">{{upperFirst ammo.label}}</span>
</div>
{{/each}}
</div>
</fieldset>
</div>
</section>
-106
View File
@@ -1,106 +0,0 @@
<section class="character-main character-main-{{ifThen isPlayMode 'play' 'edit'}}">
{{!log "character-main" this}}
<fieldset>
<legend>{{localize "HAMALRON.Label.character"}}</legend>
<div class="character-pc character-pc-{{ifThen isPlayMode 'play' 'edit'}}">
<div class="character-left">
<div class="character-left-image">
<img class="character-img" src="{{actor.img}}" data-edit="img" data-action="editImage"
data-tooltip="{{actor.name}}" />
</div>
</div>
<div class="character-right">
<div class="character-name">
{{formInput fields.name value=source.name rootId=partId disabled=isPlayMode}}
<a class="control" data-action="toggleSheet" data-tooltip="HAMALRON.ToggleSheet" data-tooltip-direction="UP">
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
</a>
</div>
<fieldset class="character-definition">
<div class="flexcol character-definition-pronouns">
{{formField systemFields.pronouns value=system.pronouns rootId=partId disabled=isPlayMode}}
</div>
<div class="splitted">
<div>
<div class="flexcol">
{{formField systemFields.species value=system.species rootId=partId disabled=isPlayMode}}
</div>
<div class="flexrow">
<div class="form-group">
<label>Trait</label>
<input class="trait" type="text" value="{{trait.name}}" disabled >
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{trait.id}}"
data-item-uuid="{{trait.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{trait.id}}"
data-item-uuid="{{trait.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
</div>
</div>
<div>
<div class="flexrow">
<div class="form-group">
<label><a data-action="toChat" data-item-uuid="{{upright.uuid}}">Upright</a></label>
<input class="trait" type="text" value="{{upright.name}}" disabled >
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{upright.id}}"
data-item-uuid="{{upright.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{upright.id}}"
data-item-uuid="{{upright.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
</div>
<div class="flexrow">
<div class="form-group">
<label><a data-action="toChat" data-item-uuid="{{downright.uuid}}">Reversed</a></label>
<input class="trait" type="text" value="{{downright.name}}" disabled >
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{downright.id}}"
data-item-uuid="{{downright.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{downright.id}}"
data-item-uuid="{{downright.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</div>
</div>
</fieldset>
<fieldset class="character-stats character-stats-{{ifThen isPlayMode 'play' 'edit'}}">
<legend>{{localize "HAMALRON.Label.stats"}}</legend>
<div class="character-stat">
<label class="rollable" data-roll-type="stat" data-stat-id="flesh"><i class="fa-regular fa-dice"></i>{{localize
"HAMALRON.Label.flesh"}}</label>
{{formInput systemFields.stats.fields.flesh.fields.value value=system.stats.flesh.value rootId=partId disabled=isPlayMode type="number" }}
</div>
<div class="character-stat">
<label class="rollable" data-roll-type="stat" data-stat-id="skin"><i class="fa-regular fa-dice"></i>{{localize
"HAMALRON.Label.skin"}}</label>
{{formInput systemFields.stats.fields.skin.fields.value value=system.stats.skin.value rootId=partId disabled=isPlayMode type="number" }}
</div>
<div class="character-stat">
<label class="rollable" data-roll-type="stat" data-stat-id="heart"><i class="fa-regular fa-dice"></i>{{localize
"HAMALRON.Label.heart"}}</label>
{{formInput systemFields.stats.fields.heart.fields.value value=system.stats.heart.value rootId=partId disabled=isPlayMode type="number" }}
</div>
<div class="character-stat">
<label class="rollable" data-roll-type="stat" data-stat-id="mind"><i class="fa-regular fa-dice"></i>{{localize
"HAMALRON.Label.mind"}}</label>
{{formInput systemFields.stats.fields.mind.fields.value value=system.stats.mind.value rootId=partId disabled=isPlayMode type="number" }}
</div>
<div class="character-stat">
<label class="rollable" data-roll-type="stat" data-stat-id="soul"><i class="fa-regular fa-dice"></i>{{localize
"HAMALRON.Label.soul"}}</label>
{{formInput systemFields.stats.fields.soul.fields.value value=system.stats.soul.value rootId=partId disabled=isPlayMode type="number" }}
</div>
</fieldset>
</section>
-70
View File
@@ -1,70 +0,0 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "HAMALRON.Label.maleficas"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addMalefica"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createMalefica"></i></a>{{/if}}
</legend>
<div class="maleficas">
{{#each maleficas as |item|}}
{{!log 'weapon' this}}
<div class="malefica item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<!--<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />-->
<div class="name" data-action="toChat" data-item-uuid="{{item.uuid}}" data-roll-type="malefica" data-tooltip="{{{item.system.description}}}<br>Time:{{item.system.time}}<br>Duration:{{item.system.duration}}<br>Range:{{item.system.range}}<br>Target:{{item.system.target}}">
<a>{{item.name}}</a>
</div>
<span class="domain" data-tooltip="Domain">{{upperFirst item.system.domain}}</span>
<span class="level" data-tooltip="Level">{{getRomanLevel item.system.level}}</span>
{{#if item.system.hasDamage}}
<a class="damage rollable" data-tooltip="Damage" data-item-id="{{item.id}}" data-action="roll"
data-roll-type="damage" data-roll-value="{{item.system.damage}}">
<i class="fa-regular fa-dice"></i>
{{item.system.damage}}</a>
{{else}}
<span class="damage" data-tooltip="Damage">-</span>
{{/if}}
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.rituals"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addRitual"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createRitual"></i></a>{{/if}}
</legend>
<div class="rituals">
{{#each rituals as |item|}}
<div class="ritual item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<!--<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />-->
<div class="name" data-action="toChat" data-item-uuid="{{item.uuid}}" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}">
<a>{{item.name}}</a>
</div>
<span class="ingredients" data-tooltip="Ingredients">{{upperFirst item.system.ingredients}}</span>
<span class="difficulty" data-tooltip="Difficulty">{{upperFirst item.system.difficulty}}</span>
<span class="threshold" data-tooltip="Threshold">{{upperFirst item.system.threshold}}</span>
<span class="limit" data-tooltip="Limit">{{upperFirst item.system.limit}}</span>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
</div>
</section>
-84
View File
@@ -1,84 +0,0 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "HAMALRON.Label.characteristics"}}</legend>
<div class="counters">
<div class="flexcol">
<div>
<label>Trauma </label>{{formInput systemFields.trauma.fields.current value=system.trauma.current}} /
{{formInput systemFields.trauma.fields.max value=system.trauma.max}}
<label class="spaced-left"> Darkness </label>{{formInput systemFields.darkness.fields.current value=system.darkness.current}} /
{{formInput systemFields.darkness.fields.max value=system.darkness.max}}
{{formInput systemFields.darkness.fields.value value=system.darkness.value}}
<label class="spaced-left"> Defense </label>{{formInput systemFields.defense.fields.base value=system.defense.base}}
{{formInput systemFields.defense.fields.bonus value=system.defense.bonus }}
{{formInput systemFields.defense.fields.total value=system.defense.total}}
{{formInput systemFields.defense.fields.resistance value=system.defense.resistance}}
<label class="spaced-left"> Movement </label>{{formInput systemFields.movement.fields.base value=system.movement.base}}
{{formInput systemFields.movement.fields.reduce value=system.defense.reduce }}
</div>
<div class="flexrow characteristics-label">
<label>&nbsp;</label><span>Curr.</span><span>Max</span>
<label>&nbsp;</label><span>Curr.</span><span>Max</span><span>Mal.DR</span>
<label>&nbsp;</label><span>Base</span><span>Armor</span><span>Total</span><span>Resi.</span>
<label>&nbsp;</label><span>Base</span><span>Redu.</span>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.perks"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addPerk"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createPerk"></i></a>{{/if}}
</legend>
<div class="perks">
{{#each perks as |item|}}
<div class="perk item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<!-- <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />-->
<div class="name" data-roll-type="perk" data-action="toChat" data-item-uuid="{{item.uuid}}" data-tooltip="{{{item.system.description}}}">
<a>{{item.name}}</a>
</div>
<span class="flavor" data-tooltip="Flavor text">{{upperFirst item.system.flavorText}}</span>
<span class="role" data-tooltip="Role">{{upperFirst item.system.role}}</span>
<span class="level" data-tooltip="Level">{{getRomanLevel item.system.level}}</span>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.ailments"}}</legend>
<div class="mortality">
<label>Mortality :</label>
{{#each system.mortality.enabled as |mortality idx|}}
<input class="mortality-checkbox" type="checkbox" data-action="updateCheckboxArray" data-index="{{@index}}"
data-name="enabled" {{#if mortality}} checked {{/if}}>
{{/each}}
</div>
<div class="ailments">
{{#each system.ailments as |item id|}}
<div class="ailment " data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="false">
<label>{{item.label}}</label> <input type="checkbox" class="checkbox" name="system.ailments.{{id}}.enabled"
{{#if item.enabled}} checked {{/if}}>
</div>
{{/each}}
</div>
</fieldset>
</div>
</section>
+154
View File
@@ -0,0 +1,154 @@
<div class="{{cssClass}}">
<div class="competence-roll-header">
<div class="actor-info-compact">
<img src="{{actingCharImg}}" class="actor-avatar" data-tooltip="{{actingCharName}}" />
<div class="actor-details">
<h3 class="competence-name">{{competence.name}}</h3>
<div class="competence-meta">
<span class="meta-item">
<i class="fas fa-shapes"></i>
{{upperFirst competence.system.carteSymbole}}
</span>
<span class="meta-item">
<i class="fas fa-layer-group"></i>
{{upperFirst competence.system.niveau}} ({{competenceModifier}})
</span>
</div>
</div>
</div>
</div>
<div class="competence-roll-body">
{{#if selectedCard}}
<div class="card-used-section">
<div class="card-used-label">
<i class="fas fa-hand-sparkles"></i>
{{localize "HAMALRON.Label.cardUsed"}}
</div>
<div class="card-used-content">
<img src="{{selectedCard.img}}" class="card-thumbnail" />
<div class="card-info">
<span class="card-name">{{selectedCard.name}}</span>
{{#if cardBonus}}
<span class="card-match {{#if (eq cardSymboleMatch true)}}match-success{{else if isAtout}}match-atout{{else}}match-partial{{/if}}">
{{#if (eq cardSymboleMatch true)}}
<i class="fas fa-check-circle"></i>
{{localize "HAMALRON.Label.matchingSymbol"}}
{{else if isAtout}}
<i class="fas fa-star"></i>
Atout
{{else}}
<i class="fas fa-adjust"></i>
{{localize "HAMALRON.Label.differentSymbol"}}
{{/if}}
</span>
{{/if}}
{{#if isValet}}
<span class="valet-special-rule">
<i class="fas fa-info-circle"></i>
Valet : Compensation en cas d'échec
</span>
{{/if}}
{{#if isCavalier}}
<span class="cavalier-special-rule">
<i class="fas fa-info-circle"></i>
Cavalier : Échec transformé en égalité
</span>
{{/if}}
{{#if isReine}}
<span class="reine-special-rule">
<i class="fas fa-info-circle"></i>
Reine : Effet exceptionnel et désagrément
</span>
{{/if}}
{{#if isRoi}}
<span class="roi-special-rule">
<i class="fas fa-info-circle"></i>
Roi : Effet exceptionnel
</span>
{{/if}}
</div>
</div>
</div>
{{/if}}
<div class="calculation-section">
<div class="calculation-row">
<span class="calc-label">{{localize "HAMALRON.Label.competenceModifier"}}</span>
<span class="calc-value">{{competenceModifier}}</span>
</div>
{{#if cardBonus}}
<div class="calculation-row">
<span class="calc-label">{{localize "HAMALRON.Label.cardBonus"}}</span>
<span class="calc-value calc-bonus">+{{cardBonus}}</span>
</div>
{{/if}}
<div class="calculation-divider"></div>
<div class="calculation-row total-row">
<span class="calc-label">{{localize "HAMALRON.Label.totalValue"}}</span>
<span class="calc-value calc-total">{{totalValue}}</span>
</div>
</div>
{{#unless isSousTensionOppose}}
<div class="difficulty-section">
<div class="difficulty-info">
<i class="fas fa-bullseye"></i>
<span class="difficulty-label">{{difficulty}}</span>
<span class="difficulty-target">{{localize "HAMALRON.Label.targetScore"}}: <strong>{{targetScore}}</strong></span>
</div>
</div>
{{/unless}}
</div>
{{#if isSousTensionOppose}}
<div class="competence-roll-footer gm-only-buttons">
{{#if isAutomaticSuccess}}
<div class="automatic-success-banner">
<i class="fas fa-star"></i>
{{localize "HAMALRON.Label.automaticSuccess"}}
<i class="fas fa-star"></i>
</div>
{{/if}}
<div class="gm-buttons">
<button class="sous-tension-btn" data-action="sousTension">
<i class="fas fa-bolt"></i>
{{localize "HAMALRON.Label.sousTension"}}
</button>
<button class="oppose-btn" data-action="oppose">
<i class="fas fa-shield-alt"></i>
{{localize "HAMALRON.Label.oppose"}}
</button>
</div>
</div>
{{else}}
<div class="competence-roll-footer {{#if isSuccess}}result-success{{else if isEquality}}result-equality{{else}}result-failure{{/if}}">
{{#if isAutomaticSuccess}}
<div class="automatic-success-banner">
<i class="fas fa-star"></i>
{{localize "HAMALRON.Label.automaticSuccess"}}
<i class="fas fa-star"></i>
</div>
{{/if}}
<div class="result-icon">
{{#if isSuccess}}
<i class="fas fa-check-circle"></i>
{{else if isEquality}}
<i class="fas fa-equals"></i>
{{else}}
<i class="fas fa-times-circle"></i>
{{/if}}
</div>
<div class="result-text">
{{#if isSuccess}}
{{localize "HAMALRON.Label.success"}}
{{else if isEquality}}
Égalité
{{else}}
{{localize "HAMALRON.Label.failure"}}
{{/if}}
</div>
</div>
{{/if}}
</div>
+31 -41
View File
@@ -1,46 +1,36 @@
<div class="hamalron-tarot-draw">
<div class="fvtt-hamalron tarot-draw-chat">
<div class="tarot-draw-header">
<h2 class="tarot-draw-title">
<i class="fas fa-hand-sparkles"></i>
{{card.name}}
</h2>
</div>
<div class="tarot-draw-content">
<div class="tarot-card-image">
<img src="{{card.img}}" alt="{{card.name}}" />
</div>
<div class="tarot-card-details">
<div class="tarot-detail-row">
<span class="detail-label">{{localize
"HAMALRON.Tarot.FIELDS.symbole.label"
}}:</span>
<span class="detail-value">{{symboleLabel}}</span>
</div>
<div class="tarot-detail-row">
<span class="detail-label">{{localize
"HAMALRON.Tarot.FIELDS.valeur.label"
}}:</span>
<span class="detail-value">{{valeurLabel}}</span>
</div>
<div class="tarot-detail-row">
<span class="detail-label">{{localize
"HAMALRON.Tarot.FIELDS.type.label"
}}:</span>
<span class="detail-value">{{typeLabel}}</span>
</div>
{{#if card.description}}
<div class="tarot-description">
<div class="description-label">{{localize
"HAMALRON.Tarot.FIELDS.description.label"
}}:</div>
<div class="description-content">{{{card.description}}}</div>
<div class="draw-info-compact">
<img src="{{card.img}}" class="card-thumbnail" />
<div class="card-details">
<h3 class="card-name">{{card.name}}</h3>
<div class="card-meta">
<span class="meta-item">
<i class="fas fa-shapes"></i>
{{symboleLabel}}
</span>
<span class="meta-item">
<i class="fas fa-layer-group"></i>
{{valeurLabel}}
</span>
<span class="meta-item">
<i class="fas fa-tag"></i>
{{typeLabel}}
</span>
</div>
{{/if}}
</div>
</div>
</div>
{{#if card.description}}
<div class="tarot-draw-body">
<div class="description-section">
<div class="description-label">
<i class="fas fa-info-circle"></i>
{{localize "HAMALRON.Tarot.FIELDS.description.label"}}
</div>
<div class="description-content">{{{card.description}}}</div>
</div>
</div>
{{/if}}
</div>
+51
View File
@@ -0,0 +1,51 @@
<div class="fvtt-hamalron tarot-tension-chat">
<div class="tarot-tension-header">
<div class="tension-info-compact">
<img src="{{card.img}}" class="card-thumbnail" />
<div class="card-details">
<h3 class="card-name">{{card.name}}</h3>
<div class="card-meta">
<span class="meta-item">
<i class="fas fa-shapes"></i>
{{symboleLabel}}
</span>
<span class="meta-item">
<i class="fas fa-layer-group"></i>
{{valeurLabel}}
</span>
<span class="meta-item">
<i class="fas fa-tag"></i>
{{typeLabel}}
</span>
</div>
</div>
</div>
</div>
<div class="tarot-tension-body">
<div class="difficulty-section">
<div class="difficulty-label">
<i class="fas fa-bolt"></i>
{{localize "HAMALRON.Label.difficulty"}}
</div>
<div class="difficulty-value">{{difficulty.label}}</div>
</div>
<div class="calculation-section">
<div class="calculation-row">
<span class="calc-label">{{localize "HAMALRON.Label.cardValue"}}</span>
<span class="calc-value">{{cardValue}}</span>
</div>
<div class="calculation-row">
<span class="calc-label">{{localize "HAMALRON.Label.tensionModifier"}}</span>
<span class="calc-value {{#if (gt tensionBonus 0)}}positive{{else if (lt tensionBonus 0)}}negative{{/if}}">
{{#if (gt tensionBonus 0)}}+{{/if}}{{tensionBonus}}
</span>
</div>
<div class="calculation-total">
<span class="total-label">{{localize "HAMALRON.Label.totalScore"}}</span>
<span class="total-value">{{totalScore}}</span>
</div>
</div>
</div>
</div>
+8 -1
View File
@@ -17,7 +17,14 @@
value=system.carteSymbole
localize=true
}}
{{formField systemFields.niveau value=system.niveau}}
{{formField systemFields.niveau value=system.niveau localize=true}}
{{#if (eq system.type "faction")}}
{{formField systemFields.faction value=system.faction localize=true}}
{{/if}}
{{#if (eq system.type "peuple")}}
{{formField systemFields.peuple value=system.peuple localize=true}}
{{/if}}
</fieldset>
<fieldset>
+12
View File
@@ -5,6 +5,18 @@
>
<div class="main-div">
<fieldset>
<legend>{{localize "HAMALRON.Label.progression"}}</legend>
<div class="progression">
<input
type="number"
name="system.progression"
value="{{system.progression}}"
{{#if isPlayMode}}disabled{{/if}}
/>
</div>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.biodata"}}</legend>
<div class="biodata">
+172 -42
View File
@@ -1,60 +1,190 @@
<section class="character-main character-main-{{ifThen isPlayMode 'play' 'edit'}}">
{{!log "character-main" this}}
<section
class="character-main character-main-{{ifThen isPlayMode 'play' 'edit'}}"
>
{{log "character-main context" this}}
{{log "isEditMode" isEditMode "isPlayMode" isPlayMode}}
<fieldset>
<legend>{{localize "HAMALRON.Label.character"}}</legend>
<div class="character-pc character-pc-{{ifThen isPlayMode 'play' 'edit'}}">
<div class="character-left">
<div class="character-left-image">
<img class="character-img" src="{{actor.img}}" data-edit="img" data-action="editImage"
data-tooltip="{{actor.name}}" />
<img
class="character-img"
src="{{actor.img}}"
data-edit="img"
data-action="editImage"
data-tooltip="{{actor.name}}"
/>
</div>
<fieldset class="character-definition">
<div class="flexcol">
<div class="form-group">
<label>{{localize "HAMALRON.Label.peuple"}}</label>
<div class="item-controls">
{{#if peuple}}
<span class="item-name">{{peuple.name}}</span>
{{#if isEditMode}}
<a
class="control"
data-action="edit"
data-item-id="{{peuple._id}}"
data-item-uuid="{{peuple.uuid}}"
data-tooltip="Éditer"
>
<i class="fa-solid fa-edit"></i>
</a>
<a
class="control"
data-action="delete"
data-item-uuid="{{peuple.uuid}}"
data-tooltip="Supprimer"
>
<i class="fa-solid fa-trash"></i>
</a>
{{/if}}
{{else}}
<span class="item-name">-</span>
{{/if}}
</div>
</div>
<div class="form-group">
<label>{{localize "HAMALRON.Label.faction"}}</label>
<div class="item-controls">
{{#if faction}}
<span class="item-name">{{faction.name}}</span>
{{#if isEditMode}}
<a
class="control"
data-action="edit"
data-item-id="{{faction._id}}"
data-item-uuid="{{faction.uuid}}"
data-tooltip="Éditer"
>
<i class="fa-solid fa-edit"></i>
</a>
<a
class="control"
data-action="delete"
data-item-uuid="{{faction.uuid}}"
data-tooltip="Supprimer"
>
<i class="fa-solid fa-trash"></i>
</a>
{{/if}}
{{else}}
<span class="item-name">-</span>
{{/if}}
</div>
</div>
</div>
</fieldset>
</div>
<div class="character-right">
<div class="character-name">
{{formInput fields.name value=source.name rootId=partId disabled=isPlayMode}}
<a class="control" data-action="toggleSheet" data-tooltip="HAMALRON.ToggleSheet" data-tooltip-direction="UP">
<input
type="text"
name="name"
value="{{source.name}}"
{{#if isPlayMode}}disabled{{/if}}
/>
<a
class="control"
data-action="toggleSheet"
data-tooltip="HAMALRON.ToggleSheet"
data-tooltip-direction="UP"
>
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
</a>
</div>
<fieldset class="character-definition">
<div class="flexcol">
{{#each system.biodata as |bioField key|}}
{{#if (eq key "age")}}
{{formField systemFields.biodata.fields.age value=system.biodata.age rootId=partId disabled=isPlayMode}}
{{/if}}
{{#if (eq key "gender")}}
{{formField systemFields.biodata.fields.gender value=system.biodata.gender rootId=partId disabled=isPlayMode}}
{{/if}}
{{/each}}
</div>
</fieldset>
<fieldset
class="character-stats character-stats-{{ifThen
isPlayMode
'play'
'edit'
}}"
>
<legend>{{localize "HAMALRON.Label.cartesSucces"}}</legend>
{{log "cartesSucces data:" system.cartesSucces}}
<div class="stats-grid">
{{#each system.cartesSucces as |carte symbole|}}
{{log "Processing carte:" symbole carte "isEditMode in loop:" ../isEditMode}}
<div class="character-stat">
<label
class="rollable stat-label"
data-roll-type="carte"
data-symbole-id="{{symbole}}"
>
{{carte.label}}
</label>
<div class="stat-values">
{{log "In stat-values, isEditMode:" ../isEditMode}}
{{#if ../isEditMode}}
{{log "Rendering input for carte"}}
<input
type="number"
name="system.cartesSucces.{{symbole}}.value"
value="{{carte.value}}"
/>
{{else}}
{{log "Rendering span for carte"}}
<span class="stat-value">{{carte.value}}</span>
{{/if}}
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset class="character-stats character-stats-{{ifThen isPlayMode 'play' 'edit'}}">
<legend>{{localize "HAMALRON.Label.cartesSucces"}}</legend>
{{#each system.cartesSucces as |carte symbole|}}
<div class="character-stat">
<label class="rollable" data-roll-type="carte" data-symbole-id="{{symbole}}"><i class="fa-regular fa-dice"></i>{{carte.label}}</label>
{{formInput systemFields.cartesSucces.fields.[symbole].fields.value value=carte.value rootId=partId disabled=isPlayMode type="number" }}
<span>/</span>
{{formInput systemFields.cartesSucces.fields.[symbole].fields.max value=carte.max rootId=partId disabled=isPlayMode type="number" }}
</div>
{{/each}}
</fieldset>
<fieldset class="character-resistances">
<legend>{{localize "HAMALRON.Label.resistances"}}</legend>
<div class="resistances">
{{#each system.resistances as |resistance symbole|}}
<div class="resistance-stat">
<label>{{resistance.label}}</label>
{{formInput systemFields.resistances.fields.[symbole].fields.value value=resistance.value rootId=partId disabled=isPlayMode type="number" }}
<span>/</span>
{{formInput systemFields.resistances.fields.[symbole].fields.max value=resistance.max rootId=partId disabled=isPlayMode type="number" }}
<fieldset class="character-resistances">
<legend>{{localize "HAMALRON.Label.resistances"}}</legend>
<div class="resistances-grid">
{{#each system.resistances as |resistance symbole|}}
<div class="resistance-stat">
<label class="stat-label">{{resistance.label}}</label>
<div class="stat-values">
{{#if ../isEditMode}}
<input
type="number"
name="system.resistances.{{symbole}}.value"
value="{{resistance.value}}"
/>
<span class="separator">/</span>
<input
type="number"
name="system.resistances.{{symbole}}.max"
value="{{resistance.max}}"
/>
{{else}}
<a
class="control resistance-control"
data-action="modifyResistance"
data-symbole="{{symbole}}"
data-delta="-1"
data-tooltip="Diminuer"
>
<i class="fa-solid fa-minus"></i>
</a>
<span class="stat-value">{{resistance.value}}</span>
<span class="separator">/</span>
<span class="stat-value">{{resistance.max}}</span>
<a
class="control resistance-control"
data-action="modifyResistance"
data-symbole="{{symbole}}"
data-delta="1"
data-tooltip="Augmenter"
>
<i class="fa-solid fa-plus"></i>
</a>
{{/if}}
</div>
</div>
{{/each}}
</div>
</fieldset>
</div>
{{/each}}
</div>
</fieldset>
</section>
+134 -61
View File
@@ -1,70 +1,143 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<section
class="tab character-{{tab.id}} {{tab.cssClass}}"
data-tab="{{tab.id}}"
data-group="{{tab.group}}"
>
<div class="main-div">
<fieldset>
<legend>{{localize "HAMALRON.Label.maleficas"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addMalefica"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createMalefica"></i></a>{{/if}}
</legend>
<div class="maleficas">
{{#each maleficas as |item|}}
{{!log 'weapon' this}}
<div class="malefica item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<fieldset>
<legend>{{localize "HAMALRON.Label.sortileges"}}{{#if isEditMode}}
<a
class="action"
data-tooltip="{{localize 'HAMALRON.Tooltip.addMalefica'}}"
data-tooltip-direction="UP"
><i class="fas fa-plus" data-action="createMalefica"></i></a>{{/if}}
</legend>
<div class="sortileges">
{{#each sortileges as |item|}}
<div
class="sortilege item"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-drag="true"
>
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<!--<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />-->
<div class="name" data-action="toChat" data-item-uuid="{{item.uuid}}" data-roll-type="malefica" data-tooltip="{{{item.system.description}}}<br>Time:{{item.system.time}}<br>Duration:{{item.system.duration}}<br>Range:{{item.system.range}}<br>Target:{{item.system.target}}">
<a>{{item.name}}</a>
</div>
<span class="domain" data-tooltip="Domain">{{upperFirst item.system.domain}}</span>
<span class="level" data-tooltip="Level">{{getRomanLevel item.system.level}}</span>
{{#if item.system.hasDamage}}
<a class="damage rollable" data-tooltip="Damage" data-item-id="{{item.id}}" data-action="roll"
data-roll-type="damage" data-roll-value="{{item.system.damage}}">
<i class="fa-regular fa-dice"></i>
{{item.system.damage}}</a>
{{else}}
<span class="damage" data-tooltip="Damage">-</span>
{{/if}}
<img
class="item-img"
src="{{item.img}}"
data-tooltip="{{item.name}}"
/>
<!--<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />-->
<div
class="name"
data-action="toChat"
data-item-uuid="{{item.uuid}}"
data-roll-type="malefica"
data-tooltip="{{{item.system.description}}}<br>Time:{{item.system.time}}<br>Duration:{{item.system.duration}}<br>Range:{{item.system.range}}<br>Target:{{item.system.target}}"
>
<a>{{item.name}}</a>
</div>
<span class="domain" data-tooltip="Domain">{{upperFirst
item.system.domain
}}</span>
<span class="level" data-tooltip="Level">{{getRomanLevel
item.system.level
}}</span>
{{#if item.system.hasDamage}}
<a
class="damage rollable"
data-tooltip="Damage"
data-item-id="{{item.id}}"
data-action="roll"
data-roll-type="damage"
data-roll-value="{{item.system.damage}}"
>
<i class="fa-regular fa-dice"></i>
{{item.system.damage}}</a>
{{else}}
<span class="damage" data-tooltip="Damage">-</span>
{{/if}}
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
<div class="controls">
<a
data-tooltip="{{localize 'HAMALRON.Edit'}}"
data-action="edit"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-edit"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Delete'}}"
data-action="delete"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
</fieldset>
</fieldset>
<fieldset>
<legend>{{localize "HAMALRON.Label.rituals"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addRitual"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createRitual"></i></a>{{/if}}
</legend>
<div class="rituals">
{{#each rituals as |item|}}
<div class="ritual item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<fieldset>
<legend>{{localize "HAMALRON.Label.rituals"}}{{#if isEditMode}}
<a
class="action"
data-tooltip="{{localize 'HAMALRON.Tooltip.addRitual'}}"
data-tooltip-direction="UP"
><i class="fas fa-plus" data-action="createRitual"></i></a>{{/if}}
</legend>
<div class="rituals">
{{#each rituals as |item|}}
<div
class="ritual item"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-drag="true"
>
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<!--<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />-->
<div class="name" data-action="toChat" data-item-uuid="{{item.uuid}}" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}">
<a>{{item.name}}</a>
</div>
<span class="ingredients" data-tooltip="Ingredients">{{upperFirst item.system.ingredients}}</span>
<span class="difficulty" data-tooltip="Difficulty">{{upperFirst item.system.difficulty}}</span>
<span class="threshold" data-tooltip="Threshold">{{upperFirst item.system.threshold}}</span>
<span class="limit" data-tooltip="Limit">{{upperFirst item.system.limit}}</span>
<img
class="item-img"
src="{{item.img}}"
data-tooltip="{{item.name}}"
/>
<!--<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />-->
<div
class="name"
data-action="toChat"
data-item-uuid="{{item.uuid}}"
data-roll-type="weapon"
data-tooltip="{{{item.system.description}}}"
>
<a>{{item.name}}</a>
</div>
<span class="ingredients" data-tooltip="Ingredients">{{upperFirst
item.system.ingredients
}}</span>
<span class="difficulty" data-tooltip="Difficulty">{{upperFirst
item.system.difficulty
}}</span>
<span class="threshold" data-tooltip="Threshold">{{upperFirst
item.system.threshold
}}</span>
<span class="limit" data-tooltip="Limit">{{upperFirst
item.system.limit
}}</span>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
<div class="controls">
<a
data-tooltip="{{localize 'HAMALRON.Edit'}}"
data-action="edit"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-edit"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Delete'}}"
data-action="delete"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
</fieldset>
</div>
</fieldset>
</div>
</section>
+191 -36
View File
@@ -1,44 +1,199 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<section
class="tab character-{{tab.id}} {{tab.cssClass}}"
data-tab="{{tab.id}}"
data-group="{{tab.group}}"
>
<div class="main-div">
<fieldset>
<legend>{{localize "HAMALRON.Label.progression"}}</legend>
<div class="progression">
{{formField systemFields.progression value=system.progression type="number"}}
</div>
</fieldset>
{{#if competencesCommunes.length}}
<fieldset class="competences-group">
<legend class="competences-type-header">Compétences communes</legend>
<div class="competences">
{{#each competencesCommunes as |item|}}
<div
class="competence item"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-drag="true"
>
<img
class="item-img"
src="{{item.img}}"
data-tooltip="{{item.name}}"
/>
<div
class="name"
data-action="rollCompetence"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-tooltip="{{{item.system.description}}}"
>
<a>{{item.name}}</a>
</div>
<span class="carte" data-tooltip="Carte">{{upperFirst
item.system.carteSymbole
}}</span>
<span
class="niveau"
data-tooltip="Modificateur: {{item.niveauModificateur}}"
>{{item.niveauName}} ({{item.niveauModificateur}})</span>
<fieldset>
<legend>{{localize "HAMALRON.Label.competences"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "HAMALRON.Tooltip.addCompetence"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createPerk"></i></a>{{/if}}
</legend>
<div class="competences">
{{#each perks as |item|}}
<div class="competence item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-roll-type="competence" data-action="toChat" data-item-uuid="{{item.uuid}}" data-tooltip="{{{item.system.description}}}">
<a>{{item.name}}</a>
</div>
<span class="type" data-tooltip="Type">{{upperFirst item.system.type}}</span>
<span class="carte" data-tooltip="Carte">{{upperFirst item.system.carteSymbole}}</span>
<span class="niveau" data-tooltip="Niveau">{{item.system.niveau}}</span>
<div class="controls">
<a data-tooltip="{{localize 'HAMALRON.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'HAMALRON.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
<div class="controls">
<a
data-tooltip="{{localize 'HAMALRON.Roll.rollCompetence'}}"
data-action="rollCompetence"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-cards"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Edit'}}"
data-action="edit"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-edit"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Delete'}}"
data-action="delete"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
{{/each}}
</div>
</fieldset>
</fieldset>
{{/if}}
</div>
</section>
</fieldset>
{{#if competencesPeuple.length}}
<fieldset class="competences-group">
<legend class="competences-type-header">Compétences de peuple</legend>
<div class="competences">
{{#each competencesPeuple as |item|}}
<div
class="competence item"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-drag="true"
>
<img
class="item-img"
src="{{item.img}}"
data-tooltip="{{item.name}}"
/>
<div
class="name"
data-action="rollCompetence"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-tooltip="{{{item.system.description}}}"
>
<a>{{item.name}}</a>
</div>
<span class="carte" data-tooltip="Carte">{{upperFirst
item.system.carteSymbole
}}</span>
<span
class="niveau"
data-tooltip="Modificateur: {{item.niveauModificateur}}"
>{{item.niveauName}} ({{item.niveauModificateur}})</span>
<div class="controls">
<a
data-tooltip="{{localize 'HAMALRON.Roll.rollCompetence'}}"
data-action="rollCompetence"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-cards"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Edit'}}"
data-action="edit"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-edit"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Delete'}}"
data-action="delete"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
{{/if}}
{{#if competencesFaction.length}}
<fieldset class="competences-group">
<legend class="competences-type-header">Compétences de faction</legend>
<div class="competences">
{{#each competencesFaction as |item|}}
<div
class="competence item"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-drag="true"
>
<img
class="item-img"
src="{{item.img}}"
data-tooltip="{{item.name}}"
/>
<div
class="name"
data-action="rollCompetence"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
data-tooltip="{{{item.system.description}}}"
>
<a>{{item.name}}</a>
</div>
<span class="carte" data-tooltip="Carte">{{upperFirst
item.system.carteSymbole
}}</span>
<span
class="niveau"
data-tooltip="Modificateur: {{item.niveauModificateur}}"
>{{item.niveauName}} ({{item.niveauModificateur}})</span>
<div class="controls">
<a
data-tooltip="{{localize 'HAMALRON.Roll.rollCompetence'}}"
data-action="rollCompetence"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-cards"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Edit'}}"
data-action="edit"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-edit"></i></a>
<a
data-tooltip="{{localize 'HAMALRON.Delete'}}"
data-action="delete"
data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"
><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
{{/if}}
{{#if isEditMode}}
<div class="add-competence-section">
<a
class="action add-competence-button"
data-tooltip="{{localize 'HAMALRON.Tooltip.addCompetence'}}"
data-tooltip-direction="UP"
>
<i class="fas fa-plus"></i>
Ajouter une compétence
</a>
</div>
{{/if}}
</div>
</section>
+60 -55
View File
@@ -5,13 +5,27 @@
>
<div class="tarot-hand-container">
<div class="tarot-hand-header">
<h2>{{localize "HAMALRON.Label.tarotHand"}}</h2>
<div class="tarot-hand-info">
<span class="card-count">
<span class="card-count {{#if isOverLimit}}over-limit{{/if}}">
<i class="fas fa-layer-group"></i>
{{tarotCards.length}}
{{handSize}} / {{handLimit}}
{{localize "HAMALRON.Label.cards"}}
</span>
<button
class="draw-card-button"
data-action="drawCard"
data-tooltip="{{localize 'HAMALRON.Label.drawCard'}}"
{{#unless (lt handSize 7)}}disabled{{/unless}}
>
<i class="fas fa-hand-sparkles"></i>
{{localize "HAMALRON.Label.drawCard"}}
</button>
{{#if isOverLimit}}
<span class="hand-warning">
<i class="fas fa-exclamation-triangle"></i>
{{localize "HAMALRON.Label.mustDiscardCard"}}
</span>
{{/if}}
</div>
</div>
@@ -19,30 +33,30 @@
<div class="tarot-hand-cards">
{{#each tarotCards as |card|}}
<div
class="tarot-card-wrapper"
class="tarot-card-wrapper {{#if card.isSuccessCard}}success-card{{/if}}"
data-item-id="{{card.id}}"
data-item-uuid="{{card.uuid}}"
data-drag="true"
data-action="selectCard"
>
<div class="tarot-card">
<div class="tarot-card-inner">
<div class="tarot-card-front">
<div class="tarot-card-header">
<h3 class="tarot-card-name">{{card.name}}</h3>
<div class="tarot-card-controls">
{{#if @root.isEditMode}}
<a
class="card-control"
class="card-control delete-control"
data-tooltip="{{localize 'HAMALRON.Delete'}}"
data-action="delete"
data-item-id="{{card.id}}"
data-item-uuid="{{card.uuid}}"
>
<i class="fas fa-trash"></i>
<i class="fas fa-times"></i>
</a>
{{/if}}
<a
class="card-control"
class="card-control view-control"
data-tooltip="{{localize 'HAMALRON.ViewDetails'}}"
data-action="edit"
data-item-id="{{card.id}}"
@@ -50,6 +64,9 @@
>
<i class="fas fa-eye"></i>
</a>
{{#if card.isSuccessCard}}
<span class="success-indicator"><i class="fas fa-star"></i></span>
{{/if}}
</div>
</div>
@@ -57,57 +74,45 @@
<img src="{{card.system.image}}" alt="{{card.name}}" />
</div>
<div class="tarot-card-info">
<div class="card-info-row">
<span class="info-label">
<i class="fas fa-star"></i>
{{localize "HAMALRON.Tarot.FIELDS.symbole.label"}}:
</span>
<span class="info-value symbole-{{card.system.symbole}}">
{{localize
(concat
"HAMALRON.Tarot.FIELDS.symbole." card.system.symbole
)
}}
</span>
</div>
<div class="card-info-row">
<span class="info-label">
<i class="fas fa-hashtag"></i>
{{localize "HAMALRON.Tarot.FIELDS.valeur.label"}}:
</span>
<span class="info-value">
{{localize
(concat
"HAMALRON.Tarot.FIELDS.valeur." card.system.valeur
)
}}
</span>
</div>
<div class="card-info-row">
<span class="info-label">
<i class="fas fa-tag"></i>
{{localize "HAMALRON.Tarot.FIELDS.type.label"}}:
</span>
<span class="info-value">
{{localize
(concat
"HAMALRON.Tarot.FIELDS.type." card.system.type
)
}}
</span>
</div>
<div class="tarot-card-name">
<h4>{{card.name}}</h4>
</div>
{{#if card.system.description}}
<div class="tarot-card-description">
<div class="description-text">
{{{card.enrichedDescription}}}
<div class="tarot-card-info">
<div class="card-info-compact">
<div class="card-symbole symbole-{{card.system.symbole}}">
<i class="fas fa-circle"></i>
{{localize (concat "HAMALRON.Tarot.FIELDS.symbole." card.system.symbole)}}
</div>
<div class="card-valeur">
{{tarotValue card.system.valeur}}
</div>
</div>
{{/if}}
<div class="card-actions">
<button
class="discard-and-draw-button"
data-action="discardAndDraw"
data-item-id="{{card.id}}"
data-tooltip="{{localize 'HAMALRON.Label.discardAndDraw'}}"
>
<i class="fas fa-exchange-alt"></i>
{{localize "HAMALRON.Label.discardAndDraw"}}
</button>
</div>
{{#if @root.isOverLimit}}
{{#if @root.isEditMode}}
<button
class="discard-button"
data-action="discardCard"
data-item-id="{{card.id}}"
data-tooltip="{{localize 'HAMALRON.Label.discardCard'}}"
>
<i class="fas fa-trash-alt"></i>
{{localize "HAMALRON.Label.discard"}}
</button>
{{/if}}
{{/if}}
</div>
</div>
</div>
</div>
+81 -30
View File
@@ -1,40 +1,91 @@
<div class="fvtt-ftl-nomad-roll-dialog">
<div class="fvtt-hamalron-roll-dialog">
<fieldSet>
{{#if (eq rollType "competence")}}
<fieldSet>
<legend>{{localize "HAMALRON.Label.competence"}}</legend>
{{#if (eq rollType "stat")}}
<legend>{{localize "HAMALRON.Label.stat"}}</legend>
{{/if}}
<div class="dialog-info">
<div class="actor-info">
<img
src="{{actorImage}}"
alt="{{actorName}}"
class="actor-portrait"
/>
<span class="actor-name">{{actorName}}</span>
</div>
<div class="dialog-stat">{{localize rollItem.label}} : 3d6+{{rollItem.value}}</div>
<div class="competence-info">
<h3>{{rollItem.name}}</h3>
<div class="competence-details">
<span class="competence-symbole">{{localize
"HAMALRON.Label.symbole"
}}:
{{upperFirst rollItem.system.carteSymbole}}</span>
<span class="competence-niveau">{{localize
"HAMALRON.Label.niveau"
}}:
{{rollItem.system.niveau}}
({{competenceModifier}})</span>
</div>
</div>
</div>
</fieldSet>
{{#if weapon}}
<div class="dialog-stat">Weapon : {{weapon.name}}</div>
{{/if}}
<fieldSet>
<legend>{{localize "HAMALRON.Label.selectTarotCard"}}</legend>
</fieldSet>
<div class="tarot-hand">
{{#if tarotCards}}
{{#each tarotCards as |card|}}
<div
class="tarot-card-select {{#if card.isSuccessCard}}success-card{{/if}}"
data-card-id="{{card.id}}"
data-card-symbole="{{card.system.symbole}}"
data-card-valeur="{{card.system.valeur}}"
data-card-type="{{card.system.type}}"
data-is-success-card="{{card.isSuccessCard}}"
>
<img
src="{{card.img}}"
alt="{{card.name}}"
data-tooltip="{{card.name}}"
/>
<span class="card-name">{{card.name}}</span>
{{#if card.isSuccessCard}}<span class="success-indicator"><i class="fas fa-star"></i></span>{{/if}}
<span class="card-values"></span>
</div>
{{/each}}
{{else}}
<p>{{localize "HAMALRON.Notifications.noTarotCards"}}</p>
{{/if}}
</div>
</fieldSet>
<fieldSet class="dialog-modifier">
<legend>Advantages & Disadvantages</legend>
<fieldSet>
<legend>{{localize "HAMALRON.Label.difficulty"}}</legend>
<select name="difficulty" class="difficulty-select">
{{selectOptions
difficultyChoices
selected="soustension_oppose"
localize=false
}}
</select>
</fieldSet>
<select name="nbadvantages" class="roll-stat-advantages">
{{selectOptions choiceAdvantages selected=nbAdvantages localize=true}}
</select>
<select name="nbdisadvantages" class="roll-stat-disadvantages">
{{selectOptions choiceDisadvantages selected=nbDisadvantages localize=true}}
</select>
</fieldSet>
<fieldSet class="dialog-formula">
<legend>Difficulty</legend>
<input name="difficulty" class="roll-difficulty" type="number" value="{{difficulty}}">
</fieldSet>
<fieldSet class="dialog-formula">
<legend>{{localize "HAMALRON.Label.formula"}}</legend>
<label name="fullFormula" id="roll-dialog-full-formula" >{{fullFormula}}</label>
</fieldSet>
<fieldSet class="dialog-result">
<legend>{{localize "HAMALRON.Label.total"}}</legend>
<div class="total-display">
<span id="competence-modifier">{{competenceModifier}}</span>
<span id="card-value-display">+ 0</span>
<span>=</span>
<span id="total-value">{{competenceModifier}}</span>
</div>
<div id="difficulty-info" class="difficulty-info">
<span>{{localize "HAMALRON.Label.targetScore"}}:
<span id="target-score">-</span></span>
</div>
</fieldSet>
{{/if}}
<fieldSet>
<legend>{{localize "HAMALRON.Label.rollView"}}</legend>
+24 -41
View File
@@ -8,9 +8,9 @@
<span class="stat-value">{{deckCount}}</span>
</div>
<div class="stat-item">
<i class="fas fa-hand-holding"></i>
<span class="stat-label">{{localize "HAMALRON.TarotDeck.CardsDrawn"}}:</span>
<span class="stat-value">{{drawnCount}}</span>
<i class="fas fa-trash-alt"></i>
<span class="stat-label">{{localize "HAMALRON.TarotDeck.CardsInDiscard"}}:</span>
<span class="stat-value">{{discardCount}}</span>
</div>
<div class="stat-item">
<i class="fas fa-clone"></i>
@@ -26,48 +26,31 @@
{{localize "HAMALRON.TarotDeck.ResetDeck"}}
</button>
<div class="draw-actions">
<button type="button" class="action-button draw-button" data-action="drawCard" {{#unless hasCards}}disabled{{/unless}}>
<i class="fas fa-hand-sparkles"></i>
{{localize "HAMALRON.TarotDeck.DrawOne"}}
</button>
<button type="button" class="action-button collect-hands-button" data-action="collectHands">
<i class="fas fa-users"></i>
{{localize "HAMALRON.TarotDeck.CollectHands"}}
</button>
<button type="button" class="action-button draw-button" data-action="drawMultiple" data-count="3" {{#unless hasCards}}disabled{{/unless}}>
<i class="fas fa-cards-blank"></i>
{{localize "HAMALRON.TarotDeck.DrawThree"}}
</button>
<button type="button" class="action-button distribute-cards-button" data-action="distributeCards" {{#unless hasCards}}disabled{{/unless}}>
<i class="fas fa-hand-holding-heart"></i>
{{localize "HAMALRON.TarotDeck.DistributeCards"}}
</button>
<button type="button" class="action-button draw-button" data-action="drawMultiple" data-count="5" {{#unless hasCards}}disabled{{/unless}}>
<i class="fas fa-cards"></i>
{{localize "HAMALRON.TarotDeck.DrawFive"}}
</button>
</div>
</div>
<button type="button" class="action-button shuffle-discard-button" data-action="shuffleDiscard" {{#unless hasDiscard}}disabled{{/unless}}>
<i class="fas fa-recycle"></i>
{{localize "HAMALRON.TarotDeck.ShuffleDiscard"}}
</button>
{{#if drawnCards.length}}
<div class="recent-draws">
<h3>{{localize "HAMALRON.TarotDeck.RecentDraws"}}</h3>
<div class="drawn-cards-list">
{{#each drawnCards}}
<div class="drawn-card">
<img src="{{this.img}}" alt="{{this.name}}" class="card-image">
<div class="card-info">
<h4 class="card-name">{{this.name}}</h4>
<div class="card-details">
<span class="card-symbole">{{lookup ../symboleLabel @index}}</span>
<span class="card-valeur">{{lookup ../valeurLabel @index}}</span>
</div>
</div>
</div>
{{/each}}
</div>
<button type="button" class="action-button draw-button" data-action="drawCard" {{#unless hasCards}}disabled{{/unless}}>
<i class="fas fa-hand-sparkles"></i>
{{localize "HAMALRON.TarotDeck.DrawOne"}}
</button>
<button type="button" class="action-button draw-tension-button" data-action="drawTension" {{#unless hasCards}}disabled{{/unless}}>
<i class="fas fa-bolt"></i>
{{localize "HAMALRON.TarotDeck.DrawTension"}}
</button>
</div>
{{else}}
<div class="no-draws">
<i class="fas fa-cards fa-3x"></i>
<p>{{localize "HAMALRON.TarotDeck.NoDrawsYet"}}</p>
</div>
{{/if}}
{{#unless hasCards}}
<div class="deck-empty-warning">
+1 -1
View File
@@ -14,8 +14,8 @@
{{formField systemFields.type value=system.type localize=true}}
{{#unless (eq system.type "atout")}}
{{formField systemFields.symbole value=system.symbole localize=true}}
{{formField systemFields.valeur value=system.valeur localize=true}}
{{/unless}}
{{formField systemFields.valeur value=system.valeur localize=true}}
</fieldset>
<fieldset>