diff --git a/README.md b/README.md index 1c8cf48..11f753d 100644 --- a/README.md +++ b/README.md @@ -133,4 +133,10 @@ make build|watch|lint # Raccourcis Makefile ## Licence -Projet fan non-officiel. L'univers et les marques Vermine 2047 appartiennent aux Éditions John Doe. +VERMINE 2047, Un jeu de Julien Blondel + +© 2023 Studio Agate +TOTEM System + +© 2023 Julien Blondel +Tous droits réservés \ No newline at end of file diff --git a/assets/icons/items/creaturecapacity.webp b/assets/icons/items/creaturecapacity.webp new file mode 100644 index 0000000..0a236c8 Binary files /dev/null and b/assets/icons/items/creaturecapacity.webp differ diff --git a/char-sheet-fixed.png b/char-sheet-fixed.png deleted file mode 100644 index d6b2665..0000000 Binary files a/char-sheet-fixed.png and /dev/null differ diff --git a/char-sheet.png b/char-sheet.png deleted file mode 100644 index f1735fb..0000000 Binary files a/char-sheet.png and /dev/null differ diff --git a/char-sheet.txt b/char-sheet.txt deleted file mode 100644 index a19f24e..0000000 --- a/char-sheet.txt +++ /dev/null @@ -1,680 +0,0 @@ -uid=78_0 RootWebArea "Foundry Virtual Tabletop" url="https://localhost:31000/game" - uid=78_1 ignored - uid=78_2 generic - uid=78_3 list - uid=78_4 generic - uid=78_5 generic - uid=78_6 generic - uid=78_7 generic - uid=78_8 generic - uid=78_9 generic - uid=78_10 list - uid=78_11 listitem level="1" - uid=78_12 tab "Outils de token" selectable - uid=78_13 listitem level="1" - uid=78_14 tab "Outils de tuile" selectable - uid=78_15 listitem level="1" - uid=78_16 tab "Outils de dessin" selectable - uid=78_17 listitem level="1" - uid=78_18 tab "Outils de mur" selectable - uid=78_19 listitem level="1" - uid=78_20 tab "Outils de lumière" selectable - uid=78_21 listitem level="1" - uid=78_22 tab "Outils de son d’ambiance" selectable - uid=78_23 listitem level="1" - uid=78_24 tab "Outils de région" selectable - uid=78_25 listitem level="1" - uid=78_26 tab "Notes" selectable - uid=78_27 list - uid=78_28 listitem level="1" - uid=78_29 button "Sélection de tokens" pressed - uid=78_30 listitem level="1" - uid=78_31 button "Sélection de cibles" - uid=78_32 listitem level="1" - uid=78_33 button "Règle" - uid=78_34 listitem level="1" - uid=78_35 button "Déplacement sans contrainte" - uid=78_36 generic - uid=78_37 generic - uid=78_38 list - uid=78_39 listitem level="1" - uid=78_40 ignored - uid=78_41 StaticText "Gamemaster [MJ]" - uid=78_42 InlineTextBox "Gamemaster [MJ]" - uid=78_43 generic - uid=78_44 generic - uid=78_45 LabelText - uid=78_46 StaticText "Latence" - uid=78_42 InlineTextBox "Latence" - uid=78_47 StaticText " " - uid=78_42 InlineTextBox " " - uid=78_48 StaticText "1ms" - uid=78_42 InlineTextBox "1ms" - uid=78_49 generic - uid=78_50 LabelText - uid=78_51 StaticText "IPS" - uid=78_42 InlineTextBox "IPS" - uid=78_52 StaticText " " - uid=78_42 InlineTextBox " " - uid=78_53 StaticText "--" - uid=78_42 InlineTextBox "--" - uid=78_54 button - uid=78_55 generic - uid=78_56 navigation - uid=78_57 list - uid=78_58 generic - uid=78_59 sectionheader - uid=78_60 generic - uid=78_61 generic - uid=78_62 LabelText - uid=78_63 LabelText - uid=78_64 sectionfooter - uid=78_65 generic roledescription="Barre de raccourcis" - uid=78_66 generic - uid=78_67 button "Couper le son" - uid=78_68 button "Menu principal" - uid=78_69 list - uid=78_70 button "Emplacement vide" - uid=78_71 ignored - uid=78_72 StaticText "1" - uid=78_42 InlineTextBox "1" - uid=78_73 button "Emplacement vide" - uid=78_74 ignored - uid=78_75 StaticText "2" - uid=78_42 InlineTextBox "2" - uid=78_76 button "Emplacement vide" - uid=78_77 ignored - uid=78_78 StaticText "3" - uid=78_42 InlineTextBox "3" - uid=78_79 button "Emplacement vide" - uid=78_80 ignored - uid=78_81 StaticText "4" - uid=78_42 InlineTextBox "4" - uid=78_82 button "Emplacement vide" - uid=78_83 ignored - uid=78_84 StaticText "5" - uid=78_42 InlineTextBox "5" - uid=78_85 button "Emplacement vide" - uid=78_86 ignored - uid=78_87 StaticText "6" - uid=78_42 InlineTextBox "6" - uid=78_88 button "Emplacement vide" - uid=78_89 ignored - uid=78_90 StaticText "7" - uid=78_42 InlineTextBox "7" - uid=78_91 button "Emplacement vide" - uid=78_92 ignored - uid=78_93 StaticText "8" - uid=78_42 InlineTextBox "8" - uid=78_94 button "Emplacement vide" - uid=78_95 ignored - uid=78_96 StaticText "9" - uid=78_42 InlineTextBox "9" - uid=78_97 button "Emplacement vide" - uid=78_98 ignored - uid=78_99 StaticText "0" - uid=78_42 InlineTextBox "0" - uid=78_100 generic - uid=78_101 navigation - uid=78_102 button "Page suivante" - uid=78_103 ignored - uid=78_104 StaticText "1" - uid=78_42 InlineTextBox "1" - uid=78_105 button "Page précédente" - uid=78_106 ignored - uid=78_107 button "Verrouiller la barre de raccourcis" - uid=78_108 button "Effacer la barre de raccourcis" - uid=78_109 generic - uid=78_110 generic - uid=78_111 generic - uid=78_112 ignored - uid=78_113 list - uid=78_114 generic "Tchat" - uid=78_115 generic - uid=78_116 generic value=" -" - uid=78_117 paragraph - uid=78_118 LineBreak " -" - uid=78_42 InlineTextBox " -" - uid=78_119 ignored - uid=78_42 generic - uid=78_42 StaticText "Entrer un message" - uid=78_42 InlineTextBox "Entrer un message" - uid=78_120 generic - uid=78_121 generic - uid=78_122 button "Public en tant qu'utilisateur" pressed - uid=78_123 button "Privé pour les maîtres de jeu" - uid=78_124 button "Aveugle pour les maîtres de jeu" - uid=78_125 button "Seulement pour soi-même" - uid=78_126 button "Public en tant que personnage" - uid=78_127 generic - uid=78_128 tablist orientation="horizontal" - uid=78_129 list - uid=78_130 listitem level="1" - uid=78_131 tab "Messages du tchat" selectable - uid=78_132 listitem level="1" - uid=78_133 tab "Rencontres de combat" selectable - uid=78_134 listitem level="1" - uid=78_135 tab "Scènes" selectable - uid=78_136 listitem level="1" - uid=78_137 tab "Objets plaçables" selectable - uid=78_138 listitem level="1" - uid=78_139 tab "Acteurs" selectable - uid=78_140 listitem level="1" - uid=78_141 tab "Objets" selectable - uid=78_142 listitem level="1" - uid=78_143 tab "Journaux" selectable - uid=78_144 listitem level="1" - uid=78_145 tab "Tables aléatoires" selectable - uid=78_146 listitem level="1" - uid=78_147 tab "Jeux de cartes" selectable - uid=78_148 listitem level="1" - uid=78_149 tab "Macros" selectable - uid=78_150 listitem level="1" - uid=78_151 tab "Playlists" selectable - uid=78_152 listitem level="1" - uid=78_153 tab "Compendiums" selectable - uid=78_154 listitem level="1" - uid=78_155 tab "Paramètres" selectable - uid=78_156 listitem level="1" - uid=78_157 button "Réduire" - uid=78_158 generic - uid=78_159 ignored - uid=78_160 ignored - uid=78_161 ignored - uid=78_162 ignored - uid=78_163 generic - uid=78_164 sectionheader - uid=78_165 ignored - uid=78_166 button "Créer un acteur" - uid=78_167 ignored - uid=78_168 ignored - uid=78_169 StaticText "Créer un acteur" - uid=78_42 InlineTextBox "Créer un acteur" - uid=78_170 button "Créer un dossier" - uid=78_171 ignored - uid=78_172 ignored - uid=78_173 StaticText "Créer un dossier" - uid=78_42 InlineTextBox "Créer un dossier" - uid=78_174 search - uid=78_175 button "Recherche par nom uniquement" - uid=78_176 searchbox "Chercher dans les Acteurs" - uid=78_177 ignored - uid=78_178 ignored - uid=78_179 generic - uid=78_180 button "Trier par ordre alphabétique" - uid=78_181 button "Réduire tous les dossiers" - uid=78_182 list - uid=78_183 listitem level="1" - uid=78_184 image "Acteur" url="https://localhost:31000/systems/vermine2047/assets/icons/actors/creature.webp" - uid=78_185 generic - uid=78_186 StaticText "Acteur" - uid=78_42 InlineTextBox "Acteur" - uid=78_187 listitem level="1" - uid=78_188 image "Acteur (2)" url="https://localhost:31000/systems/vermine2047/assets/icons/actors/group.webp" - uid=78_189 generic - uid=78_190 StaticText "Acteur (2)" - uid=78_42 InlineTextBox "Acteur (2)" - uid=78_191 listitem level="1" - uid=78_192 image "Acteur (3)" url="https://localhost:31000/systems/vermine2047/assets/icons/actors/character.webp" - uid=78_193 generic - uid=78_194 StaticText "Acteur (3)" - uid=78_42 InlineTextBox "Acteur (3)" - uid=78_195 sectionfooter - uid=78_196 ignored - uid=78_197 ignored - uid=78_198 ignored - uid=78_199 ignored - uid=78_200 ignored - uid=78_201 ignored - uid=78_202 ignored - uid=78_203 ignored - uid=78_204 ignored - uid=78_205 ignored - uid=78_206 ignored - uid=78_207 ignored - uid=78_208 ignored - uid=78_209 ignored - uid=78_210 ignored - uid=78_211 ignored - uid=78_212 ignored - uid=78_213 ignored - uid=78_214 ignored - uid=78_215 ignored - uid=78_216 ignored - uid=78_217 ignored - uid=78_218 ignored - uid=78_219 figure - uid=78_220 image url="https://localhost:31000/ui/pause.svg" - uid=78_221 Figcaption - uid=78_222 StaticText "JEU EN PAUSE" - uid=78_42 InlineTextBox "JEU EN PAUSE" - uid=78_223 form - uid=78_224 banner - uid=78_225 heading "Personnage: Acteur (3)" level="1" - uid=78_226 StaticText "Personnage: Acteur (3)" - uid=78_42 InlineTextBox "Personnage: Acteur (3)" - uid=78_227 button "Basculer les contrôles" - uid=78_228 button "Copier l'UUID du document" - uid=78_229 button "Fermer la fenêtre" - uid=78_230 generic - uid=78_231 ignored - uid=78_232 ignored - uid=78_233 button "MODE ÉDITION" - uid=78_234 StaticText "MODE ÉDITION" - uid=78_42 InlineTextBox "MODE ÉDITION" - uid=78_235 image "logo Vermine" url="https://localhost:31000/systems/vermine2047/assets/images/ui/logo.webp" - uid=78_236 ignored - uid=78_237 image "Acteur (3)" url="https://localhost:31000/systems/vermine2047/assets/icons/actors/character.webp" - uid=78_238 generic - uid=78_239 heading "ADAPTATION" level="3" - uid=78_240 StaticText "ADAPTATION" - uid=78_42 InlineTextBox "ADAPTATION" - uid=78_241 heading "L'Humain" level="5" - uid=78_242 StaticText "L'Humain" - uid=78_42 InlineTextBox "L'Humain" - uid=78_243 image url="https://localhost:31000/systems/vermine2047/assets/images/ui/totems/human.webp" - uid=78_244 heading "L'adapté" level="5" - uid=78_245 StaticText "L'adapté" - uid=78_42 InlineTextBox "L'adapté" - uid=78_246 image url="https://localhost:31000/systems/vermine2047/assets/images/ui/totems/adapted.webp" - uid=78_247 ignored - uid=78_248 ignored - uid=78_249 ignored - uid=78_250 generic - uid=78_251 generic - uid=78_252 ignored - uid=78_253 ignored - uid=78_254 ignored - uid=78_255 ignored - uid=78_256 generic - uid=78_257 generic - uid=78_258 ignored - uid=78_259 ignored - uid=78_260 list - uid=78_261 listitem level="1" - uid=78_262 ignored - uid=78_263 heading "LA HORDE" level="4" - uid=78_264 StaticText "LA HORDE" - uid=78_42 InlineTextBox "LA HORDE" - uid=78_265 image "La Horde" url="https://localhost:31000/systems/vermine2047/assets/images/ui/totems/horde.webp" - uid=78_266 navigation roledescription="Navigation dans l’onglet des feuilles de personnages" - uid=78_267 generic - uid=78_268 ignored - uid=78_269 StaticText "Caractéristiques et compétences" - uid=78_42 InlineTextBox "Caractéristiques " - uid=78_42 InlineTextBox "et compétences" - uid=78_270 generic - uid=78_271 ignored - uid=78_272 StaticText "Totem et ajustements" - uid=78_42 InlineTextBox "Totem et " - uid=78_42 InlineTextBox "ajustements" - uid=78_273 generic - uid=78_274 ignored - uid=78_275 StaticText "Matériel" - uid=78_42 InlineTextBox "Matériel" - uid=78_276 generic - uid=78_277 ignored - uid=78_278 StaticText "Histoire" - uid=78_42 InlineTextBox "Histoire" - uid=78_279 generic - uid=78_280 ignored - uid=78_281 StaticText "Combat et reserves" - uid=78_42 InlineTextBox "Combat " - uid=78_42 InlineTextBox "et " - uid=78_42 InlineTextBox "reserves" - uid=78_282 generic - uid=78_283 sectionheader - uid=78_284 generic - uid=78_285 heading "Nom Acteur (3)" level="1" - uid=78_286 LabelText - uid=78_287 StaticText "Nom" - uid=78_42 InlineTextBox "Nom" - uid=78_288 ignored - uid=78_289 StaticText "Acteur (3)" - uid=78_42 InlineTextBox "Acteur (3)" - uid=78_290 ignored - uid=78_291 LabelText - uid=78_292 StaticText "Profil" - uid=78_42 InlineTextBox "Profil" - uid=78_293 ignored - uid=78_294 ignored - uid=78_295 LabelText - uid=78_296 StaticText "Age" - uid=78_42 InlineTextBox "Age" - uid=78_297 ignored - uid=78_298 ignored - uid=78_299 StaticText "15" - uid=78_42 InlineTextBox "15" - uid=78_300 generic - uid=78_301 StaticText "(Jeune)" - uid=78_42 InlineTextBox "(Jeune)" - uid=78_302 generic - uid=78_303 heading "Totem La Horde" level="1" - uid=78_304 LabelText - uid=78_305 StaticText "Totem" - uid=78_42 InlineTextBox "Totem" - uid=78_306 generic - uid=78_307 StaticText "La Horde" - uid=78_42 InlineTextBox "La Horde" - uid=78_308 ignored - uid=78_309 LabelText - uid=78_310 StaticText "Réputation" - uid=78_42 InlineTextBox "Réputation" - uid=78_311 ignored - uid=78_312 StaticText "0" - uid=78_42 InlineTextBox "0" - uid=78_313 LabelText - uid=78_314 StaticText "Expérience" - uid=78_42 InlineTextBox "Expérience" - uid=78_315 ignored - uid=78_316 StaticText "0" - uid=78_42 InlineTextBox "0" - uid=78_317 heading "CARACTÉRISTIQUES" level="3" - uid=78_318 StaticText "CARACTÉRISTIQUES" - uid=78_42 InlineTextBox "CARACTÉRISTIQUES" - uid=78_319 ignored - uid=78_320 ignored - uid=78_321 heading "PHYSIQUE" level="4" - uid=78_322 StaticText "PHYSIQUE" - uid=78_42 InlineTextBox "PHYSIQUE" - uid=78_323 generic - uid=78_324 LabelText - uid=78_325 StaticText "Vigueur" - uid=78_42 InlineTextBox "Vigueur" - uid=78_326 generic - uid=78_327 LabelText - uid=78_328 StaticText "Santé" - uid=78_42 InlineTextBox "Santé" - uid=78_329 ignored - uid=78_330 heading "MANUEL" level="4" - uid=78_331 StaticText "MANUEL" - uid=78_42 InlineTextBox "MANUEL" - uid=78_332 generic - uid=78_333 LabelText - uid=78_334 StaticText "Précision" - uid=78_42 InlineTextBox "Précision" - uid=78_335 generic - uid=78_336 LabelText - uid=78_337 StaticText "Réflexes" - uid=78_42 InlineTextBox "Réflexes" - uid=78_338 ignored - uid=78_339 heading "MENTAL" level="4" - uid=78_340 StaticText "MENTAL" - uid=78_42 InlineTextBox "MENTAL" - uid=78_341 generic - uid=78_342 LabelText - uid=78_343 StaticText "Savoir" - uid=78_42 InlineTextBox "Savoir" - uid=78_344 generic - uid=78_345 LabelText - uid=78_346 StaticText "Perception" - uid=78_42 InlineTextBox "Perception" - uid=78_347 ignored - uid=78_348 heading "SOCIAL" level="4" - uid=78_349 StaticText "SOCIAL" - uid=78_42 InlineTextBox "SOCIAL" - uid=78_350 generic - uid=78_351 LabelText - uid=78_352 StaticText "Volonté" - uid=78_42 InlineTextBox "Volonté" - uid=78_353 generic - uid=78_354 LabelText - uid=78_355 StaticText "Empathie" - uid=78_42 InlineTextBox "Empathie" - uid=78_356 heading "COMPÉTENCES" level="3" - uid=78_357 StaticText "COMPÉTENCES" - uid=78_42 InlineTextBox "COMPÉTENCES" - uid=78_358 ignored - uid=78_359 ignored - uid=78_360 heading "L'HOMME" level="4" - uid=78_361 StaticText "L'HOMME" - uid=78_42 InlineTextBox "L'HOMME" - uid=78_362 generic - uid=78_363 LabelText - uid=78_364 StaticText "Arts " - uid=78_42 InlineTextBox "Arts " - uid=78_365 superscript - uid=78_366 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_367 generic - uid=78_368 LabelText - uid=78_369 StaticText "Civilisation " - uid=78_42 InlineTextBox "Civilisation " - uid=78_370 superscript - uid=78_371 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_372 generic - uid=78_373 LabelText - uid=78_374 StaticText "Psychologie " - uid=78_42 InlineTextBox "Psychologie " - uid=78_375 superscript - uid=78_376 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_377 generic - uid=78_378 LabelText - uid=78_379 StaticText "Rumeurs" - uid=78_42 InlineTextBox "Rumeurs" - uid=78_380 generic - uid=78_381 LabelText - uid=78_382 StaticText "Soins " - uid=78_42 InlineTextBox "Soins " - uid=78_383 superscript - uid=78_384 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_385 ignored - uid=78_386 heading "L'ANIMAL" level="4" - uid=78_387 StaticText "L'ANIMAL" - uid=78_42 InlineTextBox "L'ANIMAL" - uid=78_388 generic - uid=78_389 LabelText - uid=78_390 StaticText "Animalisme " - uid=78_42 InlineTextBox "Animalisme " - uid=78_391 superscript - uid=78_392 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_393 generic - uid=78_394 LabelText - uid=78_395 StaticText "Dissection " - uid=78_42 InlineTextBox "Dissection " - uid=78_396 superscript - uid=78_397 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_398 generic - uid=78_399 LabelText - uid=78_400 StaticText "Faune " - uid=78_42 InlineTextBox "Faune " - uid=78_401 superscript - uid=78_402 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_403 generic - uid=78_404 LabelText - uid=78_405 StaticText "Répulsion" - uid=78_42 InlineTextBox "Répulsion" - uid=78_406 generic - uid=78_407 LabelText - uid=78_408 StaticText "Pistage" - uid=78_42 InlineTextBox "Pistage" - uid=78_409 ignored - uid=78_410 heading "LA MACHINE" level="4" - uid=78_411 StaticText "LA MACHINE" - uid=78_42 InlineTextBox "LA MACHINE" - uid=78_412 generic - uid=78_413 LabelText - uid=78_414 StaticText "Artisanat " - uid=78_42 InlineTextBox "Artisanat " - uid=78_415 superscript - uid=78_416 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_417 generic - uid=78_418 LabelText - uid=78_419 StaticText "Bricolage" - uid=78_42 InlineTextBox "Bricolage" - uid=78_420 generic - uid=78_421 LabelText - uid=78_422 StaticText "Mécanique " - uid=78_42 InlineTextBox "Mécanique " - uid=78_423 superscript - uid=78_424 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_425 generic - uid=78_426 LabelText - uid=78_427 StaticText "Pilotage " - uid=78_42 InlineTextBox "Pilotage " - uid=78_428 superscript - uid=78_429 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_430 generic - uid=78_431 LabelText - uid=78_432 StaticText "Technologie " - uid=78_42 InlineTextBox "Technologie " - uid=78_433 superscript - uid=78_434 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_435 ignored - uid=78_436 heading "L'ARME" level="4" - uid=78_437 StaticText "L'ARME" - uid=78_42 InlineTextBox "L'ARME" - uid=78_438 generic - uid=78_439 LabelText - uid=78_440 StaticText "Armes à feu " - uid=78_42 InlineTextBox "Armes à feu " - uid=78_441 superscript - uid=78_442 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_443 generic - uid=78_444 LabelText - uid=78_445 StaticText "Tir à l'arc" - uid=78_42 InlineTextBox "Tir à l'arc" - uid=78_446 generic - uid=78_447 LabelText - uid=78_448 StaticText "Armurerie " - uid=78_42 InlineTextBox "Armurerie " - uid=78_449 superscript - uid=78_450 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_451 generic - uid=78_452 LabelText - uid=78_453 StaticText "Lancer" - uid=78_42 InlineTextBox "Lancer" - uid=78_454 generic - uid=78_455 LabelText - uid=78_456 StaticText "Mêlée" - uid=78_42 InlineTextBox "Mêlée" - uid=78_457 ignored - uid=78_458 heading "LA SURVIE" level="4" - uid=78_459 StaticText "LA SURVIE" - uid=78_42 InlineTextBox "LA SURVIE" - uid=78_460 generic - uid=78_461 LabelText - uid=78_462 StaticText "Vigilance" - uid=78_42 InlineTextBox "Vigilance" - uid=78_463 generic - uid=78_464 LabelText - uid=78_465 StaticText "Athlétisme" - uid=78_42 InlineTextBox "Athlétisme" - uid=78_466 generic - uid=78_467 LabelText - uid=78_468 StaticText "Alimentation" - uid=78_42 InlineTextBox "Alimentation" - uid=78_469 generic - uid=78_470 LabelText - uid=78_471 StaticText "Discrétion" - uid=78_42 InlineTextBox "Discrétion" - uid=78_472 generic - uid=78_473 LabelText - uid=78_474 StaticText "Corps-à-corps" - uid=78_42 InlineTextBox "Corps-à-corps" - uid=78_475 ignored - uid=78_476 heading "LA TERRE" level="4" - uid=78_477 StaticText "LA TERRE" - uid=78_42 InlineTextBox "LA TERRE" - uid=78_478 generic - uid=78_479 LabelText - uid=78_480 StaticText "Environnement " - uid=78_42 InlineTextBox "Environnement " - uid=78_481 superscript - uid=78_482 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_483 generic - uid=78_484 LabelText - uid=78_485 StaticText "Flore " - uid=78_42 InlineTextBox "Flore " - uid=78_486 superscript - uid=78_487 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_488 generic - uid=78_489 LabelText - uid=78_490 StaticText "Route" - uid=78_42 InlineTextBox "Route" - uid=78_491 generic - uid=78_492 LabelText - uid=78_493 StaticText "Toxiques " - uid=78_42 InlineTextBox "Toxiques " - uid=78_494 superscript - uid=78_495 StaticText "(II)" - uid=78_42 InlineTextBox "(II)" - uid=78_496 generic - uid=78_497 LabelText - uid=78_498 StaticText "Vestiges " - uid=78_42 InlineTextBox "Vestiges " - uid=78_499 superscript - uid=78_500 StaticText "(I)" - uid=78_42 InlineTextBox "(I)" - uid=78_501 ignored - uid=78_502 ignored - uid=78_503 ignored - uid=78_504 ignored - uid=78_505 ignored - uid=78_506 ignored - uid=78_507 ignored - uid=78_508 ignored - uid=78_509 ignored - uid=78_510 ignored - uid=78_511 ignored - uid=78_512 ignored - uid=78_513 ignored - uid=78_514 ignored - uid=78_515 ignored - uid=78_516 ignored - uid=78_517 ignored - uid=78_518 ignored - uid=78_519 ignored - uid=78_520 ignored - uid=78_521 ignored - uid=78_522 ignored - uid=78_523 ignored - uid=78_524 ignored - uid=78_525 ignored - uid=78_526 ignored - uid=78_527 ignored - uid=78_528 ignored - uid=78_529 ignored - uid=78_530 ignored - uid=78_531 ignored - uid=78_532 ignored - uid=78_533 ignored - uid=78_534 ignored - uid=78_535 ignored - uid=78_536 ignored - uid=78_537 ignored - uid=78_538 ignored - uid=78_539 ignored - uid=78_540 ignored - uid=78_541 ignored - uid=78_542 ignored - uid=78_543 ignored - uid=78_544 ignored - uid=78_545 ignored - uid=78_546 ignored - uid=78_547 ignored - uid=78_548 ignored - uid=78_549 ignored - uid=78_550 ignored - uid=78_551 ignored - uid=78_552 ignored - uid=78_553 ignored - uid=78_554 ignored - uid=78_555 generic diff --git a/inactive-tabs.png b/inactive-tabs.png deleted file mode 100644 index b5cc2a8..0000000 Binary files a/inactive-tabs.png and /dev/null differ diff --git a/lang/en.json b/lang/en.json index 410568a..06af754 100644 --- a/lang/en.json +++ b/lang/en.json @@ -18,6 +18,7 @@ "TYPES.Item.defense": "Defense", "TYPES.Actor.vehicle": "Vehicle", "TYPES.Item.ability": "Ability", + "TYPES.Item.creaturecapacity": "Creature capacity", "TYPES.Item.specialty": "Specialty", "TYPES.Item.background": "Background", "TYPES.Item.trauma": "Trauma", @@ -43,6 +44,20 @@ "nightmare": "Nightmare", "apocalypse": "Apocalypse" }, + "CREATURE_CAPACITY_TYPES": { + "base": { + "name": "Base" + }, + "survival": { + "name": "Survival" + }, + "nightmare": { + "name": "Nightmare" + }, + "apocalypse": { + "name": "Apocalypse" + } + }, "ROLLS": { "tool": "Dice Roller", "roll_dice": "Roll the dice" @@ -146,6 +161,7 @@ "pool": "Reserve", "pools": "Reserves", "dice_pool": "Dice pool", + "pool_malus": "Wound penalty", "auto_successes": "automatic successes", "self_control": "Self-control", "effort": "Effort", @@ -188,6 +204,8 @@ "maintenance": "Maintenance", "owner": "Owner", "no_vehicles": "No vehicles", + "no_encounters": "No encounters", + "travel_notes": "Travel notes", "rarity": "Rarity", "rarity_sm": "Rar.", "reliability": "Reliability", @@ -214,6 +232,7 @@ "boost": "Boost", "group_abilities": "Group abilities", "totem_abilities": "Totem abilities", + "creature_capacities": "Creature capacities", "type_group": "Group", "type_character": "Character", "type_npc": "NPC", @@ -327,6 +346,8 @@ "no_wound": "No wound", "apply_wound": "Apply wound", "wound_applied": "Wound applied", + "wound_escalated": "{to} wound (escalated from {from})", + "wound_death": "All wounds checked — death", "error_creature_no_defense": "Creatures cannot defend (passive defense)", "error_no_permission": "Insufficient permissions", "error_no_target": "No target selected for this exchange", @@ -418,6 +439,8 @@ "morale": "Morale", "needed": "Needed", "objective_placeholder": "eg: Survive, Explore", + "major_objective_placeholder": "eg: Reach a distant goal", + "minor_objective_placeholder": "eg: Find a medic, scavenge", "objectives": "Objectives", "pack": "Pack", "pattern": "Pattern", @@ -570,6 +593,8 @@ "ability": "Ability", "new_ability": "New ability", "abilities": "Abilities", + "creaturecapacity": "Creature capacity", + "new_creaturecapacity": "New creature capacity", "specialties": "Specialties", "new_specialty": "New specialty", "target": "Target", @@ -644,6 +669,11 @@ "dog": "Dog", "bear": "Bear" }, + "PACK_LEVELS": { + "small": "Small", + "large": "Large", + "giant": "Giant" + }, "TOTEMS": { "human": { "name": "Human", diff --git a/lang/fr.json b/lang/fr.json index 07e2fb6..bd9c146 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -10,6 +10,7 @@ "TYPES.Item.defense": "Protection", "TYPES.Actor.vehicle": "Véhicule", "TYPES.Item.ability": "Capacité", + "TYPES.Item.creaturecapacity": "Capacité de créature", "TYPES.Item.specialty": "Spécialité", "TYPES.Item.background": "Historique", "TYPES.Item.trauma": "Traumatisme", @@ -49,6 +50,20 @@ "nightmare": "Cauchemar", "apocalypse": "Apocalypse" }, + "CREATURE_CAPACITY_TYPES": { + "base": { + "name": "Base" + }, + "survival": { + "name": "Survie" + }, + "nightmare": { + "name": "Cauchemar" + }, + "apocalypse": { + "name": "Apocalypse" + } + }, "ROLLS": { "tool": "Lanceur de dés", "roll_dice": "Jeter les dés" @@ -153,6 +168,7 @@ "pools": "Réserves", "reserves": "Réserves", "dice_pool": "Pool de dés", + "pool_malus": "Malus Blessure", "auto_successes": "réussites automatiques", "self_control": "Sang-Froid", "effort": "Effort", @@ -269,6 +285,8 @@ "maintenance": "Entretien", "owner": "Propriétaire", "no_vehicles": "Aucun véhicule", + "no_encounters": "Aucune rencontre", + "travel_notes": "Notes de voyage", "rarity": "Rareté", "rarity_sm": "Rar.", "reliability": "Fiabilité", @@ -311,6 +329,8 @@ "no_wound": "Aucune blessure", "apply_wound": "Appliquer la blessure", "wound_applied": "Blessure appliquée", + "wound_escalated": "Blessure {to} (montée depuis {from})", + "wound_death": "Toutes les blessures sont cochées — mort", "error_creature_no_defense": "Les créatures ne peuvent pas se défendre (défense passive)", "error_no_permission": "Permissions insuffisantes", "error_no_target": "Aucune cible sélectionnée pour cet échange", @@ -405,6 +425,7 @@ "boost": "boost", "group_abilities": "Capacités de groupe", "totem_abilities": "Capacités de totem", + "creature_capacities": "Capacités de créature", "type_group": "Groupe", "type_character": "Personnage", "type_npc": "PNJ", @@ -431,6 +452,8 @@ "morale_low": "Bas", "morale_crisis": "Crise", "objective_placeholder": "Objectif...", + "major_objective_placeholder": "Objectif majeur...", + "minor_objective_placeholder": "Objectif mineur...", "instincts_placeholder": "Ex: Triompher, relever un défi...", "prohibits_placeholder": "Ex: Fuir, abandonner...", "error_unknown_actor": "Acteur inconnu", @@ -581,6 +604,8 @@ "ability": "Capacité", "new_ability": "Nouvelle capacité", "abilities": "Capacités", + "creaturecapacity": "Capacité de créature", + "new_creaturecapacity": "Nouvelle capacité de créature", "specialties": "Spécialités", "new_specialty": "Nouvelle spécialité", "target": "Cible", @@ -661,6 +686,11 @@ "dog": "Chien", "bear": "Ours" }, + "PACK_LEVELS": { + "small": "Petit", + "large": "Grand", + "giant": "Géant" + }, "TOTEMS": { "human": { "name": "L'Humain", diff --git a/less/actor/actor.less b/less/actor/actor.less index f63ef78..578d761 100644 --- a/less/actor/actor.less +++ b/less/actor/actor.less @@ -188,6 +188,42 @@ } } + // ── Stacked layout for creature sheets (header + tabs + content) ─── + &.creature .window-content { + display: grid; + grid-template-rows: auto auto 1fr; + grid-template-columns: 1fr; + overflow: hidden; + + > .tab.main { + grid-column: 1; + grid-row: 1; + display: flex !important; + flex-direction: column; + overflow-y: auto; + padding: 8px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + + > nav.tabs { + grid-column: 1; + grid-row: 2; + } + + > .tab:not(.main) { + grid-column: 1; + grid-row: 3; + display: none; + overflow-y: auto; + padding: 8px; + + &.active { + display: flex; + flex-direction: column; + } + } + } + form { display: flex; flex-direction: column; @@ -304,6 +340,34 @@ } } + // Fiche personnage (ApplicationV2 : l'élément fiche EST le
, le + // sélecteur "form div.hexa" ci-dessus ne s'y applique donc pas). + &.character div.hexa { + .hexa-style(); + .transition(); + margin: 0.2rem; + position: relative; + + &:hover { + .hexa-style(rgba(255, 255, 255, 0.425), rgba(0, 0, 0, 0.288)); + } + + input { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + z-index: 1; + margin: 0; + cursor: pointer; + } + + &.checked { + .hexa-style(rgb(0, 0, 0), rgba(0, 0, 0, 0.288)); + &:hover { .hexa-style(rgb(43, 43, 43), rgba(0, 0, 0, 0.288)); } + } + } + .sheet-header-toggle { text-align: right; margin-bottom: 0.5rem; diff --git a/less/actor/creature.less b/less/actor/creature.less index 7916ae4..5b9020a 100644 --- a/less/actor/creature.less +++ b/less/actor/creature.less @@ -5,7 +5,7 @@ .sheet-header { .background-image(url("@{ui-path}/barre_haut.webp"), no-repeat, 100% 100%, right top); padding: 10px; - max-height: 110px; + overflow: visible; } .header-fields { flex: 1; } @@ -13,6 +13,10 @@ .resource { .card-style(); + + // Le mixin card-style ajoute un margin-bottom (15px) : inutile dans le + // header, on le neutralise pour garder une hauteur compacte. + margin-bottom: 8px; } .resource-label { @@ -34,13 +38,20 @@ .charname { margin: 0; + height: auto; + font-size: @font-size-18; + line-height: 1.2; + span, input { - width: 100%; font-size: @font-size-18; font-weight: bold; text-align: center; } + + input { + width: 100%; + } } .stats-grid { @@ -116,4 +127,85 @@ gap: 8px; } + // ── Cases de blessures (hexagones) ────────────────────────────────── + // Le radio est masqué et recouvre l'hexagone : cliquer sur la case la coche. + div.hexa { + .hexa-style(); + .transition(); + margin: 0.2rem; + position: relative; + + &:hover { + .hexa-style(rgba(255, 255, 255, 0.425), rgba(0, 0, 0, 0.288)); + } + + input { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + z-index: 1; + margin: 0; + cursor: pointer; + } + + &.checked { + .hexa-style(rgb(0, 0, 0), rgba(0, 0, 0, 0.288)); + &:hover { .hexa-style(rgb(43, 43, 43), rgba(0, 0, 0, 0.288)); } + } + } + + // ── Capacités de créature ─────────────────────────────────────────── + .creature-list { + list-style: none; + margin: 0; + padding: 0; + + > li { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 6px; + border-bottom: 1px solid @color-border-dark-3; + + &:last-child { border-bottom: none; } + &:hover { box-shadow: 0 0 10px @theme-color-highlight inset; } + } + + .item-name { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: flex; + align-items: center; + gap: 8px; + + .item-roll { cursor: pointer; } + } + + .capacity-type { + flex: 0 0 auto; + font-size: @font-size-12; + color: @color-amber; + text-transform: uppercase; + } + + .item-controls { + flex: 0 0 auto; + display: flex; + gap: 6px; + } + } + + h4 { + a.item-control { + color: inherit; + opacity: 0.85; + + &:hover { opacity: 1; } + } + } + } diff --git a/less/actor/group.less b/less/actor/group.less index 8fed8a5..e589b9e 100644 --- a/less/actor/group.less +++ b/less/actor/group.less @@ -15,13 +15,112 @@ } } + // ── Titres de section : uniforme (centré, scotch, majuscules) ─────── h4 { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; font-family: "DistressBlack", sans-serif; text-transform: uppercase; font-size: @font-size-14; + text-align: center; + padding: 2px 8px; + margin: 0 0 8px; background: 50% 0% / cover no-repeat url("@{ui-path}/scotch.webp"); + + a { + color: inherit; + opacity: 0.85; + + &:hover { opacity: 1; } + } } + // ── Sous-titres (ex. Objectifs majeurs / mineurs) ─────────────────── + h5 { + font-family: "DistressBlack", sans-serif; + text-transform: uppercase; + font-size: @font-size-12; + color: @color-amber; + margin: 8px 0 4px; + text-align: left; + border-bottom: none; + } + + // ── Liste uniforme (objectifs, capacités, membres, rencontres) ────── + .group-list { + list-style: none; + margin: 0; + padding: 0; + + > li { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 6px; + border-bottom: 1px solid @color-border-dark-3; + + &:last-child { border-bottom: none; } + &:hover { box-shadow: 0 0 10px @theme-color-highlight inset; } + } + + > li.group-list-header { + font-weight: bold; + text-transform: uppercase; + font-size: @font-size-12; + border-bottom: 2px solid @color-border-dark-3; + box-shadow: none; + + > div { text-align: center; } + } + + .item-name, .actor-name { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .item-controls { + flex: 0 0 auto; + display: flex; + gap: 6px; + } + + input[type="text"] { + flex: 1; + min-width: 0; + } + } + + // ── Champs (Origine, Concept, Instincts, Interdits…) ──────────────── + .group-field { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; + + label { + flex: 0 0 auto; + font-weight: bold; + white-space: nowrap; + } + + > :last-child { + flex: 1; + min-width: 0; + } + + input[type="text"] { width: 100%; } + } + + // ── Colonnes des tableaux (Rencontres) ────────────────────────────── + .gcol-name { flex: 2; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .gcol-profile { flex: 3; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .gcol-totem { flex: 2; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .reserve-control, .morale-control { .card-style(); @@ -39,58 +138,13 @@ } } - .actor-list { - list-style: none; - padding: 0; - margin: 0; - - li.actor { - padding: 5px; - border-bottom: 1px solid @color-border-dark-3; - - &:last-child { border-bottom: none; } - - &:hover { - box-shadow: 0 0 10px @theme-color-highlight inset; - } - } - - .actor-name, .item-name { - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } - - .objective-item { - padding: 5px; - border-bottom: 1px solid @color-border-dark-4; - - input { - flex: 1; - width: 100%; - } - } - .totem-display { .card-style(); + flex: 1; span { font-weight: bold; } } - .identity-field { - margin-bottom: 8px; - - label { - font-weight: bold; - display: block; - margin-bottom: 3px; - } - - input { width: 100%; } - } - .level input, .reputation input { width: 60px; diff --git a/less/actor/npc.less b/less/actor/npc.less index f56fcf7..35b9848 100644 --- a/less/actor/npc.less +++ b/less/actor/npc.less @@ -5,7 +5,25 @@ .sheet-header { .background-image(url("@{ui-path}/barre_haut.webp"), no-repeat, 100% 100%, right top); padding: 0.5rem; - max-height: 150px; + overflow: visible; + } + + .charname { + margin: 0; + height: auto; + font-size: @font-size-18; + line-height: 1.2; + + span, + input { + font-size: @font-size-18; + font-weight: bold; + text-align: center; + } + + input { + width: 100%; + } } .ability-value, @@ -66,12 +84,19 @@ .npc-wounds { flex-wrap: wrap; + gap: 8px 16px; + margin-bottom: 8px; .wound-cat { display: inline-flex; align-items: center; gap: 4px; font-weight: bold; + + .wound-label { + font-size: @font-size-12; + white-space: nowrap; + } } .wound-boxes { @@ -82,6 +107,10 @@ font-size: 8px; color: @color-border-dark-2; } + + .hexa { + margin: 0; + } } } @@ -199,9 +228,25 @@ .hexa { .hexa-style(); .transition(); + position: relative; &:hover { .hexa-style(rgba(255, 255, 255, 0.425), rgba(0, 0, 0, 0.288)); } + + input { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + z-index: 1; + margin: 0; + cursor: pointer; + } + + &.checked { + .hexa-style(rgb(0, 0, 0), rgba(0, 0, 0, 0.288)); + &:hover { .hexa-style(rgb(43, 43, 43), rgba(0, 0, 0, 0.288)); } + } } } diff --git a/less/actor/vehicle.less b/less/actor/vehicle.less index 265c8ad..f4310b8 100644 --- a/less/actor/vehicle.less +++ b/less/actor/vehicle.less @@ -59,13 +59,17 @@ .sheet-header { .background-image(url("@{ui-path}/barre_haut.webp"), no-repeat, 100% 100%, right top); padding: 10px; - max-height: 130px; + overflow: visible; } .header-fields { flex: 1; } .resource { .card-style(); + + // Le mixin card-style ajoute un margin-bottom (15px) : inutile dans le + // header, on le neutralise pour garder une hauteur compacte. + margin-bottom: 8px; } .resource-label { @@ -92,13 +96,20 @@ .charname { margin: 0; + height: auto; + font-size: @font-size-18; + line-height: 1.2; + span, input { - width: 100%; font-size: @font-size-18; font-weight: bold; text-align: center; } + + input { + width: 100%; + } } .vehicle-owner { diff --git a/less/base.less b/less/base.less index f2fab58..bee9a8b 100644 --- a/less/base.less +++ b/less/base.less @@ -665,7 +665,11 @@ ol.chat-log { cursor: pointer; &:hover { transform: translateY(0.5rem); } } - &.success { border-bottom-color: @color-acid-green; } + &.success { + border-bottom-color: @color-acid-green; + border-bottom-width: 6px; + box-shadow: 0 0 8px fade(@color-acid-green, 55%); + } &.adapted::after { content: "adapté"; } &.human::after { content: "humain"; } &.rerolled { transform: translateY(0rem); } diff --git a/less/items.less b/less/items.less index 608468c..296ffe0 100644 --- a/less/items.less +++ b/less/items.less @@ -98,3 +98,14 @@ ol#chat-log div.item-card header img, ol.chat-log div.item-card header img { max-width: 30%; } + +// Icônes des cartes d'item envoyées au chat (ApplicationV2). +// Le template des cartes (templates/item/chatCards/parts/base.hbs) rend +// une pleine taille : on la plafonne à 64×64. +ol#chat-log .chat-card-img, +ol.chat-log .chat-card-img { + max-width: 64px; + max-height: 64px; + object-fit: contain; + flex: 0 0 auto; +} diff --git a/less/variables.less b/less/variables.less index a8d6109..b7f475d 100644 --- a/less/variables.less +++ b/less/variables.less @@ -138,7 +138,7 @@ @theme-color-highlight: #005a3c; // Couleurs insecte / organique -@color-acid-green: #6ab04c; +@color-acid-green: #1e7d32; @color-amber: #e8b84b; @color-chitin-dark: #2a2520; @color-hemolymph: #8b4513; diff --git a/module/applications/sheets/_module.mjs b/module/applications/sheets/_module.mjs index ad39a94..84ea577 100644 --- a/module/applications/sheets/_module.mjs +++ b/module/applications/sheets/_module.mjs @@ -11,6 +11,7 @@ export { VermineWeaponSheetV2, VermineDefenseSheetV2, VermineAbilitySheetV2, + VermineCreatureCapacitySheetV2, VermineSpecialtySheetV2, VermineBackgroundSheetV2, VermineTraumaSheetV2, diff --git a/module/applications/sheets/base-actor-sheet.mjs b/module/applications/sheets/base-actor-sheet.mjs index 6a0109f..d15b1b6 100644 --- a/module/applications/sheets/base-actor-sheet.mjs +++ b/module/applications/sheets/base-actor-sheet.mjs @@ -38,6 +38,7 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo roll: VermineBaseActorSheet.#onRollItem, attack: VermineBaseActorSheet.#onAttack, clickRadio: VermineBaseActorSheet.#onClickRadioHexa, + clickWound: VermineBaseActorSheet.#onClickWound, effectControl: VermineBaseActorSheet.#onEffectControl, chooseTotem: VermineBaseActorSheet.#onChooseTotem } @@ -264,9 +265,10 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo if (!id) return const item = this.document.items.get(id) if (!item) return - // Armes : PNJ → dialogue de combat (valeur d'Attaque) ; personnage → - // dialogue de compétence. Les PNJ n'ont ni caractéristiques ni compétences. - if (item.type === "weapon" && this.document.type === 'npc') { + // Armes : PNJ et créatures → dialogue de combat (valeur d'Attaque) ; + // personnage → dialogue de compétence. PNJ/créatures n'ont ni + // caractéristiques ni compétences. + if (item.type === "weapon" && (this.document.type === 'npc' || this.document.type === 'creature')) { const { default: CombatDialog } = await import("../../system/dialogs/combatDialog.mjs") const dialog = await CombatDialog.create({ actorId: this.document.id, weapon: item }) if (dialog) dialog.render(true) @@ -297,6 +299,8 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo } static async #onToggleEquip(event, target) { + event.preventDefault() + event.stopPropagation() const id = target.closest("[data-item-id]")?.dataset?.itemId if (!id) return const item = this.document.items.get(id) @@ -322,6 +326,36 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo this.document.update(update) } + /** + * Coche/décoche les cases de Blessure en respectant l'ordre de gravité + * (règles p.39) : on ne peut cocher que la case suivante dans l'ordre + * (une blessure s'applique toujours au Seuil égal ou inférieur le plus + * élevé), et on ne peut pas en sauter. Décocher une case retire toutes + * celles situées après elle. + */ + static #onClickWound(event, target) { + event.preventDefault() + event.stopPropagation() + const input = target + const box = parseInt(input.value, 10) || 0 // numéro de case (1-based) + let current = this.document + const propTree = input.name.split(".") + for (const prop of propTree) { + current = current[prop] + } + const currentValue = parseInt(current, 10) || 0 + let next = currentValue + if (box === currentValue + 1) { + // Cocher la case suivante dans l'ordre. + next = box + } else if (box <= currentValue) { + // Décocher : retire la case cliquée et toutes celles après. + next = box - 1 + } + // Si box > currentValue + 1 : on ne permet pas de sauter des cases. + this.document.update({ [input.name]: next }) + } + static #onEffectControl(event, target) { onManageActiveEffect(event, this.document) } diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index 106ec5f..625ecc1 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -4,7 +4,7 @@ export default class VermineCharacterSheetV2 extends VermineBaseActorSheet { static DEFAULT_OPTIONS = { classes: ["character"], - position: { width: 860, height: 720 }, + position: { width: 920, height: 720 }, window: { contentClasses: ["character-content"] }, actions: { addSpecialty: VermineCharacterSheetV2.#onAddSpecialty, diff --git a/module/applications/sheets/creature-sheet.mjs b/module/applications/sheets/creature-sheet.mjs index d1b9862..211747b 100644 --- a/module/applications/sheets/creature-sheet.mjs +++ b/module/applications/sheets/creature-sheet.mjs @@ -59,16 +59,25 @@ export default class VermineCreatureSheetV2 extends VermineBaseActorSheet { context.roleOptions = CONFIG.VERMINE.creatureRoleLevels context.sizeOptions = CONFIG.VERMINE.creatureSizeLevels context.packOptions = CONFIG.VERMINE.creaturePackLevels + context.sizeLabel = doc.system.size?.value !== undefined + ? game.i18n.localize(CONFIG.VERMINE.creatureSizeLevels[doc.system.size.value]?.label ?? "") + : "" + context.packLabel = doc.system.pack?.value + ? game.i18n.localize(CONFIG.VERMINE.creaturePackLevels[doc.system.pack.value]?.label ?? "") + : "" break case "info": context.tab = context.tabs.info + context.capacities = doc.itemTypes.creaturecapacity break case "stats": context.tab = context.tabs.stats context.patternLabel = doc.system.pattern?.value ? game.i18n.localize(CONFIG.VERMINE.creaturePatternLevels[doc.system.pattern.value]?.label ?? "") : "" context.sizeLabel = doc.system.size?.value !== undefined ? game.i18n.localize(CONFIG.VERMINE.creatureSizeLevels[doc.system.size.value]?.label ?? "") : "" context.roleLabel = doc.system.role?.value ? game.i18n.localize(CONFIG.VERMINE.creatureRoleLevels[doc.system.role.value]?.label ?? "") : "" - context.packLabel = doc.system.pack?.value || game.i18n.localize("VERMINE.none") + context.packLabel = doc.system.pack?.value + ? `${doc.system.pack.value} (${game.i18n.localize(CONFIG.VERMINE.creaturePackLevels[doc.system.pack.value]?.label ?? "")})` + : game.i18n.localize("VERMINE.none") // Contribution cumulée de la Taille (les modificateurs se cumulent : Taille N = somme 1..N) const sizeLevels = CONFIG.VERMINE.creatureSizeLevels || {} const sizeLevel = doc.system.size?.value ?? 0 @@ -97,11 +106,17 @@ export default class VermineCreatureSheetV2 extends VermineBaseActorSheet { return context } - /** @override - Les créatures n'ont pas de caractéristiques/compétences : on ouvre le dialogue d'attaque (pool calculé). */ + /** @override - Les créatures n'ont pas de caractéristiques/compétences : on ouvre le dialogue d'attaque (pool calculé) ou de Réaction. */ async _onRoll(event) { event.preventDefault() const el = event.currentTarget const type = el.dataset.type + if (type === "creature-reaction") { + const { default: NpcRollDialog } = await import("../../system/dialogs/npcRollDialog.mjs") + const dialog = await NpcRollDialog.create({ actorId: this.document.id, rolltype: "reaction" }) + if (dialog) dialog.render(true) + return + } if (type !== "creature-attack") return super._onRoll(event) const { default: CombatDialog } = await import("../../system/dialogs/combatDialog.mjs") const dialog = await CombatDialog.create({ actorId: this.document.id }) diff --git a/module/applications/sheets/group-sheet.mjs b/module/applications/sheets/group-sheet.mjs index ef5e55e..f3c3466 100644 --- a/module/applications/sheets/group-sheet.mjs +++ b/module/applications/sheets/group-sheet.mjs @@ -7,6 +7,7 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { position: { width: 700, height: 600 }, window: { contentClasses: ["group-content"] }, actions: { + chooseTotem: VermineGroupSheetV2.#onChooseTotem, chooseActor: VermineGroupSheetV2.#onChooseActor, deleteMember: VermineGroupSheetV2.#onDeleteMember, deleteEncounter: VermineGroupSheetV2.#onDeleteEncounter, @@ -56,9 +57,22 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { if (this.document.system.encounters?.length > 0) { for (const encId of this.document.system.encounters) { const a = game.actors.get(encId) - if (a) context.resolvedEncounters[encId] = { name: a.name, id: a.id } + if (a) { + context.resolvedEncounters[encId] = { + name: a.name, + id: a.id, + type: a.type, + profile: a.system?.identity?.profile || "", + totem: a.system?.identity?.totem || "" + } + } } } + // Notes de voyage (riche texte) + const roadNotes = this.document.system?.roadNotes + context.enrichedRoadNotes = roadNotes + ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(roadNotes, { async: true }) + : "" return context } @@ -70,10 +84,6 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { context.tab = context.tabs.info context.abilities = doc.itemTypes.ability.filter(i => i.system.type !== "totem") context.totem_abilities = doc.itemTypes.ability.filter(i => i.system.type === "totem") - context.specialties = doc.itemTypes.specialty - context.backgrounds = doc.itemTypes.background - context.traumas = doc.itemTypes.trauma - context.evolutions = doc.itemTypes.evolution break case "gear": context.tab = context.tabs.gear @@ -84,7 +94,6 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { break case "road": context.tab = context.tabs.road - context.vehicles = this.#getOwnedVehicles() break case "reserve": context.tab = context.tabs.reserve @@ -101,7 +110,8 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { // Actions : délégation aux applications AppV1 existantes pour TotemPicker/ActorPicker static async #onChooseTotem(event, target) { const { TotemPicker } = await import("../../system/applications.mjs") - new TotemPicker(target, this.document).render(true) + // Le Totem du Groupe remplit automatiquement Instincts/Interdits. + new TotemPicker(target, this.document, { fillInstincts: true }).render(true) } static async #onChooseActor(event, target) { const { ActorPicker } = await import("../../system/applications.mjs") diff --git a/module/applications/sheets/item-sheets.mjs b/module/applications/sheets/item-sheets.mjs index 17730a1..63b0762 100644 --- a/module/applications/sheets/item-sheets.mjs +++ b/module/applications/sheets/item-sheets.mjs @@ -24,6 +24,12 @@ export class VermineAbilitySheetV2 extends VermineBaseItemSheet { static PARTS = { main: { template: "systems/vermine2047/templates/item/item-ability-sheet.hbs", scrollable: [""] } } } +// ── Capacité de créature ──────────────────────────────────────────────── +export class VermineCreatureCapacitySheetV2 extends VermineBaseItemSheet { + static DEFAULT_OPTIONS = { classes: ["creaturecapacity"], position: { width: 560 } } + static PARTS = { main: { template: "systems/vermine2047/templates/item/item-creaturecapacity-sheet.hbs", scrollable: [""] } } +} + // ── Spécialité ──────────────────────────────────────────────────────── export class VermineSpecialtySheetV2 extends VermineBaseItemSheet { static DEFAULT_OPTIONS = { classes: ["specialty"], position: { width: 400 } } diff --git a/module/models/_module.mjs b/module/models/_module.mjs index 9de8d92..c73ab79 100644 --- a/module/models/_module.mjs +++ b/module/models/_module.mjs @@ -8,6 +8,7 @@ export { default as VermineWeaponData } from "./weapon.mjs" export { default as VermineDefenseData } from "./defense.mjs" export { default as VermineVehicleData } from "./vehicle.mjs" export { default as VermineAbilityData } from "./ability.mjs" +export { default as VermineCreatureCapacityData } from "./creaturecapacity.mjs" export { default as VermineSpecialtyData } from "./specialty.mjs" export { default as VermineBackgroundData } from "./background.mjs" export { default as VermineTraumaData } from "./trauma.mjs" diff --git a/module/models/creature.mjs b/module/models/creature.mjs index 486fb74..4587f17 100644 --- a/module/models/creature.mjs +++ b/module/models/creature.mjs @@ -130,8 +130,9 @@ export default class VermineCreatureData extends foundry.abstract.TypeDataModel // Vigueur : taille + meute this.computed.vigor = sizeVigor + (packConfig.damage || 0) - // Réaction : rôle - this.computed.reaction = (roleConfig.reaction || 0) + (roleConfig.reaction_bonus || 0) + // Réaction : rôle (le bonus de rôle est compté séparément et ajouté + // comme réussites automatiques par le NpcRollDialog — cf. modèle PNJ). + this.computed.reaction = roleConfig.reaction || 0 this.computed.reactionBonus = roleConfig.reaction_bonus || 0 // Réserves @@ -146,8 +147,13 @@ export default class VermineCreatureData extends foundry.abstract.TypeDataModel } /** - * Calcule les seuils de blessures à partir du patron, de la taille et de la meute. - * Les seuils sont la somme des valeurs correspondantes des trois sources. + * Calcule les seuils et les cercles de blessures à partir du patron, de la + * taille et de la meute. + * + * Règles (regles_creatures.txt) : + * - Seuil = contribution du Gabarit + contributions de Taille (cumulées). + * Le Groupe n'ajoute PAS de seuil (tableau « Groupe » : cercles seuls). + * - Cercles = cercles du Gabarit + cercles de Taille (cumulés) + cercles du Groupe. */ _calculateCreatureWoundThresholds() { const patternLevel = this.pattern?.value || 1 @@ -159,30 +165,27 @@ export default class VermineCreatureData extends foundry.abstract.TypeDataModel // Les modificateurs de Taille se cumulent (Taille N = somme des tailles 1..N). const sizeLevels = CONFIG.VERMINE.creatureSizeLevels || {} - let sizeMinor = 0 - let sizeMajor = 0 - let sizeDeadly = 0 + const sizeThresholds = { minor: 0, major: 0, deadly: 0 } + const sizeWounds = { minor: 0, major: 0, deadly: 0 } for (let i = 1; i <= sizeLevel; i++) { const cfg = sizeLevels[i] || {} - sizeMinor += cfg.minorWound || 0 - sizeMajor += cfg.majorWound || 0 - sizeDeadly += cfg.deadlyWound || 0 + sizeThresholds.minor += cfg.minorThreshold || 0 + sizeThresholds.major += cfg.majorThreshold || 0 + sizeThresholds.deadly += cfg.deadlyThreshold || 0 + sizeWounds.minor += cfg.minorWound || 0 + sizeWounds.major += cfg.majorWound || 0 + sizeWounds.deadly += cfg.deadlyWound || 0 } - this.minorWound.threshold = (patternConfig.minorWound || 0) - + sizeMinor - + (packConfig.minorWound || 0) - this.majorWound.threshold = (patternConfig.majorWound || 0) - + sizeMajor - + (packConfig.majorWound || 0) - this.deadlyWound.threshold = (patternConfig.deadlyWound || 0) - + sizeDeadly - + (packConfig.deadlyWound || 0) + // Seuils : gabarit + taille cumulée (pas de contribution du groupe). + this.minorWound.threshold = (patternConfig.minorThreshold ?? 0) + sizeThresholds.minor + this.majorWound.threshold = (patternConfig.majorThreshold ?? 0) + sizeThresholds.major + this.deadlyWound.threshold = (patternConfig.deadlyThreshold ?? 0) + sizeThresholds.deadly - // Max de blessures - this.minorWound.max = Math.min(5, this.minorWound.threshold + 2) - this.majorWound.max = Math.min(4, this.majorWound.threshold + 1) - this.deadlyWound.max = Math.min(2, this.deadlyWound.threshold) + // Cercles : gabarit + taille cumulée + groupe. + this.minorWound.max = (patternConfig.minorWound ?? 0) + sizeWounds.minor + (packConfig.minorWound ?? 0) + this.majorWound.max = (patternConfig.majorWound ?? 0) + sizeWounds.major + (packConfig.majorWound ?? 0) + this.deadlyWound.max = (patternConfig.deadlyWound ?? 0) + sizeWounds.deadly + (packConfig.deadlyWound ?? 0) } /** diff --git a/module/models/creaturecapacity.mjs b/module/models/creaturecapacity.mjs new file mode 100644 index 0000000..0dd316e --- /dev/null +++ b/module/models/creaturecapacity.mjs @@ -0,0 +1,19 @@ +import { listItemSchema } from "./_shared.mjs" + +/** + * DataModel pour les items de type "creaturecapacity" (capacités de créature). + * @augments {foundry.abstract.TypeDataModel} + */ +export default class VermineCreatureCapacityData extends foundry.abstract.TypeDataModel { + /** @override */ + static LOCALIZATION_PREFIXES = ["VERMINE.item.creaturecapacity"] + + /** @override */ + static defineSchema() { + const fields = foundry.data.fields + return { + ...listItemSchema(), + type: new fields.StringField({ required: true, initial: "base" }) + } + } +} diff --git a/module/models/group.mjs b/module/models/group.mjs index a12133e..61c0433 100644 --- a/module/models/group.mjs +++ b/module/models/group.mjs @@ -42,6 +42,9 @@ export default class VermineGroupData extends foundry.abstract.TypeDataModel { // Équipement equipment: equipmentSchema(), + // Notes de voyage (lieux, dangers, routes…) + roadNotes: new fields.HTMLField({ required: true, initial: "" }), + // Niveau du groupe (1-10) level: levelSchema(1, 1, 10), diff --git a/module/system/applications.mjs b/module/system/applications.mjs index 2714f1d..f443af2 100644 --- a/module/system/applications.mjs +++ b/module/system/applications.mjs @@ -2,10 +2,11 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api export class TotemPicker extends HandlebarsApplicationMixin(ApplicationV2) { - constructor(linkEl, actor) { + constructor(linkEl, actor, options = {}) { super(); this.linkEl = linkEl; this.actor = actor; + this.fillInstincts = options.fillInstincts === true; } static get DEFAULT_OPTIONS() { @@ -32,7 +33,17 @@ export class TotemPicker extends HandlebarsApplicationMixin(ApplicationV2) { el.addEventListener('click', event => { const link = event.target.closest('a'); if (!link?.dataset.totem) return; - this.actor.update({ 'system.identity.totem': link.dataset.totem }); + const update = { 'system.identity.totem': link.dataset.totem }; + // Remplit automatiquement Instincts/Interdits depuis la config du totem + // (utilisé pour le Totem du Groupe). + if (this.fillInstincts && this.actor.system?.identity) { + const totemKey = link.dataset.totem; + const instincts = game.i18n.localize(`TOTEMS.${totemKey}.instincts`); + const bans = game.i18n.localize(`TOTEMS.${totemKey}.bans`); + if (!instincts.startsWith("TOTEMS.")) update['system.identity.instincts'] = instincts; + if (!bans.startsWith("TOTEMS.")) update['system.identity.prohibits'] = bans; + } + this.actor.update(update); this.close(); }); }); diff --git a/module/system/config.mjs b/module/system/config.mjs index e56b1cf..fd9c59c 100644 --- a/module/system/config.mjs +++ b/module/system/config.mjs @@ -129,30 +129,30 @@ VERMINE.npcRoleLevels = { * Creature Pattern Levels configuration */ VERMINE.creaturePatternLevels = { - 1: { "label": "PATTERN_LEVELS.insect", "attack": 2, "damage": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, - 2: { "label": "PATTERN_LEVELS.rat", "attack": 3, "damage": 1, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, - 3: { "label": "PATTERN_LEVELS.dog", "attack": 4, "damage": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, - 4: { "label": "PATTERN_LEVELS.bear", "attack": 6, "damage": 6, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 } + 1: { "label": "PATTERN_LEVELS.insect", "attack": 2, "damage": 0, "minorThreshold": 0, "majorThreshold": 0, "deadlyThreshold": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, + 2: { "label": "PATTERN_LEVELS.rat", "attack": 3, "damage": 1, "minorThreshold": 0, "majorThreshold": 1, "deadlyThreshold": 3, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, + 3: { "label": "PATTERN_LEVELS.dog", "attack": 4, "damage": 3, "minorThreshold": 1, "majorThreshold": 3, "deadlyThreshold": 5, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, + 4: { "label": "PATTERN_LEVELS.bear", "attack": 6, "damage": 6, "minorThreshold": 3, "majorThreshold": 5, "deadlyThreshold": 7, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 } } /** * Creature Size Levels configuration */ VERMINE.creatureSizeLevels = { - 0: { "label": "SIZE_LEVELS.tiny", "attack": 0, "vigor": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 0 }, - 1: { "label": "SIZE_LEVELS.small", "attack": 1, "vigor": 1, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, - 2: { "label": "SIZE_LEVELS.medium", "attack": 2, "vigor": 2, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 }, - 3: { "label": "SIZE_LEVELS.large", "attack": 3, "vigor": 3, "minorWound": 3, "majorWound": 3, "deadlyWound": 3 } + 0: { "label": "SIZE_LEVELS.tiny", "attack": 0, "vigor": 0, "minorThreshold": 0, "majorThreshold": 0, "deadlyThreshold": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 0 }, + 1: { "label": "SIZE_LEVELS.small", "attack": 1, "vigor": 1, "minorThreshold": 0, "majorThreshold": 1, "deadlyThreshold": 1, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, + 2: { "label": "SIZE_LEVELS.medium", "attack": 2, "vigor": 2, "minorThreshold": 2, "majorThreshold": 2, "deadlyThreshold": 2, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, + 3: { "label": "SIZE_LEVELS.large", "attack": 3, "vigor": 3, "minorThreshold": 3, "majorThreshold": 3, "deadlyThreshold": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 } } /** * Creature Pack Levels configuration */ VERMINE.creaturePackLevels = { - 0: { "attack": 0, "damage": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 0 }, - 1: { "attack": 1, "damage": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, - 2: { "attack": 2, "damage": 2, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 }, - 3: { "attack": 5, "damage": 5, "minorWound": 3, "majorWound": 3, "deadlyWound": 3 } + 0: { "label": "VERMINE.none", "attack": 0, "damage": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 0 }, + 1: { "label": "PACK_LEVELS.small", "attack": 1, "damage": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, + 2: { "label": "PACK_LEVELS.large", "attack": 2, "damage": 2, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 }, + 3: { "label": "PACK_LEVELS.giant", "attack": 5, "damage": 5, "minorWound": 3, "majorWound": 3, "deadlyWound": 3 } } /** @@ -180,6 +180,25 @@ VERMINE.abilityCategories = { } } +/** + * Types de Capacités de créature (mode d'activation/disponibilité). + * Correspond aux Modes de jeu + une catégorie "base". + */ +VERMINE.creatureCapacityTypes = { + "base": { + "label": "CREATURE_CAPACITY_TYPES.base" + }, + "survival": { + "label": "CREATURE_CAPACITY_TYPES.survival" + }, + "nightmare": { + "label": "CREATURE_CAPACITY_TYPES.nightmare" + }, + "apocalypse": { + "label": "CREATURE_CAPACITY_TYPES.apocalypse" + } +} + VERMINE.abilities = { "vigor": "ABILITIES.vigor.name", "health": "ABILITIES.health.name", diff --git a/module/system/dialogs/combatDialog.mjs b/module/system/dialogs/combatDialog.mjs index b067f4e..0309a32 100644 --- a/module/system/dialogs/combatDialog.mjs +++ b/module/system/dialogs/combatDialog.mjs @@ -260,8 +260,9 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app const toolsChecked = this.#el.querySelector("input[name='usingTools']:checked"); const tooling = toolsChecked && toolsChecked.value !== "0" ? 1 : 0; const group = parseInt(this.#el.querySelector("#group")?.value, 10) || 0; - const total = this.basePool + selfControl + pools + specialty + help + tooling + group; - return { ability, skill, selfControl, pools, specialty, help, tooling, group, total }; + const malus = VermineExchange.woundMalus(this.actor); + const total = Math.max(0, this.basePool + selfControl + pools + specialty + help + tooling + group - malus); + return { ability, skill, selfControl, pools, specialty, help, tooling, group, malus, total }; } getDicePool() { @@ -297,7 +298,7 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app const b = this.getPoolBreakdown(); const bonusEl = this.#el.querySelector("#total-bonus"); - if (bonusEl) bonusEl.textContent = b.selfControl + b.pools + b.specialty + b.help + b.tooling + b.group; + if (bonusEl) bonusEl.textContent = b.selfControl + b.pools + b.specialty + b.help + b.tooling + b.group - b.malus; const handSel = this.#el.querySelector("#handicap"); const handEl = this.#el.querySelector("#current-handicap"); @@ -367,7 +368,7 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app : null }; - await VermineUtils.roll({ + const rollParams = { actor: this.actor, NoD: this.getDicePool(), Reroll: this.getReroll(), @@ -387,9 +388,13 @@ export default class CombatDialog extends HandlebarsApplicationMixin(foundry.app targets: targets.map(t => t.name), attack, messageFlags: { "vermine-exchange": attack } - }); + }; + // Fermeture immédiate du dialogue : le jet (et l'animation 3D) continue + // en arrière-plan sans bloquer la fermeture. this.close(); + + await VermineUtils.roll(rollParams); } #getRangeKey() { diff --git a/module/system/dialogs/npcRollDialog.mjs b/module/system/dialogs/npcRollDialog.mjs index 7d7826c..6087612 100644 --- a/module/system/dialogs/npcRollDialog.mjs +++ b/module/system/dialogs/npcRollDialog.mjs @@ -1,4 +1,5 @@ import { VermineUtils } from "../roll.mjs" +import { VermineExchange } from "../exchange.mjs" const { HandlebarsApplicationMixin } = foundry.applications.api @@ -161,7 +162,8 @@ export default class NpcRollDialog extends HandlebarsApplicationMixin(foundry.ap getPoolBreakdown() { const help = this.#getHelped() const group = this.#getGroup() - return { pool: this.pool, help, group, total: this.pool + help + group } + const malus = VermineExchange.woundMalus(this.#actor) + return { pool: this.pool, help, group, malus, total: Math.max(0, this.pool + help + group - malus) } } #updateUI() { @@ -169,7 +171,7 @@ export default class NpcRollDialog extends HandlebarsApplicationMixin(foundry.ap const totalEl = this.#el.querySelector("#dice-pool-total") if (totalEl) totalEl.textContent = `${b.total}D` const bonusEl = this.#el.querySelector("#total-bonus") - if (bonusEl) bonusEl.textContent = b.help + b.group + if (bonusEl) bonusEl.textContent = b.help + b.group - b.malus const freeEl = this.#el.querySelector("#free-successes") if (freeEl) freeEl.textContent = String(this.freeSuccesses) } @@ -191,7 +193,7 @@ export default class NpcRollDialog extends HandlebarsApplicationMixin(foundry.ap : game.i18n.localize("VERMINE.defense_esquive")) : this.label - await VermineUtils.roll({ + const rollParams = { actor: this.#actor, NoD: this.getPoolBreakdown().total, Reroll: this.rerolls, @@ -201,8 +203,12 @@ export default class NpcRollDialog extends HandlebarsApplicationMixin(foundry.ap bonusSuccesses: this.freeSuccesses, poolBreakdown: this.getPoolBreakdown(), messageFlags: this.defense ? { "vermine-defense": this.defense } : null - }) + } + // Fermeture immédiate du dialogue : le jet (et l'animation 3D) continue + // en arrière-plan sans bloquer la fermeture. this.close() + + await VermineUtils.roll(rollParams) } } diff --git a/module/system/dialogs/rollDialog.mjs b/module/system/dialogs/rollDialog.mjs index 5e2bf54..92d6802 100644 --- a/module/system/dialogs/rollDialog.mjs +++ b/module/system/dialogs/rollDialog.mjs @@ -1,4 +1,5 @@ import { VermineUtils } from "../roll.mjs"; +import { VermineExchange } from "../exchange.mjs"; const { HandlebarsApplicationMixin } = foundry.applications.api; @@ -164,8 +165,9 @@ export default class RollDialog extends HandlebarsApplicationMixin(foundry.appli const specialty = specChecked ? 1 : 0; const help = helped ? 1 : 0; const tooling = tools ? 1 : 0; - const total = ability + skillPool + selfControl + specialty + help + tooling + group + experience; - return { ability, skill: skillPool, selfControl, specialty, help, tooling, group, experience, total }; + const malus = VermineExchange.woundMalus(this.#actor); + const total = Math.max(0, ability + skillPool + selfControl + specialty + help + tooling + group + experience - malus); + return { ability, skill: skillPool, selfControl, specialty, help, tooling, group, experience, malus, total }; } getDicePool() { @@ -293,7 +295,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(foundry.appli #calculateBonusCount() { const b = this.getPoolBreakdown(); - return b.specialty + b.help + b.tooling + b.group + b.selfControl + b.experience; + return b.specialty + b.help + b.tooling + b.group + b.selfControl + b.experience - b.malus; } #refreshExperienceUI() { @@ -448,7 +450,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(foundry.appli await group.update({ "system.experience.dice": groupPool - pulled }); } - await VermineUtils.roll({ + const rollParams = { actor: this.#actor, NoD: this.getDicePool(), Reroll: this.getReroll(), @@ -467,9 +469,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(foundry.appli weapon: this.weapon?.toObject() ?? null, targets: [...game.user.targets].map(t => t.name), messageFlags: this.defense ? { "vermine-defense": this.defense } : null - }); + }; + // Fermeture immédiate du dialogue : le jet (et l'animation 3D) continue + // en arrière-plan sans bloquer la fermeture. this.close(); + + await VermineUtils.roll(rollParams); } } diff --git a/module/system/exchange.mjs b/module/system/exchange.mjs index 00f514c..cb294c7 100644 --- a/module/system/exchange.mjs +++ b/module/system/exchange.mjs @@ -204,20 +204,52 @@ export class VermineExchange { return Boolean(actor) && (game.user.isGM || actor.isOwner) } + /** Ordre de gravité des blessures (croissant). */ + static WOUND_ORDER = ['minorWound', 'majorWound', 'deadlyWound'] + + /** Malus de la pire blessure (règles p.42) : -1D Légère, -2D Grave, -3D Mortelle. */ + static WOUND_MALUS = { minorWound: 1, majorWound: 2, deadlyWound: 3 } + /** - * Applique +1 dans la catégorie de blessure indiquée (plafonné au max). + * Malus de blessure applicable à toutes les actions : seul le Malus de la + * Blessure la plus grave compte (non cumulatif). + * @param {Actor} actor + * @returns {number} 0, 1, 2 ou 3 + */ + static woundMalus(actor) { + if (!actor?.system) return 0 + if (actor.system.deadlyWound?.value > 0) return 3 + if (actor.system.majorWound?.value > 0) return 2 + if (actor.system.minorWound?.value > 0) return 1 + return 0 + } + + /** + * Applique +1 cercle de blessure, en montant en gravité si les cercles du + * niveau correspondant sont déjà pleins (règles p.42 : si tous les cercles + * d'une Blessure sont cochés, la suivante est de gravité supérieure). * @param {Actor} actor * @param {string} woundCategory 'minorWound' | 'majorWound' | 'deadlyWound' - * @returns {Promise} nouvelle valeur, ou false si refusé + * @returns {Promise} + * - false si refusé (permissions) ou null si invalide + * - { category, value, escalated, death } si appliqué (death si tout est plein) */ static async applyWound(actor, woundCategory) { if (!actor || !woundCategory) return null if (!this.canApplyWound(actor)) return false - const current = actor.system?.[woundCategory]?.value || 0 - const max = actor.system?.[woundCategory]?.max ?? Number.POSITIVE_INFINITY - const next = Math.min(current + 1, max) - await actor.update({ [`system.${woundCategory}.value`]: next }) - return next + const startIdx = this.WOUND_ORDER.indexOf(woundCategory) + if (startIdx === -1) return null + for (let i = startIdx; i < this.WOUND_ORDER.length; i++) { + const cat = this.WOUND_ORDER[i] + const sys = actor.system?.[cat] + const max = sys?.max ?? Number.POSITIVE_INFINITY + const value = sys?.value || 0 + if (value < max) { + await actor.update({ [`system.${cat}.value`]: value + 1 }) + return { category: cat, value: value + 1, escalated: cat !== woundCategory, death: false } + } + } + return { category: woundCategory, value: null, escalated: false, death: true } } // ── Résolution ────────────────────────────────────────────────────── @@ -457,10 +489,18 @@ export class VermineExchange { ui.notifications.warn(game.i18n.localize('VERMINE.error_no_permission')) return } - const next = await this.applyWound(defender, wound) - if (next === false) return + const result = await this.applyWound(defender, wound) + if (result === false) return btn.disabled = true - btn.innerHTML = ` ${game.i18n.localize('VERMINE.wound_applied')}` + let label = game.i18n.localize('VERMINE.wound_applied') + if (result?.death) { + label = game.i18n.localize('VERMINE.wound_death') + } else if (result?.escalated) { + const from = game.i18n.localize(this.woundLabelKey(wound)) + const to = game.i18n.localize(this.woundLabelKey(result.category)) + label = game.i18n.format('VERMINE.wound_escalated', { from, to }) + } + btn.innerHTML = ` ${label}` // Persiste l'état du bouton seulement si l'utilisateur peut modifier le message if (game.user.isGM || attackMessage.isOwner) { const msgEl = btn.closest('.vermine-roll-message') diff --git a/module/system/handlebars-manager.mjs b/module/system/handlebars-manager.mjs index 16dfb54..5b81fc5 100644 --- a/module/system/handlebars-manager.mjs +++ b/module/system/handlebars-manager.mjs @@ -367,6 +367,17 @@ export const registerHandlebarsHelpers = function () { Handlebars.registerHelper('ifStartsWith', function (arg1, arg2, options) { return (typeof arg1 === 'string' && arg1.startsWith(arg2)) ? options.fn(this) : options.inverse(this); }); + // Chiffre → chiffre romain (handicaps, entraves). 0 → chaîne vide. + Handlebars.registerHelper('roman', function (n) { + const table = [[10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I']] + let num = Number(n) + if (!Number.isFinite(num) || num <= 0) return '' + let out = '' + for (const [v, s] of table) { + while (num >= v) { out += s; num -= v } + } + return out + }); //math operations diff --git a/module/vermine2047.mjs b/module/vermine2047.mjs index 66f764c..ce55751 100644 --- a/module/vermine2047.mjs +++ b/module/vermine2047.mjs @@ -53,6 +53,7 @@ Hooks.once('init', async function () { CONFIG.Item.dataModels.weapon = models.VermineWeaponData; CONFIG.Item.dataModels.defense = models.VermineDefenseData; CONFIG.Item.dataModels.ability = models.VermineAbilityData; + CONFIG.Item.dataModels.creaturecapacity = models.VermineCreatureCapacityData; CONFIG.Item.dataModels.specialty = models.VermineSpecialtyData; CONFIG.Item.dataModels.background = models.VermineBackgroundData; CONFIG.Item.dataModels.trauma = models.VermineTraumaData; @@ -119,6 +120,9 @@ Hooks.once('init', async function () { foundry.documents.collections.Items.registerSheet("vermine2047", sheets.VermineAbilitySheetV2, { types: ["ability"], makeDefault: true }) + foundry.documents.collections.Items.registerSheet("vermine2047", sheets.VermineCreatureCapacitySheetV2, { + types: ["creaturecapacity"], makeDefault: true + }) foundry.documents.collections.Items.registerSheet("vermine2047", sheets.VermineSpecialtySheetV2, { types: ["specialty"], makeDefault: true }) diff --git a/screenshot-initial.png b/screenshot-initial.png deleted file mode 100644 index 61b1b70..0000000 Binary files a/screenshot-initial.png and /dev/null differ diff --git a/screenshot-weapon.png b/screenshot-weapon.png deleted file mode 100644 index b48d100..0000000 Binary files a/screenshot-weapon.png and /dev/null differ diff --git a/system.json b/system.json index d7333bd..f1ebd3f 100644 --- a/system.json +++ b/system.json @@ -33,7 +33,7 @@ "Actor": { "character": { "htmlFields": ["equipment.description", "identity.biography", "identity.relations"] }, "npc": { "htmlFields": ["equipment.description", "identity.notes"] }, - "group": { "htmlFields": ["equipment.description", "identity.notes"] }, + "group": { "htmlFields": ["equipment.description", "identity.notes", "roadNotes"] }, "creature": { "htmlFields": ["equipment.description", "identity.notes", "identity.biography"] }, "community": { "htmlFields": ["identity.notes", "location.landmarks", "location.territory", "history.events", "history.relations"] }, "vehicle": { "htmlFields": ["identity.notes"] } @@ -43,6 +43,7 @@ "weapon": { "htmlFields": ["description"] }, "defense": { "htmlFields": ["description"] }, "ability": { "htmlFields": ["description"] }, + "creaturecapacity": { "htmlFields": ["description"] }, "specialty": {}, "background": { "htmlFields": ["description"] }, "trauma": { "htmlFields": ["description"] }, diff --git a/templates/actor/appv2/character-combat.hbs b/templates/actor/appv2/character-combat.hbs index be302f7..4483788 100644 --- a/templates/actor/appv2/character-combat.hbs +++ b/templates/actor/appv2/character-combat.hbs @@ -127,7 +127,7 @@ name="system.minorWound.value" value="{{@minorwoundmax}}" data-wound="minorWound" - data-action="clickRadio" + data-action="clickWound" class=" {{#iflteq @minorwoundmax @root.system.minorWound.value }} checked @@ -156,7 +156,7 @@ name="system.majorWound.value" value="{{@majourwoundmax}}" data-wound="majorWound" - data-action="clickRadio" + data-action="clickWound" class=" {{#iflteq @majourwoundmax @root.system.majorWound.value }} checked @@ -188,7 +188,7 @@ name="system.deadlyWound.value" value="{{@deadlywoundmax}}" data-wound="deadlyWound" - data-action="clickRadio" + data-action="clickWound" class=" {{#iflteq @deadlywoundmax @root.system.deadlyWound.value }} checked {{/iflteq}} diff --git a/templates/actor/appv2/character-totem.hbs b/templates/actor/appv2/character-totem.hbs index 53c4540..d7f6990 100644 --- a/templates/actor/appv2/character-totem.hbs +++ b/templates/actor/appv2/character-totem.hbs @@ -54,7 +54,7 @@ data-tooltip="niveau">{{item.system.level.value}} - {{item.system.learn.threshold}}/{{item.system.learn.hindrance}} + {{item.system.learn.threshold}}{{#ifgt item.system.learn.hindrance 0}}/{{ roman item.system.learn.hindrance }}{{/ifgt}}
diff --git a/templates/actor/appv2/creature-combat.hbs b/templates/actor/appv2/creature-combat.hbs index 210906f..6e5ac16 100644 --- a/templates/actor/appv2/creature-combat.hbs +++ b/templates/actor/appv2/creature-combat.hbs @@ -39,31 +39,43 @@
  • {{ localize 'VERMINE.wounds.light' }} ({{ system.minorWound.threshold }}D) - {{#repeat system.minorWound.max }} - - {{/repeat}} +
    + {{#repeat system.minorWound.max 1 "minorwoundmax"}} +
    + +
    + {{/repeat}} +
  • {{ localize 'VERMINE.wounds.heavy' }} ({{ system.majorWound.threshold }}D) - {{#repeat system.majorWound.max }} - - {{/repeat}} +
    + {{#repeat system.majorWound.max 1 "majorwoundmax"}} +
    + +
    + {{/repeat}} +
  • {{ localize 'VERMINE.wounds.deadly' }} ({{ system.deadlyWound.threshold }}D) - {{#repeat system.deadlyWound.max }} - - {{/repeat}} +
    + {{#repeat system.deadlyWound.max 1 "deadlywoundmax"}} +
    + +
    + {{/repeat}} +
diff --git a/templates/actor/appv2/creature-info.hbs b/templates/actor/appv2/creature-info.hbs index c40cafb..9b226da 100644 --- a/templates/actor/appv2/creature-info.hbs +++ b/templates/actor/appv2/creature-info.hbs @@ -38,6 +38,27 @@ + {{!-- Capacités de créature --}} +
+

{{ localize 'VERMINE.creature_capacities' }}{{#if isEditMode}}{{/if}}

+
    + {{#each capacities as |item id|}} +
  1. +
    + {{item.name}} + {{ smarttl "CREATURE_CAPACITY_TYPES" item.system.type }} +
    +
    + {{#if @root.isEditMode}} + + + {{/if}} +
    +
  2. + {{/each}} +
+
+

{{ localize 'IDENTITY.notes' }}

diff --git a/templates/actor/appv2/creature-main.hbs b/templates/actor/appv2/creature-main.hbs index 28b5db5..992fe22 100644 --- a/templates/actor/appv2/creature-main.hbs +++ b/templates/actor/appv2/creature-main.hbs @@ -61,12 +61,12 @@ {{else}} - {{system.size.value}} + {{#if (ne system.size.value "0")}}{{system.size.value}} ({{localize sizeLabel}}){{else}}{{localize 'VERMINE.none'}}{{/if}} {{/if}}
@@ -75,17 +75,17 @@
{{#if isEditMode}} {{else}} - {{system.pack.value}} + {{#if system.pack.value}}{{system.pack.value}} ({{localize packLabel}}){{else}}{{ localize 'VERMINE.none' }}{{/if}} {{/if}}
diff --git a/templates/actor/appv2/creature-stats.hbs b/templates/actor/appv2/creature-stats.hbs index 697f455..3355cc3 100644 --- a/templates/actor/appv2/creature-stats.hbs +++ b/templates/actor/appv2/creature-stats.hbs @@ -7,6 +7,12 @@ {{ system.computed.attack }} + {{!-- Réaction (lancable) --}} + +

{{ localize 'ADVERSITY.pattern' }}: {{ patternLabel }}

diff --git a/templates/actor/appv2/group-gear.hbs b/templates/actor/appv2/group-gear.hbs index 64561bc..70a9ec6 100644 --- a/templates/actor/appv2/group-gear.hbs +++ b/templates/actor/appv2/group-gear.hbs @@ -33,7 +33,7 @@

{{ localize 'IDENTITY.notes'}}

- {{editor system.equipment.description target="system.equipment.description" button=true owner=owner editable=editable}} + {{formInput systemFields.equipment.fields.description enriched=enrichedEquipmentNotes value=system.equipment.description name="system.equipment.description" toggled=true}}

{{localize 'ITEMS.weapons'}}

diff --git a/templates/actor/appv2/group-info.hbs b/templates/actor/appv2/group-info.hbs index 5a3329c..ec6a7b0 100644 --- a/templates/actor/appv2/group-info.hbs +++ b/templates/actor/appv2/group-info.hbs @@ -1,13 +1,11 @@
- {{!-- Group Identity --}} - + {{!-- Origine / Concept --}}

{{ localize 'IDENTITY.origin' }}

-
+
{{#if isEditMode}} - + {{else}} {{system.identity.origin}} {{/if}} @@ -16,40 +14,122 @@

{{ localize 'IDENTITY.theme' }}

-
+
{{#if isEditMode}} - + {{else}} {{system.identity.theme}} {{/if}}
- {{!-- Group Notes --}} + {{!-- Notes --}}
-
-

{{ localize 'IDENTITY.notes' }}

- {{formInput systemFields.identity.fields.notes enriched=enrichedNotes value=system.identity.notes name="system.identity.notes" toggled=true}} -
+

{{ localize 'IDENTITY.notes' }}

+ {{formInput systemFields.identity.fields.notes enriched=enrichedNotes value=system.identity.notes name="system.identity.notes" toggled=true}}
- {{!-- Group Abilities (from items) --}} + {{!-- Objectifs --}}
-

- {{ localize 'VERMINE.abilities' }} - {{#if isEditMode}} - +

{{ localize 'VERMINE.objectives' }}

+ +
{{ localize 'VERMINE.major_objectives' }}
+
    + {{#each system.objectives.major as |objective id|}} +
  1. +
    + {{#if @root.isEditMode}} + + {{else}} + {{objective}} + {{/if}} +
    +
    + {{#if @root.isEditMode}} + + {{/if}} +
    +
  2. + {{/each}} +
+ {{#if isEditMode}} + {{ localize 'ITEMS.new_objective' }} + {{/if}} + +
{{ localize 'VERMINE.minor_objectives' }}
+
    + {{#each system.objectives.minor as |objective id|}} +
  1. +
    + {{#if @root.isEditMode}} + + {{else}} + {{objective}} + {{/if}} +
    +
    + {{#if @root.isEditMode}} + + {{/if}} +
    +
  2. + {{/each}} +
+ {{#if isEditMode}} + {{ localize 'ITEMS.new_objective' }} + {{/if}} +
+ + {{!-- Totem --}} +
+

{{ localize 'IDENTITY.totem' }}

+
+ {{#if (eq system.identity.totem "")}} + {{ localize 'VERMINE.totem_picker' }} + {{else}} +
+ {{ smarttl "TOTEMS" system.identity.totem }} + {{ localize 'UI.effect_edit' }} +
{{/if}} - -
    +
+
+ + {{#if isEditMode}} + + {{else}} + {{system.identity.instincts}} + {{/if}} +
+
+ + {{#if isEditMode}} + + {{else}} + {{system.identity.prohibits}} + {{/if}} +
+
+ + {{!-- Capacités de groupe --}} +
+

{{ localize 'VERMINE.group_abilities' }}{{#if isEditMode}}{{/if}}

+
    {{#each abilities as |item id|}} {{#if (ne item.system.type 'totem')}} -
  1. -
    +
  2. + -
    +
    {{#if @root.isEditMode}} {{/if}} @@ -60,119 +140,18 @@
- {{!-- Group Totem Abilities --}} + {{!-- Capacités de totem --}}
-

- {{ localize 'VERMINE.totem_abilities' }} - {{#if isEditMode}} - - {{/if}} -

-
    +

    {{ localize 'VERMINE.totem_abilities' }}{{#if isEditMode}}{{/if}}

    +
      {{#each totem_abilities as |item id|}} -
    1. -
      +
    2. +
      {{item.name}} {{item.system.level.value}} - {{item.system.learn.threshold}}/{{item.system.learn.hindrance}} + {{item.system.learn.threshold}}{{#ifgt item.system.learn.hindrance 0}}/{{ roman item.system.learn.hindrance }}{{/ifgt}}
      -
      - {{#if @root.isEditMode}} - - {{/if}} -
      -
    3. - {{/each}} -
    -
- - {{!-- Specialties --}} -
-

- {{ localize 'ITEMS.specialties' }} - {{#if isEditMode}} - - {{/if}} -

-
    - {{#each specialties as |item id|}} -
  1. - -
    - {{#if @root.isEditMode}} - - {{/if}} -
    -
  2. - {{/each}} -
-
- - {{!-- Backgrounds --}} -
-

- {{ localize 'ITEMS.backgrounds' }} - {{#if isEditMode}} - - {{/if}} -

-
    - {{#each backgrounds as |item id|}} -
  1. - -
    - {{#if @root.isEditMode}} - - {{/if}} -
    -
  2. - {{/each}} -
-
- - {{!-- Traumas --}} -
-

- {{ localize 'ITEMS.traumas' }} - {{#if isEditMode}} - - {{/if}} -

-
    - {{#each traumas as |item id|}} -
  1. - -
    - {{#if @root.isEditMode}} - - {{/if}} -
    -
  2. - {{/each}} -
-
- - {{!-- Evolutions --}} -
-

- {{ localize 'ITEMS.evolutions' }} - {{#if isEditMode}} - - {{/if}} -

-
    - {{#each evolutions as |item id|}} -
  1. - -
    +
    {{#if @root.isEditMode}} {{/if}} diff --git a/templates/actor/appv2/group-reserve.hbs b/templates/actor/appv2/group-reserve.hbs index 91878ba..0a242d8 100644 --- a/templates/actor/appv2/group-reserve.hbs +++ b/templates/actor/appv2/group-reserve.hbs @@ -1,8 +1,8 @@
    - {{!-- Group Reserve and Morale --}} + {{!-- Réserve et Moral --}}
    -

    {{ localize 'VERMINE.reserve' }}

    +

    {{ localize 'VERMINE.reserve' }}

    {{#if isEditMode}} @@ -35,27 +35,21 @@
    - {{!-- Group Members --}} -
    -

    - {{ localize 'VERMINE.group_members' }} - {{#if isEditMode}} - - {{/if}} -

    -
      + {{!-- Membres --}} +
      +

      {{ localize 'VERMINE.group_members' }}{{#if isEditMode}}{{/if}}

      +
        {{#each system.members as |memberId|}} {{#with (lookup ../resolvedMembers memberId) as |member|}} -
      1. -
        +
      2. +
        {{#if member}} {{member.name}} {{else}} ID: {{memberId}} {{/if}}
        -
        +
        {{#if @root.isEditMode}} {{/if}} @@ -65,156 +59,5 @@ {{/each}}
      - - {{!-- Group Encounters --}} -
      -

      - {{ localize 'VERMINE.encounters' }} - {{#if isEditMode}} - - {{/if}} -

      -
        - {{#each system.encounters as |encounterId|}} - {{#with (lookup ../resolvedEncounters encounterId) as |encounter|}} -
      1. -
        - {{#if encounter}} - {{encounter.name}} - {{else}} - ID: {{encounterId}} - {{/if}} -
        -
        - {{#if @root.isEditMode}} - - {{/if}} -
        -
      2. - {{/with}} - {{/each}} -
      -
      - - {{!-- Group Objectives --}} -
      -

      {{ localize 'VERMINE.objectives' }}

      - -
      -
      {{ localize 'VERMINE.major_objectives' }}
      -
        - {{#each system.objectives.major as |objective id|}} -
      1. -
        - {{#if @root.isEditMode}} - - {{else}} - {{objective}} - {{/if}} -
        -
        - {{#if @root.isEditMode}} - - {{/if}} -
        -
      2. - {{/each}} -
      - {{#if isEditMode}} - {{ localize 'ITEMS.new_objective' }} - {{/if}} -
      - -
      -
      {{ localize 'VERMINE.minor_objectives' }}
      -
        - {{#each system.objectives.minor as |objective id|}} -
      1. -
        - {{#if @root.isEditMode}} - - {{else}} - {{objective}} - {{/if}} -
        -
        - {{#if @root.isEditMode}} - - {{/if}} -
        -
      2. - {{/each}} -
      - {{#if isEditMode}} - {{ localize 'ITEMS.new_objective' }} - {{/if}} -
      -
      - - {{!-- Group Abilities --}} -
      -

      - {{ localize 'VERMINE.group_abilities' }} - {{#if isEditMode}} - - {{/if}} -

      -
        - {{#each abilities as |item id|}} - {{#if (ne item.type 'totem')}} -
      1. - -
        - {{#if @root.isEditMode}} - - {{/if}} -
        -
      2. - {{/if}} - {{/each}} -
      -
      - - {{!-- Totem Section --}} -
      -

      {{ localize 'IDENTITY.totem' }}

      -
      - - {{#if isEditMode}} - - {{else}} - {{system.identity.instincts}} - {{/if}} -
      -
      - - {{#if isEditMode}} - - {{else}} - {{system.identity.prohibits}} - {{/if}} -
      -
      - {{#if (eq system.identity.totem "")}} - {{ localize 'VERMINE.totem_picker' }} - {{else}} -
      - {{ smarttl "TOTEMS" system.identity.totem }} - {{ localize 'UI.effect_edit' }} -
      - {{/if}} -
      -
    diff --git a/templates/actor/appv2/group-road.hbs b/templates/actor/appv2/group-road.hbs index 5cf24f5..f032d8e 100644 --- a/templates/actor/appv2/group-road.hbs +++ b/templates/actor/appv2/group-road.hbs @@ -1,40 +1,49 @@
    -
      -
    1. -
      {{ localize 'IDENTITY.name'}}
      -
      {{ localize 'VERMINE.mobility'}}
      -
      {{ localize 'VERMINE.rarity'}}
      -
      {{ localize 'VERMINE.reliability'}}
      -
      - {{#if isEditMode}} - - {{/if}} -
      -
    2. - {{#each vehicles as |vehicle|}} -
    3. -
      -
      - -
      - {{vehicle.name}} -
      - - - -
      - {{#if @root.isEditMode}} - - {{/if}} -
      -
    4. - {{else}} -
    5. - {{ localize 'VERMINE.no_vehicles' }} -
    6. - {{/each}} -
    +
    + {{!-- Rencontres --}} +
    +

    {{ localize 'VERMINE.encounters' }}{{#if isEditMode}}{{/if}}

    +
      +
    1. +
      {{ localize 'IDENTITY.name'}}
      +
      {{ localize 'IDENTITY.profile'}}
      +
      {{ localize 'IDENTITY.totem'}}
      +
      +
    2. + {{#each system.encounters as |encounterId|}} + {{#with (lookup ../resolvedEncounters encounterId) as |encounter|}} +
    3. + {{#if encounter}} +
      + {{encounter.name}} + ({{encounter.type}}) +
      +
      {{encounter.profile}}
      +
      {{#if encounter.totem}}{{ smarttl "TOTEMS" encounter.totem }}{{/if}}
      + {{else}} + +
      +
      + {{/if}} +
      + {{#if @root.isEditMode}} + + {{/if}} +
      +
    4. + {{/with}} + {{else}} +
    5. + {{ localize 'VERMINE.no_encounters' }} +
    6. + {{/each}} +
    +
    + + {{!-- Notes de voyage --}} +
    +

    {{ localize 'VERMINE.travel_notes' }}

    + {{formInput systemFields.roadNotes enriched=enrichedRoadNotes value=system.roadNotes name="system.roadNotes" toggled=true}} +
    +
    diff --git a/templates/actor/appv2/npc-combat.hbs b/templates/actor/appv2/npc-combat.hbs index 68f57a5..4440746 100644 --- a/templates/actor/appv2/npc-combat.hbs +++ b/templates/actor/appv2/npc-combat.hbs @@ -1,45 +1,45 @@
    {{> "systems/vermine2047/templates/actor/parts/actor-equipped-gear.hbs"}}

    {{ localize "VERMINE.wounds.name"}}

    -
      -
    • {{ localize 'VERMINE.wounds.light'}} ({{ - system.minorWound.threshold }}) -
      +
      + + {{ localize 'VERMINE.wounds.light'}} ({{ system.minorWound.threshold }}) + {{#repeat system.minorWound.max 1 "minorwoundmax"}}
      {{/repeat}} -
      -
    • -
    • {{ localize 'VERMINE.wounds.heavy'}} ({{ - system.majorWound.threshold }}) -
      + + + + {{ localize 'VERMINE.wounds.heavy'}} ({{ system.majorWound.threshold }}) + {{#repeat system.majorWound.max 1 "majorwoundmax"}}
      -
      {{/repeat}} -
      -
    • -
    • {{ localize 'VERMINE.wounds.deadly'}} ({{ - system.deadlyWound.threshold }}) -
      + + + + {{ localize 'VERMINE.wounds.deadly'}} ({{ system.deadlyWound.threshold }}) + {{#repeat system.deadlyWound.max 1 "deadlywoundmax"}}
      -
      {{/repeat}} -
      -
    • -
    + + +

    {{ localize "UI.effects.name"}}

      {{#each effects as |section sid|}} diff --git a/templates/actor/appv2/npc-notes.hbs b/templates/actor/appv2/npc-notes.hbs index a10f7e9..f176d80 100644 --- a/templates/actor/appv2/npc-notes.hbs +++ b/templates/actor/appv2/npc-notes.hbs @@ -1,14 +1,6 @@

      {{ localize 'IDENTITY.notes' }}

      -
      - - {{#if isEditMode}} - - {{else}} - {{system.identity.profile}} - {{/if}} -
      {{#if isEditMode}} diff --git a/templates/actor/appv2/npc-traits.hbs b/templates/actor/appv2/npc-traits.hbs index f850fe1..bcb68b5 100644 --- a/templates/actor/appv2/npc-traits.hbs +++ b/templates/actor/appv2/npc-traits.hbs @@ -17,9 +17,9 @@
    1. {{ localize 'ADVERSITY.wounds' }}: - {{#repeat system.minorWound.max}}{{/repeat}} {{ system.minorWound.threshold }} - {{#repeat system.majorWound.max}}{{/repeat}} {{ system.majorWound.threshold }} - {{#repeat system.deadlyWound.max}}{{/repeat}} {{ system.deadlyWound.threshold }} + {{#repeat system.minorWound.max 1 "woundindex"}}{{/repeat}} {{ system.minorWound.threshold }} + {{#repeat system.majorWound.max 1 "woundindex"}}{{/repeat}} {{ system.majorWound.threshold }} + {{#repeat system.deadlyWound.max 1 "woundindex"}}{{/repeat}} {{ system.deadlyWound.threshold }}
    2. diff --git a/templates/actor/character/character-totem.hbs b/templates/actor/character/character-totem.hbs index b975477..7ceeeec 100644 --- a/templates/actor/character/character-totem.hbs +++ b/templates/actor/character/character-totem.hbs @@ -48,7 +48,7 @@ data-tooltip="niveau">{{item.system.level.value}} - {{item.system.learn.threshold}}/{{item.system.learn.hindrance}} + {{item.system.learn.threshold}}{{#ifgt item.system.learn.hindrance 0}}/{{ roman item.system.learn.hindrance }}{{/ifgt}}
      diff --git a/templates/actor/parts/actor-equipped-gear.hbs b/templates/actor/parts/actor-equipped-gear.hbs index 0450008..f79310f 100644 --- a/templates/actor/parts/actor-equipped-gear.hbs +++ b/templates/actor/parts/actor-equipped-gear.hbs @@ -27,6 +27,11 @@ ({{item.system.damage.type}})
      {{#if item.system.skill}}{{ smarttlk 'SKILLS' item.system.skill 'name' }}{{/if}}
      +
      + +
      {{/each}}
    diff --git a/templates/actor/parts/actor-weapons.hbs b/templates/actor/parts/actor-weapons.hbs index db358da..5ff52ef 100644 --- a/templates/actor/parts/actor-weapons.hbs +++ b/templates/actor/parts/actor-weapons.hbs @@ -47,8 +47,6 @@ class="fas fa-edit"> -
  2. {{/each}} diff --git a/templates/item/chatCards/ability.hbs b/templates/item/chatCards/ability.hbs index c74df26..8677519 100644 --- a/templates/item/chatCards/ability.hbs +++ b/templates/item/chatCards/ability.hbs @@ -30,7 +30,7 @@ {{item.system.learn.threshold}} {{#ifgt item.system.learn.hindrance 0}} - / {{item.system.learn.hindrance}} + / {{ roman item.system.learn.hindrance }} {{/ifgt}}
diff --git a/templates/item/chatCards/creaturecapacity.hbs b/templates/item/chatCards/creaturecapacity.hbs new file mode 100644 index 0000000..0fa0158 --- /dev/null +++ b/templates/item/chatCards/creaturecapacity.hbs @@ -0,0 +1,13 @@ + + {{> "systems/vermine2047/templates/item/chatCards/parts/base.hbs"}} + + {{!-- Capacité de créature specific content --}} +
+ {{#if item.system.type}} +
+ {{ localize 'VERMINE.type' }}: + {{ smarttl "CREATURE_CAPACITY_TYPES" item.system.type }} +
+ {{/if}} +
+ diff --git a/templates/item/chatCards/parts/base.hbs b/templates/item/chatCards/parts/base.hbs index 9ea9015..440cb07 100644 --- a/templates/item/chatCards/parts/base.hbs +++ b/templates/item/chatCards/parts/base.hbs @@ -1,5 +1,6 @@
image de {{item.name}} diff --git a/templates/item/item-ability-sheet.hbs b/templates/item/item-ability-sheet.hbs index 2a7d69b..7726492 100644 --- a/templates/item/item-ability-sheet.hbs +++ b/templates/item/item-ability-sheet.hbs @@ -31,10 +31,15 @@

- + / - +

description

diff --git a/templates/item/item-creaturecapacity-sheet.hbs b/templates/item/item-creaturecapacity-sheet.hbs new file mode 100644 index 0000000..9948cd6 --- /dev/null +++ b/templates/item/item-creaturecapacity-sheet.hbs @@ -0,0 +1,24 @@ +
+
+ +
+

+
+
+ +
+

+ + +

+

{{ localize "VERMINE.sheet.description"}}

+
+ {{localize "VERMINE.sheet.description"}} + {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} +
+
+
diff --git a/templates/roll-message.hbs b/templates/roll-message.hbs index 353fb03..b9375d7 100644 --- a/templates/roll-message.hbs +++ b/templates/roll-message.hbs @@ -148,6 +148,9 @@ {{#if param.poolBreakdown.domainBonus}} {{#ifgt param.poolBreakdown.domainBonus 0}}{{localize "VERMINE.domain_bonus"}}{{else}}{{localize "VERMINE.domain_penalty"}}{{/ifgt}} {{param.poolBreakdown.domainBonus}}D {{/if}} + {{#if param.poolBreakdown.malus}} + {{localize "VERMINE.pool_malus"}} -{{param.poolBreakdown.malus}}D + {{/if}} {{localize "VERMINE.pool_total"}} {{param.poolBreakdown.total}}D