Compare commits

..

51 Commits

Author SHA1 Message Date
Mandar
5cf4401fa3 1.2.1 - Praised be Firefox 2021-02-18 02:23:38 +01:00
Mandar
69e96b6610 Fix dice swap and items on firefox 2021-02-18 02:10:48 +01:00
Mandar
87b54ac3ef 1.2.0 - Roll n Keep 2021-02-17 12:45:28 +01:00
Mandar
08c0059ca5 Add line for mark dice process in RnK 2021-02-16 19:42:43 +01:00
Mandar
bc615d05fa Fix TN position 2021-02-16 18:34:56 +01:00
Mandar
da0bdf453e Change npc skill position + fix profile img on rnk 2021-02-16 18:08:25 +01:00
Mandar
dfef6d4092 Fix rnk header html & css 2021-02-16 16:56:25 +01:00
Mandar
5ffaa062fc Fix npc tabs and Roll Button display 2021-02-16 16:02:49 +01:00
Mandar
14b47a5381 Add tabs on Npc sheets 2021-02-16 15:43:18 +01:00
Vlyan
d213d179dc Added some images for clan shuji 2021-02-16 09:13:54 +01:00
Vlyan
42708d54e8 No RnK button if regular dice are also in the roll 2021-02-16 09:13:54 +01:00
Mandar
386a62ef55 Fix gm toolbox 2021-02-15 19:47:13 +01:00
Mandar
babbafffef Html + css Rnk adjustement for flex content 2021-02-14 23:19:06 +01:00
Mandar
3eb623120a New Item liste style 2021-02-14 23:18:07 +01:00
Vlyan
d2f9b6891e Prepared: reverse on right-click 2021-02-13 17:48:16 +01:00
Vlyan
a00fa80607 Fix for undefined skillAssistance 2021-02-13 17:29:14 +01:00
Vlyan
95d031c7a8 Add an option to set the TN to 1 when the encounter type is selected (Intrigue, Duel, Skirmish or Mass battle) 2021-02-13 16:14:06 +01:00
Vlyan
cb0696f662 Split Items by category in actor sheet (pc & npc) for better readability
Fix actor fromData
2021-02-13 14:31:12 +01:00
Vlyan
db5d5b62aa Better management for School Techniques
Gray color for hidden TN result in chat
Removed unused "techniques.list" props in template
2021-02-13 13:23:02 +01:00
Vlyan
6b322be3f4 Added total success count on a hidden TN roll 2021-02-12 14:01:00 +01:00
Vlyan
48b17be458 RnK : Added ability to GM to undo the last choices 2021-02-10 17:41:35 +01:00
Vlyan
7d7d62f950 Breaking the message reference 2021-02-10 14:01:14 +01:00
Mandar
fa03e5152b Fix Gm Tools items width 2021-02-10 12:56:28 +01:00
Mandar
a823d89344 Fix chat header position 2021-02-10 00:11:33 +01:00
Vlyan
47eb508dd4 Added Skill assistance used indicator 2021-02-09 14:01:43 +01:00
Mandar
1cc496ad77 Style for new dice Rnk + technique fix 2021-02-09 13:54:00 +01:00
Vlyan
e0cb2bf235 Fix for Roll: If only skill dice, keepLimit = nb skill dice 2021-02-09 12:17:28 +01:00
Vlyan
8a22706ad2 Split techniques in actor sheet for better readability 2021-02-09 12:16:15 +01:00
Vlyan
0cb0a2f3ea Save and display initialFormula on chat 2021-02-08 19:19:15 +01:00
Vlyan
fc56afa28e fix difficulty path as Mandar do not report it :D 2021-02-06 13:00:17 +01:00
Vlyan
768fda1752 Tweaked reverse the token's bar on fatigue and colorize in red the strife bar if compromise 2021-02-06 12:49:24 +01:00
Mandar
694333a1cb Add style for chat result 2021-02-05 20:58:22 +01:00
Jzrzmy
b54f58c9ce Allow token fatigue bar reversing 2021-02-05 19:55:12 +00:00
Vlyan
6a9e84f126 Add skill assistance 2021-02-04 11:22:36 +01:00
Vlyan
84b160b50d Add Reroll and Swap visualisation in chatlog 2021-02-04 10:04:45 +01:00
Vlyan
78568ded55 changelog :D 2021-02-03 20:04:31 +01:00
Vlyan
b59fde880d RnK : Reroll add a extra step in RnK dialog
GmBx: Changed new BTs to "Sleep" & "Scene end" actions (more used)
2021-02-03 20:01:57 +01:00
Vlyan
7969c5f526 RnK : Reroll add a extra step 2021-02-03 19:41:39 +01:00
Vlyan
ca5a164f7f Add confirm on item deletion in readme 2021-02-03 12:27:36 +01:00
Vlyan
45ae96724e Add confirm on item deletion 2021-02-03 11:44:22 +01:00
Vlyan
7f987a7682 Some test on gm toolbox 2021-02-02 18:27:36 +01:00
Vlyan
d88d985575 20q Disable the generate button once clicked 2021-02-02 15:32:03 +01:00
Vlyan
9f8a24bd68 forgot a little test 2021-02-02 15:25:48 +01:00
Vlyan
4e629efe12 Added a booster for loading compendium's core items (speed up 20q) 2021-02-02 15:13:42 +01:00
Vlyan
e542dd390b Click on rings in the PC/PNC sheet now open the DicePicker 2021-02-02 12:28:14 +01:00
Vlyan
a517a92488 some renaming stuff 2021-02-02 12:09:11 +01:00
Vlyan
30da4f3a02 RnK French Translation and Minors fixes 2021-02-02 10:51:15 +01:00
Vlyan
931a28fbfe -RnK dialog auto-open after a roll
-Move for some roll props
-2 RnK bugfix (TN & Reroll)
2021-02-02 09:28:46 +01:00
Vlyan
4350506e09 Fix image's behavior on create for all items sub classes 2021-02-01 17:51:27 +01:00
Vlyan
68577737fc RnK with some bugs 2021-02-01 16:27:57 +01:00
Vlyan
30f71e31cd working on RnK 2021-01-30 16:43:57 +01:00
55 changed files with 2074 additions and 648 deletions

View File

@@ -1,5 +1,37 @@
# Changelog # Changelog
## 1.2.1 - Praised be Firefox
- Fix dice swap on firefox that overflowed on the top and bottom of the RnK dialog
- Fix new items list on firefox who deformed the sheets
## 1.2.0 - Roll n Keep
- Added Roll n Keep 1st iteration !
- Ability to Keep, Discard, Re-roll and Swap:
- Keep: Keep the die for the next step, if it's an explosive one, automatically roll a new die
- Discard: Self explain, do not keep this die for the next step.
- Re-roll: Replace this die by a new roll (Usually Advantage & Disadvantage stuff). When a reroll is selected, all the dice in the current step will be tag as keep by default.
- Swap (Face): Set a desired face for this die (Some weird techniques stuff)
- Usage:
- All these actions are done by drag and drop a die result into a target action
- A colored icon symbolize the choice made on the dice
- You can always change choices for the current step until you clic next
- Please note all dice without choice will be discarded for the next step
- The GM has the ability to undo choices by left-clicking in the status headers
- Limitation: The roll need to only have L5R dice in it (no mixed regular + L5R)
- Fix image's behavior on create for all items sub classes
- Click on rings in the PC/PNC sheet now open the DicePicker with the selected ring
- Added a booster for loading compendium's core items (speed up 20Q)
- Added confirm dialog on item's deletion (Hold "ctrl" on the click, if you want to bypass it)
- Added "Sleep" & "Scene End" buttons in "GM ToolBox" (old "difficulty" box)
- Token's bar:
- The strife bar is now displayed in red if the actor is compromised
- Added an option, off by default, to reverse the fatigue's token bar (thanks to Jzrzmy)
- Added an option, on by default, to set the TN to 1 when the encounter type is selected (Intrigue, Duel, Skirmish or Mass battle)
- Split Techniques & Items by category in actor sheet (pc & npc) for better readability
- Armor & Weapon added in the conflict tab now set the "equipped" property by default
- Added Tabs on NPC sheets
- New styles for dice results
## 1.1.2 - One Compendium to bring them all ## 1.1.2 - One Compendium to bring them all
- Added compendiums (Thanks to Stéfano Fara for the English version !) Partial for French as PoW and CR are not translated yet - Added compendiums (Thanks to Stéfano Fara for the English version !) Partial for French as PoW and CR are not translated yet
- Shadowlands - Shadowlands

View File

@@ -67,7 +67,7 @@
}, },
{ {
"id": "Robes of Judgment", "id": "Robes of Judgment",
"name": "Robes of Judgment (WIP)", "name": "Robes de jugement",
"description": "", "description": "",
"book_reference": "Les Royaumes Célestes p.97" "book_reference": "Les Royaumes Célestes p.97"
}, },

View File

@@ -4,7 +4,16 @@
"Maintainers": ["Team L5R"] "Maintainers": ["Team L5R"]
}, },
"SETTINGS": { "SETTINGS": {
"None": "No option" "None": "No option",
"ReverseFatigueBar": "Reverse token fatigue bar",
"RollNKeep": {
"DeleteOldMessage": "RnK Delete previous chat message",
"DeleteOldMessageHint": "Choose to keep or delete the previous message for a RnK series"
},
"Initiative": {
"SetTn1OnTypeChange": "Set TN to 1 on encounter change",
"SetTn1OnTypeChangeHint": "Set the TN to 1 when the encounter type is selected (Intrigue, Duel, Skirmish or Mass battle)"
}
}, },
"ACTOR": { "ACTOR": {
"TypeCharacter": "Player Character", "TypeCharacter": "Player Character",
@@ -21,10 +30,9 @@
}, },
"l5r5e": { "l5r5e": {
"global": { "global": {
"ok": "OK",
"add": "Add", "add": "Add",
"edit": "Edit", "edit": "Edit",
"delete": "Delete", "delete_confirm": "Are you sure you want to delete '{name}' ?",
"drop_here": "Drop here", "drop_here": "Drop here",
"edge_translation_disclaimer": "" "edge_translation_disclaimer": ""
}, },
@@ -83,14 +91,19 @@
"difficulty_hidden": "TN ???", "difficulty_hidden": "TN ???",
"dicepicker": "Dice Picker", "dicepicker": "Dice Picker",
"void_point_used": "Void point used", "void_point_used": "Void point used",
"assistance_used": "Skill assistance used",
"roll_n_keep": "Roll & Keep", "roll_n_keep": "Roll & Keep",
"initiative_roll": "Initiative roll" "initiative_roll": "Initiative roll",
"success_text": "Success!",
"bonus_text": "bonus successes",
"fail_text": "Fail!"
}, },
"dicepicker": { "dicepicker": {
"difficulty_title": "Difficulty", "difficulty_title": "Difficulty",
"difficulty_hidden_label": "Hide TN", "difficulty_hidden_label": "Hide TN",
"use_void_point_label": "Spend a", "use_void_point_label": "Spend a",
"void_point_tooltip": "Void point", "void_point_tooltip": "Void point",
"skill_assistance_label": "Assistance",
"roll_label": "Roll", "roll_label": "Roll",
"bt_add_macro": "Add a macro" "bt_add_macro": "Add a macro"
}, },
@@ -98,10 +111,19 @@
"title": "L5R Roll & Keep", "title": "L5R Roll & Keep",
"discard_drop_here": "Discard", "discard_drop_here": "Discard",
"reroll_drop_here": "Re-roll", "reroll_drop_here": "Re-roll",
"reroll_chat": "Re-rolled dice", "swap_drop_here": "Swap",
"keep_drop_here": "Keep", "keep_drop_here": "Keep",
"keep_chat": "New roll from an exploding die", "bt_validate": "Finalize this step",
"bt_validate": "Finalize" "undo": "[GM] Undo the last step choices"
},
"gm_toolbox": {
"title": "GM ToolBox",
"difficulty_hidden": "Change difficulty visibility",
"difficulty": "Change difficulty (right: add, left: subtract, middle: TN 2)",
"sleep": "Comfortable rest for all characters (Remove Water x2 fatigue)",
"sleep_info": "The characters had a good night's sleep.",
"scene_end": "End of scene (Conflict and Fatigue half reset for all characters)",
"scene_end_info": "The tension of the scene finally drops."
}, },
"max": "Max", "max": "Max",
"current": "Current", "current": "Current",

View File

@@ -4,7 +4,16 @@
"Maintainers": ["Team L5R"] "Maintainers": ["Team L5R"]
}, },
"SETTINGS": { "SETTINGS": {
"None": "Sin opción" "None": "Sin opción",
"ReverseFatigueBar": "Invertir la barra de fatiga de los token",
"RollNKeep": {
"DeleteOldMessage": "RnK Delete previous chat message",
"DeleteOldMessageHint": "Choose to keep or delete the previous message for a RnK series"
},
"Initiative": {
"SetTn1OnTypeChange": "Set TN to 1 on encounter change",
"SetTn1OnTypeChangeHint": "Set the TN to 1 when the encounter type is selected (Intrigue, Duel, Skirmish or Mass battle)"
}
}, },
"ACTOR": { "ACTOR": {
"TypeCharacter": "Personaje jugador", "TypeCharacter": "Personaje jugador",
@@ -21,10 +30,9 @@
}, },
"l5r5e": { "l5r5e": {
"global": { "global": {
"ok": "OK",
"add": "Añadir", "add": "Añadir",
"edit": "Editar", "edit": "Editar",
"delete": "Borrar", "delete_confirm": "Are you sure you want to delete '{name}' ?",
"drop_here": "Dejar caer aquí", "drop_here": "Dejar caer aquí",
"edge_translation_disclaimer": "Edge Studio nos da su permiso para ofrecer este módulo a la comunidad, pero tanto los textos así como los códigos que lo constituyen no tienen su aprobación explícita." "edge_translation_disclaimer": "Edge Studio nos da su permiso para ofrecer este módulo a la comunidad, pero tanto los textos así como los códigos que lo constituyen no tienen su aprobación explícita."
}, },
@@ -83,14 +91,19 @@
"difficulty_hidden": "NO ???", "difficulty_hidden": "NO ???",
"dicepicker": "Dice Picker", "dicepicker": "Dice Picker",
"void_point_used": "Punto de vacío utilizado", "void_point_used": "Punto de vacío utilizado",
"assistance_used": "Skill assistance used",
"roll_n_keep": "Tirar y guardar", "roll_n_keep": "Tirar y guardar",
"initiative_roll": "Tirada de Iniciativa" "initiative_roll": "Tirada de Iniciativa",
"success_text": "Éxitos!",
"bonus_text": "bonus successes",
"fail_text": "Fail!"
}, },
"dicepicker": { "dicepicker": {
"difficulty_title": "Dificultad", "difficulty_title": "Dificultad",
"difficulty_hidden_label": "Ocultar NO", "difficulty_hidden_label": "Ocultar NO",
"use_void_point_label": "Gasta un", "use_void_point_label": "Gasta un",
"void_point_tooltip": "Punto de vacío", "void_point_tooltip": "Punto de vacío",
"skill_assistance_label": "Assistance",
"roll_label": "Tirar", "roll_label": "Tirar",
"bt_add_macro": "Añadir una macro" "bt_add_macro": "Añadir una macro"
}, },
@@ -98,10 +111,19 @@
"title": "L5R Roll & Keep", "title": "L5R Roll & Keep",
"discard_drop_here": "Descartar", "discard_drop_here": "Descartar",
"reroll_drop_here": "Relanzar", "reroll_drop_here": "Relanzar",
"reroll_chat": "Dados relanzados", "swap_drop_here": "Swap",
"keep_drop_here": "Guardar", "keep_drop_here": "Guardar",
"keep_chat": "Nueva tirada de un dado relanzable", "bt_validate": "Finalizar",
"bt_validate": "Finalizar" "undo": "[GM] Undo the last step choices"
},
"gm_toolbox": {
"title": "GM ToolBox",
"difficulty_hidden": "Change difficulty visibility",
"difficulty": "Change difficulty (right: add, left: subtract, middle: TN 2)",
"sleep": "Comfortable rest for all characters (Remove Water x2 fatigue)",
"sleep_info": "The characters had a good night's sleep.",
"scene_end": "End of scene (Conflict and Fatigue half reset for all characters)",
"scene_end_info": "The tension of the scene finally drops."
}, },
"max": "Máx", "max": "Máx",
"current": "Actuales", "current": "Actuales",

View File

@@ -4,7 +4,16 @@
"Maintainers": ["Team L5R"] "Maintainers": ["Team L5R"]
}, },
"SETTINGS": { "SETTINGS": {
"None": "Aucune option" "None": "Aucune option",
"ReverseFatigueBar": "Inverser la barre de fatigue des token",
"RollNKeep": {
"DeleteOldMessage": "RnK Supprime le précédent message du chat",
"DeleteOldMessageHint": "Si coché, on supprime le message précédent pour la série de jets via le RnK"
},
"Initiative": {
"SetTn1OnTypeChange": "ND 1 à la sélection du type de rencontre",
"SetTn1OnTypeChangeHint": "Met le ND à 1 lorsqu'on modifie le type de rencontre (Intrigue, Duel, Escarmouche ou Bataille rangée)"
}
}, },
"ACTOR": { "ACTOR": {
"TypeCharacter": "Personnage Joueur", "TypeCharacter": "Personnage Joueur",
@@ -21,10 +30,9 @@
}, },
"l5r5e": { "l5r5e": {
"global": { "global": {
"ok": "OK",
"add": "Ajouter", "add": "Ajouter",
"edit": "Modifier", "edit": "Modifier",
"delete": "Supprimer", "delete_confirm": "Etes-vous sûr de vouloir supprimer '{name}' ?",
"drop_here": "Déposez ici", "drop_here": "Déposez ici",
"edge_translation_disclaimer": "" "edge_translation_disclaimer": ""
}, },
@@ -83,25 +91,39 @@
"difficulty_hidden": "ND ???", "difficulty_hidden": "ND ???",
"dicepicker": "Dice Picker", "dicepicker": "Dice Picker",
"void_point_used": "Point de vide utilisé", "void_point_used": "Point de vide utilisé",
"assistance_used": "Assistance de compétence utilisée",
"roll_n_keep": "Roll & Keep", "roll_n_keep": "Roll & Keep",
"initiative_roll": "Jet d'initiative" "initiative_roll": "Jet d'initiative",
"success_text": "Succès !",
"bonus_text": "succès bonus",
"fail_text": "Échec !"
}, },
"dicepicker": { "dicepicker": {
"difficulty_title": "Difficulté", "difficulty_title": "Difficulté",
"difficulty_hidden_label": "ND Caché", "difficulty_hidden_label": "ND Caché",
"use_void_point_label": "Dépenser un", "use_void_point_label": "Dépenser un",
"void_point_tooltip": "Point de Vide", "void_point_tooltip": "Point de Vide",
"skill_assistance_label": "Assistance",
"roll_label": "Lancer", "roll_label": "Lancer",
"bt_add_macro": "Ajouter une macro" "bt_add_macro": "Ajouter une macro"
}, },
"roll_n_keep": { "roll_n_keep": {
"title": "L5R Roll & Keep", "title": "L5R Roll & Keep",
"discard_drop_here": "Discard", "discard_drop_here": "Abandonner",
"reroll_drop_here": "Re-roll", "reroll_drop_here": "Relancer",
"reroll_chat": "Re-rolled dice", "swap_drop_here": "Modifier",
"keep_drop_here": "Keep", "keep_drop_here": "Garder",
"keep_chat": "New roll from a exploding dice", "bt_validate": "Finaliser cette étape",
"bt_validate": "Finalize" "undo": "[GM] Annuler les choix de la dernière étape"
},
"gm_toolbox": {
"title": "GM ToolBox",
"difficulty_hidden": "Modifier la visibilité de la difficulté",
"difficulty": "Modifier la difficulté (droite: ajout, gauche: soustraction, milieu: ND 2)",
"sleep": "Repos confortable pour tous les personnages (Enlève Eau x2 de fatigue)",
"sleep_info": "Les personnages ont passé une bonne nuit de sommeil.",
"scene_end": "Fin de scène (Conflit et Fatigue à moitié pour tous les personnages dont la valeur dépasse ce seuil)",
"scene_end_info": "La tension de la scène retombe enfin"
}, },
"max": "Max", "max": "Max",
"current": "Actuel", "current": "Actuel",

View File

@@ -32,14 +32,14 @@
{"_id":"L5RCoreShu000032","name":"Regal Bearing","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.220"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000032","name":"Regal Bearing","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.220"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000033","name":"Well of Desire","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.221"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000033","name":"Well of Desire","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.221"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000034","name":"Shallow Waters","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.220"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000034","name":"Shallow Waters","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.220"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000035","name":"Lady Shinjos Speed (Unicorn)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000035","name":"Lady Shinjos Speed (Unicorn)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/clans/unicorn.svg","effects":[]}
{"_id":"L5RCoreShu000036","name":"Lady Dojis Decree (Crane)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000036","name":"Lady Dojis Decree (Crane)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/clans/crane.svg","effects":[]}
{"_id":"L5RCoreShu000037","name":"Courtiers Resolve","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000037","name":"Courtiers Resolve","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000038","name":"A Samurais Fate","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000038","name":"A Samurais Fate","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000039","name":"Lord Bayushis Whispers (Scorpion)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000039","name":"Lord Bayushis Whispers (Scorpion)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/clans/scorpion.svg","effects":[]}
{"_id":"L5RCoreShu000040","name":"Lord Togashis Insight (Dragon)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000040","name":"Lord Togashis Insight (Dragon)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/clans/dragon.svg","effects":[]}
{"_id":"L5RCoreShu000041","name":"Rouse the Soul","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"5","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000041","name":"Rouse the Soul","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"5","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000042","name":"Lord Akodos Roar (Lion)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000042","name":"Lord Akodos Roar (Lion)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"2","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.223"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/clans/lion.svg","effects":[]}
{"_id":"L5RCoreShu000043","name":"All Arts Are One","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"3","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000043","name":"All Arts Are One","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"3","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Core Rulebook p.222"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000044","name":"Hidden in Smoke","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.117"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000044","name":"Hidden in Smoke","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.117"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000045","name":"Assess Strengths","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.117"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000045","name":"Assess Strengths","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.117"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
@@ -52,7 +52,7 @@
{"_id":"L5RCoreShu000052","name":"Fun and Games","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.119"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000052","name":"Fun and Games","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"water","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.119"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000053","name":"Foreseen Need","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.119"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000053","name":"Foreseen Need","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Court of Stones p.119"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000054","name":"Spin the Web (Kolat)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"3","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Emerald Empire p.248"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000054","name":"Spin the Web (Kolat)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"3","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Emerald Empire p.248"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000055","name":"Awe of Heaven (Imperial)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Emerald Empire p.248"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000055","name":"Awe of Heaven (Imperial)","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"4","bought_at_rank":0,"ring":"void","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Emerald Empire p.248"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/clans/imperial.svg","effects":[]}
{"_id":"L5RCoreShu000056","name":"Look Out","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"3","bought_at_rank":0,"ring":"earth","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Path of Waves p.92"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000056","name":"Look Out","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"3","bought_at_rank":0,"ring":"earth","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Path of Waves p.92"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000057","name":"Bellow of Resolve","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"earth","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Path of Waves p.92"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000057","name":"Bellow of Resolve","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"1","bought_at_rank":0,"ring":"earth","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Path of Waves p.92"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}
{"_id":"L5RCoreShu000058","name":"Ruse of the Moon's Reflection","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"5","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Path of Waves p.93"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]} {"_id":"L5RCoreShu000058","name":"Ruse of the Moon's Reflection","permission":{"default":0},"type":"technique","data":{"in_curriculum":false,"xp_used":0,"rank":"5","bought_at_rank":0,"ring":"air","technique_type":"shuji","xp_cost":"3","description":"","book_reference":"Path of Waves p.93"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/techs/shuji.svg","effects":[]}

View File

@@ -12,7 +12,9 @@ export class ActorL5r5e extends Actor {
// } // }
// Replace default image // Replace default image
data.img = `${CONFIG.l5r5e.paths.assets}icons/actors/${data.type}.svg`; if (data.img === undefined) {
data.img = `${CONFIG.l5r5e.paths.assets}icons/actors/${data.type}.svg`;
}
// Some tweak on actors token // Some tweak on actors token
data.token = data.token || {}; data.token = data.token || {};

View File

@@ -27,9 +27,81 @@ export class BaseSheetL5r5e extends ActorSheet {
sheetData.data.stances = CONFIG.l5r5e.stances; sheetData.data.stances = CONFIG.l5r5e.stances;
sheetData.data.techniquesList = CONFIG.l5r5e.techniques; sheetData.data.techniquesList = CONFIG.l5r5e.techniques;
// Sort Items by name
sheetData.items.sort((a, b) => {
return a.name.localeCompare(b.name);
});
// Split Techniques by types
sheetData.data.splitTechniquesList = this._splitTechniques(sheetData);
// Split Items by types
sheetData.data.splitItemsList = this._splitItems(sheetData);
return sheetData; return sheetData;
} }
/**
* Split Techniques by types for better readability
* @private
*/
_splitTechniques(sheetData) {
const out = {};
// Build the list order
[...CONFIG.l5r5e.techniques, ...CONFIG.l5r5e.techniques_school].forEach((tech) => {
out[tech] = [];
});
// Add tech the character knows
sheetData.items.forEach((item) => {
if (item.type === "technique") {
out[item.data.technique_type].push(item);
}
});
// Remove unused techs
Object.keys(out).forEach((tech) => {
if (
out[tech].length < 1 &&
!sheetData.data.techniques[tech] &&
!CONFIG.l5r5e.techniques_school.includes(tech)
) {
delete out[tech];
}
});
// Manage school add button
sheetData.data.techniques["school_ability"] = out["school_ability"].length === 0;
sheetData.data.techniques["mastery_ability"] = out["mastery_ability"].length === 0;
// Always display "school_ability", but display "mastery_ability" only if rank >= 5
if (sheetData.data.identity?.school_rank < 5 && out["mastery_ability"].length === 0) {
delete out["mastery_ability"];
}
return out;
}
/**
* Split Items by types for better readability
* @private
*/
_splitItems(sheetData) {
const out = {
weapon: [],
armor: [],
item: [],
};
sheetData.items.forEach((item) => {
if (["item", "armor", "weapon"].includes(item.type)) {
out[item.type].push(item);
}
});
return out;
}
/** /**
* Return a light sheet if in "limited" state * Return a light sheet if in "limited" state
* @override * @override
@@ -71,6 +143,7 @@ export class BaseSheetL5r5e extends ActorSheet {
/** /**
* Handle dropped data on the Actor sheet * Handle dropped data on the Actor sheet
* @param {Event} event
*/ */
async _onDrop(event) { async _onDrop(event) {
// *** Everything below here is only needed if the sheet is editable *** // *** Everything below here is only needed if the sheet is editable ***
@@ -185,6 +258,7 @@ export class BaseSheetL5r5e extends ActorSheet {
} }
new game.l5r5e.DicePickerDialog({ new game.l5r5e.DicePickerDialog({
ringId: li.data("ring") || null,
skillId: skillId, skillId: skillId,
skillCatId: li.data("skillcat") || null, skillCatId: li.data("skillcat") || null,
isInitiativeRoll: li.data("initiative") || false, isInitiativeRoll: li.data("initiative") || false,
@@ -207,28 +281,12 @@ export class BaseSheetL5r5e extends ActorSheet {
}); });
// Equipped / Readied // Equipped / Readied
html.find(".equip-readied-control").on("click", (event) => { html.find(".equip-readied-control").on("click", this._switchEquipReadied.bind(this));
event.preventDefault();
event.stopPropagation();
this._switchEquipReadied(event);
});
// *** Items : add, edit, delete *** // *** Items : add, edit, delete ***
html.find(".item-add").on("click", (event) => { html.find(".item-add").on("click", this._addSubItem.bind(this));
event.preventDefault(); html.find(`.item-edit`).on("click", this._editSubItem.bind(this));
event.stopPropagation(); html.find(`.item-delete`).on("click", this._deleteSubItem.bind(this));
this._addSubItem(event);
});
html.find(`.item-edit`).on("click", (event) => {
event.preventDefault();
event.stopPropagation();
this._editSubItem(event);
});
html.find(`.item-delete`).on("click", (event) => {
event.preventDefault();
event.stopPropagation();
this._deleteSubItem(event);
});
} }
/** /**
@@ -247,9 +305,13 @@ export class BaseSheetL5r5e extends ActorSheet {
/** /**
* Add a generic item with sub type * Add a generic item with sub type
* @param {Event} event
* @private * @private
*/ */
async _addSubItem(event) { async _addSubItem(event) {
event.preventDefault();
event.stopPropagation();
const type = $(event.currentTarget).data("item-type"); const type = $(event.currentTarget).data("item-type");
const titles = { const titles = {
item: "l5r5e.items.title_new", item: "l5r5e.items.title_new",
@@ -262,7 +324,7 @@ export class BaseSheetL5r5e extends ActorSheet {
const created = await this.actor.createEmbeddedEntity("OwnedItem", { const created = await this.actor.createEmbeddedEntity("OwnedItem", {
name: game.i18n.localize(titles[type]), name: game.i18n.localize(titles[type]),
type: type, type: type,
img: "icons/svg/mystery-man.svg", img: `${CONFIG.l5r5e.paths.assets}icons/items/${type}.svg`,
}); });
const item = this.actor.getOwnedItem(created._id); const item = this.actor.getOwnedItem(created._id);
@@ -272,14 +334,37 @@ export class BaseSheetL5r5e extends ActorSheet {
item.data.data.bought_at_rank = this.actor.data.data.identity.school_rank; item.data.data.bought_at_rank = this.actor.data.data.identity.school_rank;
} }
switch (item.data.type) {
case "armor": // no break
case "weapon":
if ($(event.currentTarget).data("item-eqquiped")) {
item.data.data.equipped = true;
}
break;
case "technique": {
// If technique, select the current type
const techType = $(event.currentTarget).data("tech-type");
if ([...CONFIG.l5r5e.techniques, ...CONFIG.l5r5e.techniques_school].includes(techType)) {
item.data.data.technique_type = techType;
item.data.img = `${CONFIG.l5r5e.paths.assets}/icons/techs/${techType}.svg`;
}
break;
}
}
item.sheet.render(true); item.sheet.render(true);
} }
/** /**
* Edit a generic item with sub type * Edit a generic item with sub type
* @param {Event} event
* @private * @private
*/ */
_editSubItem(event) { _editSubItem(event) {
event.preventDefault();
event.stopPropagation();
const itemId = $(event.currentTarget).data("item-id"); const itemId = $(event.currentTarget).data("item-id");
const item = this.actor.getOwnedItem(itemId); const item = this.actor.getOwnedItem(itemId);
item.sheet.render(true); item.sheet.render(true);
@@ -287,9 +372,13 @@ export class BaseSheetL5r5e extends ActorSheet {
/** /**
* Delete a generic item with sub type * Delete a generic item with sub type
* @param {Event} event
* @private * @private
*/ */
_deleteSubItem(event) { _deleteSubItem(event) {
event.preventDefault();
event.stopPropagation();
const itemId = $(event.currentTarget).data("item-id"); const itemId = $(event.currentTarget).data("item-id");
// Remove 1 qty if possible // Remove 1 qty if possible
@@ -298,32 +387,48 @@ export class BaseSheetL5r5e extends ActorSheet {
return; return;
} }
// Specific advancements, remove 1 to selected ring/skill const callback = async () => {
if (tmpItem.type === "advancement") { // Specific advancements, remove 1 to selected ring/skill
const actor = duplicate(this.actor.data.data); if (tmpItem.type === "advancement") {
const itmData = tmpItem.data.data; const actor = duplicate(this.actor.data.data);
if (itmData.advancement_type === "ring") { const itmData = tmpItem.data.data;
// Ring if (itmData.advancement_type === "ring") {
actor.rings[itmData.ring] = Math.max(1, actor.rings[itmData.ring] - 1); // Ring
} else { actor.rings[itmData.ring] = Math.max(1, actor.rings[itmData.ring] - 1);
// Skill } else {
const skillCatId = CONFIG.l5r5e.skills.get(itmData.skill); // Skill
if (skillCatId) { const skillCatId = CONFIG.l5r5e.skills.get(itmData.skill);
actor.skills[skillCatId][itmData.skill] = Math.max(0, actor.skills[skillCatId][itmData.skill] - 1); if (skillCatId) {
actor.skills[skillCatId][itmData.skill] = Math.max(
0,
actor.skills[skillCatId][itmData.skill] - 1
);
}
} }
// Update Actor
this.actor.update({
data: diffObject(this.actor.data.data, actor),
});
} }
// Update Actor return this.actor.deleteOwnedItem(itemId);
this.actor.update({ };
data: diffObject(this.actor.data.data, actor),
}); // Holing Ctrl = without confirm
if (event.ctrlKey) {
return callback();
} }
return this.actor.deleteOwnedItem(itemId); game.l5r5e.HelpersL5r5e.confirmDeleteDialog(
game.i18n.format("l5r5e.global.delete_confirm", { name: tmpItem.name }),
callback
);
} }
/** /**
* Switch "in_curriculum" * Switch "in_curriculum"
* @param {Event} event
* @private * @private
*/ */
_switchSubItemCurriculum(event) { _switchSubItemCurriculum(event) {
@@ -358,9 +463,13 @@ export class BaseSheetL5r5e extends ActorSheet {
/** /**
* Switch Readied state on a weapon * Switch Readied state on a weapon
* @param {Event} event
* @private * @private
*/ */
_switchEquipReadied(event) { _switchEquipReadied(event) {
event.preventDefault();
event.stopPropagation();
const type = $(event.currentTarget).data("type"); const type = $(event.currentTarget).data("type");
if (!["equipped", "readied"].includes(type)) { if (!["equipped", "readied"].includes(type)) {
return; return;

View File

@@ -49,11 +49,6 @@ export class CharacterSheetL5r5e extends BaseSheetL5r5e {
// Split Money // Split Money
sheetData.data.money = this._zeniToMoney(this.actor.data.data.zeni); sheetData.data.money = this._zeniToMoney(this.actor.data.data.zeni);
// Sort Items by name
sheetData.items.sort((a, b) => {
return a.name.localeCompare(b.name);
});
// split advancements list by rank, and calculate xp spent // split advancements list by rank, and calculate xp spent
this._prepareAdvancement(sheetData); this._prepareAdvancement(sheetData);
sheetData.data.xp_saved = Math.floor(parseInt(sheetData.data.xp_total) - parseInt(sheetData.data.xp_spent)); sheetData.data.xp_saved = Math.floor(parseInt(sheetData.data.xp_total) - parseInt(sheetData.data.xp_spent));

View File

@@ -208,6 +208,7 @@ export class TwentyQuestionsDialog extends FormApplication {
html.find("#generate").on("click", async (event) => { html.find("#generate").on("click", async (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
$(event.currentTarget).prop("disabled", true);
await this.object.toActor(this.actor, flattenObject(this.cache)); await this.object.toActor(this.actor, flattenObject(this.cache));
await this.close({ submit: true, force: true }); await this.close({ submit: true, force: true });
}); });

View File

@@ -41,7 +41,7 @@ export class CombatL5r5e extends Combat {
// Get score for each combatant // Get score for each combatant
const updatedCombatants = []; const updatedCombatants = [];
ids.forEach((combatantId) => { for (const combatantId of ids) {
const combatant = game.combat.combatants.find((c) => c._id === combatantId); const combatant = game.combat.combatants.find((c) => c._id === combatantId);
// Skip if combatant already have a initiative value // Skip if combatant already have a initiative value
@@ -77,33 +77,49 @@ export class CombatL5r5e extends Combat {
formula = createFormula.join("+"); formula = createFormula.join("+");
} }
const roll = new game.l5r5e.RollL5r5e(formula); let roll;
roll.actor = combatant.actor; let rnkMessage;
roll.l5r5e.stance = data.stance; const flavor =
roll.l5r5e.skillId = skillId; game.i18n.localize("l5r5e.chatdices.initiative_roll") +
roll.l5r5e.skillCatId = skillCat; " (" +
roll.l5r5e.summary.difficulty = game.i18n.localize(`l5r5e.conflict.initiative.prepared_${isPrepared}`) +
messageOptions.difficulty !== undefined ? messageOptions.difficulty : cfg.difficulty; ")";
roll.l5r5e.summary.difficultyHidden =
messageOptions.difficultyHidden !== undefined
? messageOptions.difficultyHidden
: cfg.difficultyHidden;
roll.l5r5e.summary.voidPointUsed = !!messageOptions.useVoidPoint;
roll.roll(); if (messageOptions.rnkRoll instanceof game.l5r5e.RollL5r5e && ids.length === 1) {
roll.toMessage({ // Specific RnK
flavor: roll = messageOptions.rnkRoll;
game.i18n.localize("l5r5e.chatdices.initiative_roll") + rnkMessage = await roll.toMessage({ flavor });
" (" + } else {
game.i18n.localize(`l5r5e.conflict.initiative.prepared_${isPrepared}`) + // Regular
")", roll = new game.l5r5e.RollL5r5e(formula);
}); roll.actor = combatant.actor;
roll.l5r5e.isInitiativeRoll = true;
roll.l5r5e.stance = data.stance;
roll.l5r5e.skillId = skillId;
roll.l5r5e.skillCatId = skillCat;
roll.l5r5e.difficulty =
messageOptions.difficulty !== undefined ? messageOptions.difficulty : cfg.difficulty;
roll.l5r5e.difficultyHidden =
messageOptions.difficultyHidden !== undefined
? messageOptions.difficultyHidden
: cfg.difficultyHidden;
roll.l5r5e.voidPointUsed = !!messageOptions.useVoidPoint;
roll.l5r5e.skillAssistance = messageOptions.skillAssistance || 0;
roll.roll();
rnkMessage = await roll.toMessage({ flavor });
}
// Ugly but work... i need the new message
if (ids.length === 1) {
combatant.actor.rnkMessage = rnkMessage;
}
// if the character succeeded on their Initiative check, they add 1 to their base initiative value, // if the character succeeded on their Initiative check, they add 1 to their base initiative value,
// plus an additional amount equal to their bonus successes. // plus an additional amount equal to their bonus successes.
const successes = Math.min(roll.l5r5e.summary.ringsUsed, roll.l5r5e.summary.success); const successes = roll.l5r5e.summary.totalSuccess;
if (successes >= roll.l5r5e.summary.difficulty) { if (successes >= roll.l5r5e.difficulty) {
initiative = initiative + 1 + Math.max(successes - roll.l5r5e.summary.difficulty, 0); initiative = initiative + 1 + Math.max(successes - roll.l5r5e.difficulty, 0);
} }
} }
@@ -111,7 +127,7 @@ export class CombatL5r5e extends Combat {
_id: combatant._id, _id: combatant._id,
initiative: initiative, initiative: initiative,
}); });
}); }
// Update all combatants at once // Update all combatants at once
await this.updateEmbeddedEntity("Combatant", updatedCombatants); await this.updateEmbeddedEntity("Combatant", updatedCombatants);

View File

@@ -27,14 +27,15 @@ export class DicePickerDialog extends FormApplication {
skill: { skill: {
id: "", id: "",
value: 0, value: 0,
default_value: 0, defaultValue: 0,
cat: "", cat: "",
name: "", name: "",
assistance: 0,
}, },
difficulty: { difficulty: {
value: 2, value: 2,
hidden: false, hidden: false,
add_void_point: false, addVoidPoint: false,
}, },
useVoidPoint: false, useVoidPoint: false,
isInitiativeRoll: false, isInitiativeRoll: false,
@@ -50,8 +51,6 @@ export class DicePickerDialog extends FormApplication {
classes: ["l5r5e", "dice-picker-dialog"], classes: ["l5r5e", "dice-picker-dialog"],
template: CONFIG.l5r5e.paths.templates + "dice/dice-picker-dialog.html", template: CONFIG.l5r5e.paths.templates + "dice/dice-picker-dialog.html",
title: "L5R Dice Roller", title: "L5R Dice Roller",
width: 660,
height: 460,
actor: null, actor: null,
ringId: null, ringId: null,
skillId: "", skillId: "",
@@ -184,6 +183,7 @@ export class DicePickerDialog extends FormApplication {
} }
this.object.skill = { this.object.skill = {
...this.object.skill,
id: skillId.toLowerCase().trim(), id: skillId.toLowerCase().trim(),
value: 0, value: 0,
cat: "", cat: "",
@@ -215,13 +215,13 @@ export class DicePickerDialog extends FormApplication {
switch (this._actor.data.type) { switch (this._actor.data.type) {
case "character": case "character":
this.object.skill.value = this._actor.data.data.skills[skillCatId]?.[this.object.skill.id] || 0; this.object.skill.value = this._actor.data.data.skills[skillCatId]?.[this.object.skill.id] || 0;
this.object.skill.default_value = this.object.skill.value; this.object.skill.defaultValue = this.object.skill.value;
break; break;
case "npc": case "npc":
// Skill value is in categories for npc // Skill value is in categories for npc
this.object.skill.value = this._actor.data.data.skills[skillCatId] || 0; this.object.skill.value = this._actor.data.data.skills[skillCatId] || 0;
this.object.skill.default_value = this.object.skill.value; this.object.skill.defaultValue = this.object.skill.value;
break; break;
} }
} }
@@ -249,7 +249,7 @@ export class DicePickerDialog extends FormApplication {
isHidden = true; isHidden = true;
} }
this.object.difficulty.hidden = !!isHidden; this.object.difficulty.hidden = !!isHidden;
this.object.difficulty.add_void_point = this.object.difficulty.hidden; this.object.difficulty.addVoidPoint = this.object.difficulty.hidden;
this._updateVoidPointUsage(); this._updateVoidPointUsage();
} }
@@ -274,7 +274,7 @@ export class DicePickerDialog extends FormApplication {
actor: this._actor, actor: this._actor,
actorIsPc: !this._actor || this._actor.data?.type === "character", actorIsPc: !this._actor || this._actor.data?.type === "character",
canUseVoidPoint: canUseVoidPoint:
this.object.difficulty.add_void_point || !this._actor || this._actor.data.data.void_points.value > 0, this.object.difficulty.addVoidPoint || !this._actor || this._actor.data.data.void_points.value > 0,
disableSubmit: this.object.skill.value < 1 && this.object.ring.value < 1, disableSubmit: this.object.skill.value < 1 && this.object.ring.value < 1,
difficultyHiddenIsLock: this._difficultyHiddenIsLock, difficultyHiddenIsLock: this._difficultyHiddenIsLock,
}; };
@@ -323,11 +323,27 @@ export class DicePickerDialog extends FormApplication {
this.render(false); this.render(false);
}); });
// Skill assistance
html.find(".assistance").on("click", async (event) => {
event.preventDefault();
event.stopPropagation();
const assistanceAdd = $(event.currentTarget).data("value");
if (this.object.skill.assistance > 0 || assistanceAdd > 0) {
this._quantityChange("skill", assistanceAdd);
}
this.object.skill.assistance = Math.max(
Math.min(parseInt(this.object.skill.assistance) + assistanceAdd, 9),
0
);
this.render(false);
});
// Click on the Default Skill Dice // Click on the Default Skill Dice
html.find("#skill_default_value").on("click", async (event) => { html.find("#skill_default_value").on("click", async (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.object.skill.value = this.object.skill.default_value; this.object.skill.value = this.object.skill.defaultValue;
this.object.skill.assistance = 0;
this.render(false); this.render(false);
}); });
@@ -345,7 +361,7 @@ export class DicePickerDialog extends FormApplication {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.object.difficulty.hidden = !this.object.difficulty.hidden; this.object.difficulty.hidden = !this.object.difficulty.hidden;
this.object.difficulty.add_void_point = this.object.difficulty.hidden; this.object.difficulty.addVoidPoint = this.object.difficulty.hidden;
this._updateVoidPointUsage(); this._updateVoidPointUsage();
this.render(false); this.render(false);
}); });
@@ -354,7 +370,7 @@ export class DicePickerDialog extends FormApplication {
html.find("#diff_add_void_point").on("click", async (event) => { html.find("#diff_add_void_point").on("click", async (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.object.difficulty.add_void_point = !this.object.difficulty.add_void_point; this.object.difficulty.addVoidPoint = !this.object.difficulty.addVoidPoint;
this._updateVoidPointUsage(); this._updateVoidPointUsage();
this.render(false); this.render(false);
}); });
@@ -391,7 +407,7 @@ export class DicePickerDialog extends FormApplication {
} }
// If hidden add 1 void pt // If hidden add 1 void pt
if (this.object.difficulty.add_void_point) { if (this.object.difficulty.addVoidPoint) {
actorData.void_points.value = Math.min(actorData.void_points.value + 1, actorData.void_points.max); actorData.void_points.value = Math.min(actorData.void_points.value + 1, actorData.void_points.max);
} }
@@ -415,9 +431,10 @@ export class DicePickerDialog extends FormApplication {
formula.push(`${this.object.skill.value}ds`); formula.push(`${this.object.skill.value}ds`);
} }
let message;
if (this.object.isInitiativeRoll) { if (this.object.isInitiativeRoll) {
// Initiative roll // Initiative roll
this._actor.rollInitiative({ await this._actor.rollInitiative({
initiativeOptions: { initiativeOptions: {
formula: formula.join("+"), formula: formula.join("+"),
// updateTurn: true, // updateTurn: true,
@@ -426,9 +443,13 @@ export class DicePickerDialog extends FormApplication {
difficulty: this.object.difficulty.value, difficulty: this.object.difficulty.value,
difficultyHidden: this.object.difficulty.hidden, difficultyHidden: this.object.difficulty.hidden,
useVoidPoint: this.object.useVoidPoint, useVoidPoint: this.object.useVoidPoint,
skillAssistance: this.object.skill.assistance,
}, },
}, },
}); });
// Adhesive tape to get the messageId :/
message = this._actor.rnkMessage;
delete this._actor.rnkMessage;
} else { } else {
// Regular roll, so let's roll ! // Regular roll, so let's roll !
const roll = await new game.l5r5e.RollL5r5e(formula.join("+")); const roll = await new game.l5r5e.RollL5r5e(formula.join("+"));
@@ -437,12 +458,17 @@ export class DicePickerDialog extends FormApplication {
roll.l5r5e.stance = this.object.ring.id; roll.l5r5e.stance = this.object.ring.id;
roll.l5r5e.skillId = this.object.skill.id; roll.l5r5e.skillId = this.object.skill.id;
roll.l5r5e.skillCatId = this.object.skill.cat; roll.l5r5e.skillCatId = this.object.skill.cat;
roll.l5r5e.summary.difficulty = this.object.difficulty.value; roll.l5r5e.difficulty = this.object.difficulty.value;
roll.l5r5e.summary.difficultyHidden = this.object.difficulty.hidden; roll.l5r5e.difficultyHidden = this.object.difficulty.hidden;
roll.l5r5e.summary.voidPointUsed = this.object.useVoidPoint; roll.l5r5e.voidPointUsed = this.object.useVoidPoint;
roll.l5r5e.skillAssistance = this.object.skill.assistance;
await roll.roll(); await roll.roll();
await roll.toMessage(); message = await roll.toMessage();
}
if (message) {
new game.l5r5e.RollnKeepDialog(message._id).render(true);
} }
return this.close(); return this.close();
@@ -463,7 +489,7 @@ export class DicePickerDialog extends FormApplication {
_updateVoidPointUsage() { _updateVoidPointUsage() {
if ( if (
this.object.useVoidPoint && this.object.useVoidPoint &&
!this.object.difficulty.add_void_point && !this.object.difficulty.addVoidPoint &&
!!this._actor && !!this._actor &&
this._actor.data.data.void_points.value < 1 this._actor.data.data.void_points.value < 1
) { ) {

View File

@@ -18,8 +18,8 @@ export class AbilityDie extends L5rBaseDie {
8: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "skill_s" }, 8: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "skill_s" },
9: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "skill_s" }, 9: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "skill_s" },
10: { success: 1, explosive: 0, opportunity: 1, strife: 0, image: "skill_so" }, 10: { success: 1, explosive: 0, opportunity: 1, strife: 0, image: "skill_so" },
11: { success: 1, explosive: 1, opportunity: 0, strife: 1, image: "skill_et" }, 11: { success: 0, explosive: 1, opportunity: 0, strife: 1, image: "skill_et" },
12: { success: 1, explosive: 1, opportunity: 0, strife: 0, image: "skill_e" }, 12: { success: 0, explosive: 1, opportunity: 0, strife: 0, image: "skill_e" },
}; };
/** @override */ /** @override */

View File

@@ -14,6 +14,14 @@ export class L5rBaseDie extends DiceTerm {
this.l5r5e = { success: 0, explosive: 0, opportunity: 0, strife: 0 }; this.l5r5e = { success: 0, explosive: 0, opportunity: 0, strife: 0 };
} }
/**
* Return the total number of success + explosives
* @returns {number}
*/
get totalSuccess() {
return this.l5r5e.success + this.l5r5e.explosive;
}
/** /**
* Return a standardized representation for the displayed formula associated with this DiceTerm * Return a standardized representation for the displayed formula associated with this DiceTerm
* @override * @override
@@ -64,13 +72,7 @@ export class L5rBaseDie extends DiceTerm {
this._evaluateModifiers(); this._evaluateModifiers();
// Combine all results // Combine all results
this.l5r5e = { success: 0, explosive: 0, opportunity: 0, strife: 0 }; this.l5rSummary();
this.results.forEach((term) => {
const face = this.constructor.FACES[term.result];
["success", "explosive", "opportunity", "strife"].forEach((props) => {
this.l5r5e[props] += parseInt(face[props]);
});
});
// Return the evaluated term // Return the evaluated term
this._evaluated = true; this._evaluated = true;
@@ -79,24 +81,36 @@ export class L5rBaseDie extends DiceTerm {
return this; return this;
} }
/**
* Summarise the total of success, strife... for L5R dices for the current Die
*/
l5rSummary() {
this.l5r5e = { success: 0, explosive: 0, opportunity: 0, strife: 0 };
this.results.forEach((term) => {
const face = this.constructor.FACES[term.result];
["success", "explosive", "opportunity", "strife"].forEach((props) => {
this.l5r5e[props] += parseInt(face[props]);
});
if (face.explosive) {
term.exploded = true;
}
});
}
/** /**
* Roll the DiceTerm by mapping a random uniform draw against the faces of the dice term * Roll the DiceTerm by mapping a random uniform draw against the faces of the dice term
* @override * @override
*/ */
roll(options) { roll(options) {
const roll = super.roll(options); const roll = super.roll(options);
//roll.l5r5e = this.l5r5e; //roll.l5r5e = this.l5r5e;
return roll; return roll;
} }
/** @override */ /** @override */
static fromData(data) { static fromData(data) {
const roll = super.fromData(data); const roll = super.fromData(data);
roll.l5r5e = data.l5r5e; roll.l5r5e = data.l5r5e;
return roll; return roll;
} }
@@ -106,9 +120,7 @@ export class L5rBaseDie extends DiceTerm {
*/ */
toJSON() { toJSON() {
const json = super.toJSON(); const json = super.toJSON();
json.l5r5e = this.l5r5e; json.l5r5e = this.l5r5e;
return json; return json;
} }
} }

View File

@@ -13,7 +13,7 @@ export class RingDie extends L5rBaseDie {
3: { success: 0, explosive: 0, opportunity: 1, strife: 0, image: "ring_o" }, 3: { success: 0, explosive: 0, opportunity: 1, strife: 0, image: "ring_o" },
4: { success: 1, explosive: 0, opportunity: 0, strife: 1, image: "ring_st" }, 4: { success: 1, explosive: 0, opportunity: 0, strife: 1, image: "ring_st" },
5: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "ring_s" }, 5: { success: 1, explosive: 0, opportunity: 0, strife: 0, image: "ring_s" },
6: { success: 1, explosive: 1, opportunity: 0, strife: 1, image: "ring_et" }, 6: { success: 0, explosive: 1, opportunity: 0, strife: 1, image: "ring_et" },
}; };
/** @override */ /** @override */

View File

@@ -1,5 +1,5 @@
/** /**
* L5R Initiative Roll dialog * L5R GM Toolbox dialog
* @extends {FormApplication} * @extends {FormApplication}
*/ */
export class GmToolsDialog extends FormApplication { export class GmToolsDialog extends FormApplication {
@@ -19,12 +19,9 @@ export class GmToolsDialog extends FormApplication {
id: "l5r5e-gm-tools-dialog", id: "l5r5e-gm-tools-dialog",
classes: ["l5r5e", "gm-tools-dialog"], classes: ["l5r5e", "gm-tools-dialog"],
template: CONFIG.l5r5e.paths.templates + "dice/gm-tools-dialog.html", template: CONFIG.l5r5e.paths.templates + "dice/gm-tools-dialog.html",
title: game.i18n.localize("l5r5e.dicepicker.difficulty_title"), title: game.i18n.localize("l5r5e.gm_toolbox.title"),
width: 200, // ignored under 200px left: x - 512,
height: 130, // ignored under 50px top: y - 98,
scale: 0.5, // so scale /2 :D
left: x - 470,
top: y - 94,
closeOnSubmit: false, closeOnSubmit: false,
submitOnClose: false, submitOnClose: false,
submitOnChange: true, submitOnChange: true,
@@ -37,6 +34,25 @@ export class GmToolsDialog extends FormApplication {
*/ */
constructor(options = {}) { constructor(options = {}) {
super(options); super(options);
this._initialize();
}
/**
* Refresh data (used from socket)
*/
async refresh() {
if (!game.user.isGM) {
return;
}
this._initialize();
this.render(false);
}
/**
* Initialize the values
* @private
*/
_initialize() {
this.object = { this.object = {
difficulty: game.settings.get("l5r5e", "initiative.difficulty.value"), difficulty: game.settings.get("l5r5e", "initiative.difficulty.value"),
difficultyHidden: game.settings.get("l5r5e", "initiative.difficulty.hidden"), difficultyHidden: game.settings.get("l5r5e", "initiative.difficulty.hidden"),
@@ -67,6 +83,8 @@ export class GmToolsDialog extends FormApplication {
if (!game.user.isGM) { if (!game.user.isGM) {
return false; return false;
} }
this.position.width = "auto";
this.position.height = "auto";
return super.render(force, options); return super.render(force, options);
} }
@@ -104,6 +122,8 @@ export class GmToolsDialog extends FormApplication {
// Modify difficulty hidden // Modify difficulty hidden
html.find(`.difficulty_hidden`).on("click", (event) => { html.find(`.difficulty_hidden`).on("click", (event) => {
event.preventDefault();
event.stopPropagation();
this.object.difficultyHidden = !this.object.difficultyHidden; this.object.difficultyHidden = !this.object.difficultyHidden;
game.settings game.settings
.set("l5r5e", "initiative.difficulty.hidden", this.object.difficultyHidden) .set("l5r5e", "initiative.difficulty.hidden", this.object.difficultyHidden)
@@ -130,6 +150,13 @@ export class GmToolsDialog extends FormApplication {
} }
game.settings.set("l5r5e", "initiative.difficulty.value", this.object.difficulty).then(() => this.submit()); game.settings.set("l5r5e", "initiative.difficulty.value", this.object.difficulty).then(() => this.submit());
}); });
// Scene End & Sleep
html.find(`.gm_actor_updates`).on("click", (event) => {
event.preventDefault();
event.stopPropagation();
this._updatesActors($(event.currentTarget).data("type"));
});
} }
/** /**
@@ -140,15 +167,54 @@ export class GmToolsDialog extends FormApplication {
* @override * @override
*/ */
async _updateObject(event, formData) { async _updateObject(event, formData) {
// Notify the change to other players if they already have opened the DicePicker
game.l5r5e.sockets.refreshAppId("l5r5e-dice-picker-dialog");
// If the current GM also have the DP open
const app = Object.values(ui.windows).find((e) => e.id === "l5r5e-dice-picker-dialog");
if (app && typeof app.refresh === "function") {
app.refresh();
}
this.render(false); this.render(false);
} }
/**
* Update all actors
* @param {string} type
* @private
*/
_updatesActors(type) {
if (!game.user.isGM) {
return;
}
game.actors.entities.forEach((actor) => {
switch (type) {
case "sleep":
// Remove 'water x2' fatigue points
actor.data.data.fatigue.value = Math.max(
0,
actor.data.data.fatigue.value - Math.ceil(actor.data.data.rings.water * 2)
);
break;
case "scene_end":
// If more than half the value => roundup half conflit & fatigue
actor.data.data.fatigue.value = Math.min(
actor.data.data.fatigue.value,
Math.ceil(actor.data.data.fatigue.max / 2)
);
actor.data.data.strife.value = Math.min(
actor.data.data.strife.value,
Math.ceil(actor.data.data.strife.max / 2)
);
break;
}
actor.update({
data: {
fatigue: {
value: actor.data.data.fatigue.value,
},
strife: {
value: actor.data.data.strife.value,
},
},
});
});
ui.notifications.info(game.i18n.localize(`l5r5e.gm_toolbox.${type}_info`));
}
} }

View File

@@ -8,23 +8,35 @@ export class RollnKeepDialog extends FormApplication {
*/ */
static CHOICES = { static CHOICES = {
discard: "discard", discard: "discard",
face_change: "face-change",
keep: "keep", keep: "keep",
nothing: null, nothing: null,
reroll: "reroll", reroll: "reroll",
reserve: "reserve", // reserve: "reserve",
swap: "swap",
}; };
/** /**
* The current ChatMessage where we come from * The current ChatMessage where we come from
* @param {ChatMessage} message * @param {ChatMessage} message
*/ */
message = null; _message = null;
/**
* The current Roll
* @param {RollL5r5e} roll
*/
roll = null;
/** /**
* Payload Object * Payload Object
*/ */
object = { object = {
currentStep: 0,
submitDisabled: false,
swapDiceFaces: {
rings: [],
skills: [],
},
dicesList: [[]], dicesList: [[]],
}; };
@@ -38,59 +50,102 @@ export class RollnKeepDialog extends FormApplication {
classes: ["l5r5e", "roll-n-keep-dialog"], classes: ["l5r5e", "roll-n-keep-dialog"],
template: CONFIG.l5r5e.paths.templates + "dice/roll-n-keep-dialog.html", template: CONFIG.l5r5e.paths.templates + "dice/roll-n-keep-dialog.html",
title: game.i18n.localize("l5r5e.roll_n_keep.title"), title: game.i18n.localize("l5r5e.roll_n_keep.title"),
width: 660, closeOnSubmit: false,
height: 660,
}); });
} }
/** /**
* Define a unique and dynamic element ID for the rendered ActorSheet application * Define a unique and dynamic element ID for the rendered application
*/ */
get id() { get id() {
return `l5r5e-roll-n-keep-dialog-${this.message._id}`; return `l5r5e-roll-n-keep-dialog-${this._message._id}`;
}
/**
* ChatMessage
* @param {ChatMessage} msg
*/
set message(msg) {
this._message = msg instanceof ChatMessage ? msg : null;
}
/**
* ChatMessage
* @returns {ChatMessage}
*/
get message() {
return this._message;
} }
/** /**
* Create the Roll n Keep dialog * Create the Roll n Keep dialog
* @param {ChatMessage} message * @param {number} messageId
* @param {FormApplicationOptions} options * @param {FormApplicationOptions} options
*/ */
constructor(message, options = {}) { constructor(messageId, options = {}) {
super({}, options); super({}, options);
this.message = message; this.message = game.messages.get(messageId);
this._initialize(); this.options.editable =
this._message?.isAuthor || this._message?._roll.l5r5e.actor?.owner || this._message?.owner || false;
this._initializeDiceFaces();
this._initializeHistory();
} }
/** /**
* Refresh data (used from socket) * Refresh data (used from socket)
*/ */
async refresh() { async refresh() {
if (!this.message) { if (!this._message) {
return; return;
} }
this._initialize(); this._initializeHistory();
this.render(false); this.render(false);
} }
/** /**
* Initialize the dialog with the message * Render
* @param {boolean} force
* @param {RenderOptions} options
* @returns {Application}
* @override
*/
render(force = null, options = {}) {
if (!this._message) {
return;
}
this.position.width = "auto";
this.position.height = "auto";
return super.render(force, options);
}
/**
* Initialize the dice history list
* @private * @private
*/ */
_initialize() { _initializeHistory() {
// Get the roll if (!this._message) {
const roll = game.l5r5e.RollL5r5e.fromData(this.message.roll); return;
}
console.clear(); // Get the roll
console.log(roll); // TODO TMP this.roll = game.l5r5e.RollL5r5e.fromData(this._message._roll);
// Already history // Already history
if (Array.isArray(roll.l5r5e.history)) { if (Array.isArray(this.roll.l5r5e.history)) {
this.object.dicesList = roll.l5r5e.history; this.object.dicesList = this.roll.l5r5e.history;
let currentStep = this.roll.l5r5e.history.length - 1;
if (!this._haveChoice(currentStep, RollnKeepDialog.CHOICES.nothing)) {
currentStep += 1;
}
this.object.currentStep = currentStep;
return; return;
} }
// New // New
roll.terms.forEach((term) => { this.object.dicesList = [[]];
this.roll.terms.forEach((term) => {
if (typeof term !== "object") { if (typeof term !== "object") {
return; return;
} }
@@ -98,14 +153,24 @@ export class RollnKeepDialog extends FormApplication {
this.object.dicesList[0].push({ this.object.dicesList[0].push({
type: term.constructor.name, type: term.constructor.name,
face: res.result, face: res.result,
explosive: term.constructor.FACES[res.result].explosive,
img: term.constructor.getResultSrc(res.result),
choice: RollnKeepDialog.CHOICES.nothing, choice: RollnKeepDialog.CHOICES.nothing,
}); });
}); });
}); });
} }
/**
* Fill the dices faces
* @private
*/
_initializeDiceFaces() {
// All faces are unique for rings
this.object.swapDiceFaces.rings = Object.keys(game.l5r5e.RingDie.FACES);
// Only unique for Skills
this.object.swapDiceFaces.skills = [1, 3, 6, 8, 10, 11, 12];
}
/** /**
* Create drag-and-drop workflow handlers for this Application * Create drag-and-drop workflow handlers for this Application
* @return An array of DragDrop handlers * @return An array of DragDrop handlers
@@ -121,6 +186,15 @@ export class RollnKeepDialog extends FormApplication {
]; ];
} }
/**
* Define whether a user is able to begin a dragstart workflow for a given drag selector
* @param selector The candidate HTML selector for dragging
* @return Can the current user drag this selector?
*/
_canDragStart(selector) {
return this.options.editable;
}
/** /**
* Callback actions which occur at the beginning of a drag start workflow. * Callback actions which occur at the beginning of a drag start workflow.
* @param {DragEvent} event The originating DragEvent * @param {DragEvent} event The originating DragEvent
@@ -142,20 +216,23 @@ export class RollnKeepDialog extends FormApplication {
* @return {Object} * @return {Object}
*/ */
getData(options = null) { getData(options = null) {
const draggableList = []; // Disable submit / edition
this.object.dicesList.forEach((step, idx) => { this.options.classes = this.options.classes.filter((e) => e !== "finalized");
step.forEach((die, dieNum) => { this.object.submitDisabled = false;
if (die) {
draggableList[dieNum] = idx; if (this._checkKeepCount(this.object.currentStep)) {
} const kept = this._getKeepCount(this.object.currentStep);
}); this.object.submitDisabled = kept < 1 || kept > this.roll.l5r5e.keepLimit;
}); } else if (!this.object.dicesList[this.object.currentStep]) {
this.options.editable = false;
this.options.classes.push("finalized");
}
return { return {
...super.getData(options), ...super.getData(options),
cssClass: this.options.classes.join(" "),
data: this.object, data: this.object,
draggableList: draggableList, l5r5e: this.roll.l5r5e,
l5r5e: this.message._roll.l5r5e,
}; };
} }
@@ -166,11 +243,28 @@ export class RollnKeepDialog extends FormApplication {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
// GM Only, need to be before the editable check
if (game.user.isGM && this.object.currentStep > 0) {
// Add Context menu to rollback choices
new ContextMenu(html, ".l5r5e.profil", [
{
name: game.i18n.localize("l5r5e.roll_n_keep.undo"),
icon: '<i class="fas fa-undo"></i>',
callback: () => this._undoLastStepChoices(),
},
]);
}
// *** Everything below here is only needed if the sheet is editable ***
if (!this.options.editable) {
return;
}
// Finalize Button // Finalize Button
html.find("#finalize").on("click", (event) => { html.find("#finalize").on("click", (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
if (this._getKeepCount() > 0) { if (!this.object.submitDisabled) {
this.submit(); this.submit();
} }
}); });
@@ -180,6 +274,11 @@ export class RollnKeepDialog extends FormApplication {
* Handle dropped items * Handle dropped items
*/ */
async _onDropItem(event) { async _onDropItem(event) {
// *** Everything below here is only needed if the sheet is editable ***
if (!this.options.editable) {
return;
}
const type = $(event.currentTarget).data("type"); const type = $(event.currentTarget).data("type");
const json = event.dataTransfer.getData("text/plain"); const json = event.dataTransfer.getData("text/plain");
if (!json || !Object.values(RollnKeepDialog.CHOICES).some((e) => !!e && e === type)) { if (!json || !Object.values(RollnKeepDialog.CHOICES).some((e) => !!e && e === type)) {
@@ -191,81 +290,361 @@ export class RollnKeepDialog extends FormApplication {
return; return;
} }
let addNewRoll = false;
const current = this.object.dicesList[data.step][data.die]; const current = this.object.dicesList[data.step][data.die];
current.choice = type; delete current.newFace;
// Actions p 26 : change, ignore/discard, reroll, reserve, change face
switch (type) { switch (type) {
case RollnKeepDialog.CHOICES.keep: case RollnKeepDialog.CHOICES.swap: {
if (current.explosive) { // Dice Type Ring/Skill
addNewRoll = true; const diceType = $(event.currentTarget).data("die");
const diceNewFace = $(event.currentTarget).data("face");
if (current.type !== diceType || current.face === diceNewFace) {
current.choice = RollnKeepDialog.CHOICES.nothing;
this.render(false);
return false;
} }
current.newFace = diceNewFace;
break; break;
}
case RollnKeepDialog.CHOICES.reroll: case RollnKeepDialog.CHOICES.reroll:
addNewRoll = true; // If reroll, we need to keep all the line by default
this._forceChoiceForDiceWithoutOne(RollnKeepDialog.CHOICES.keep);
break; break;
} }
// New roll current.choice = type;
if (addNewRoll) {
if (!this.object.dicesList[data.step + 1]) { // Little time saving : if we reach the max kept dices, discard all dices without a choice
this.object.dicesList[data.step + 1] = Array(this.object.dicesList[0].length).fill(null); if (
} this._checkKeepCount(this.object.currentStep) &&
this.object.dicesList[data.step + 1][data.die] = await this._newRoll(current.type, type); this._getKeepCount(this.object.currentStep) === this.roll.l5r5e.keepLimit
) {
this._forceChoiceForDiceWithoutOne(RollnKeepDialog.CHOICES.discard);
} }
this.render(false); this.render(false);
return false; return false;
} }
/**
* Roll a new die avec return the result
* @private
*/
async _newRoll(dieType, actionType) {
const roll = await new game.l5r5e.RollL5r5e(dieType === "RingDie" ? "1dr" : "1ds");
roll.actor = this.message.roll.l5r5e.actor;
roll.l5r5e.stance = this.message.roll.l5r5e.stance;
// roll.l5r5e.skillId = this.message.roll.l5r5e.skillId;
// roll.l5r5e.skillCatId = this.message.roll.l5r5e.skillCatId;
await roll.roll();
await roll.toMessage({
flavor: game.i18n.localize(`l5r5e.roll_n_keep.${actionType}_chat`),
});
const dice = roll.terms[0];
const result = dice.results[0].result;
return {
type: dieType,
face: result,
explosive: dice.constructor.FACES[result].explosive,
img: dice.constructor.getResultSrc(result),
choice: RollnKeepDialog.CHOICES.nothing,
};
}
/** /**
* Return the current number of dices kept * Return the current number of dices kept
* @private * @private
*/ */
_getKeepCount() { _getKeepCount(step) {
return this.object.dicesList.reduce((acc, step) => { return this.object.dicesList[step].reduce((acc, die) => {
return ( if (
acc + !!die &&
step.reduce((acc2, die) => { [RollnKeepDialog.CHOICES.keep, RollnKeepDialog.CHOICES.reroll, RollnKeepDialog.CHOICES.swap].includes(
if (!!die && die.choice === RollnKeepDialog.CHOICES.keep) { die.choice
acc2 = acc2 + 1; )
} ) {
return acc2; acc = acc + 1;
}, 0) }
); return acc;
}, 0); }, 0);
} }
/**
* Return true if a "_getKeepCount" is needed
* @param {number} step
* @returns {boolean}
* @private
*/
_checkKeepCount(step) {
return (
!this._haveChoice(step, RollnKeepDialog.CHOICES.reroll) &&
(step === 0 || this._haveChoice(step - 1, RollnKeepDialog.CHOICES.reroll))
);
}
/**
* Return true if this choice exist in the current step
* @private
*/
_haveChoice(currentStep, choice) {
return (
this.object.dicesList[currentStep] &&
this.object.dicesList[currentStep].some((e) => !!e && e.choice === choice)
);
}
/**
* Discard all dices without a choice for the current step
* @param {string} newChoice
* @private
*/
_forceChoiceForDiceWithoutOne(newChoice) {
this.object.dicesList[this.object.currentStep]
.filter((e) => !!e)
.map((e) => {
if (e.choice === RollnKeepDialog.CHOICES.nothing) {
e.choice = newChoice;
}
return e;
});
}
/**
* Initialize dice array for "step" if needed
* @param {number} step
* @private
*/
_initializeDicesListStep(step) {
if (!this.object.dicesList[step]) {
this.object.dicesList[step] = Array(this.object.dicesList[0].length).fill(null);
}
}
/**
* Apply all choices to build the next step
* @returns {Promise<void>}
* @private
*/
async _applyChoices() {
const nextStep = this.object.currentStep + 1;
const haveReroll = this._haveChoice(this.object.currentStep, RollnKeepDialog.CHOICES.reroll);
// Foreach kept dices, apply choices
const newRolls = {};
this.object.dicesList[this.object.currentStep].forEach((die, idx) => {
if (!die) {
return;
}
switch (die.choice) {
case RollnKeepDialog.CHOICES.keep:
if (haveReroll) {
// Reroll line add all kept into a new line
this._initializeDicesListStep(nextStep);
this.object.dicesList[nextStep][idx] = duplicate(
this.object.dicesList[this.object.currentStep][idx]
);
this.object.dicesList[nextStep][idx].choice = RollnKeepDialog.CHOICES.nothing;
this.object.dicesList[this.object.currentStep][idx].choice = RollnKeepDialog.CHOICES.discard;
} else if (game.l5r5e[die.type].FACES[die.face].explosive) {
// Exploding dice : add a new dice in the next step
if (!newRolls[die.type]) {
newRolls[die.type] = 0;
}
newRolls[die.type] += 1;
}
break;
case RollnKeepDialog.CHOICES.reroll:
// Reroll : add a new dice in the next step
if (!newRolls[die.type]) {
newRolls[die.type] = 0;
}
newRolls[die.type] += 1;
break;
case RollnKeepDialog.CHOICES.swap:
// FaceSwap : add a new dice with selected face in next step
this._initializeDicesListStep(nextStep);
this.object.dicesList[nextStep][idx] = {
type: this.object.dicesList[this.object.currentStep][idx].type,
face: this.object.dicesList[this.object.currentStep][idx].newFace,
choice: RollnKeepDialog.CHOICES.keep,
};
delete this.object.dicesList[this.object.currentStep][idx].newFace;
break;
}
});
// If new rolls, roll and add them
if (Object.keys(newRolls).length > 0) {
const newRollsResults = await this._newRoll(newRolls);
this._initializeDicesListStep(nextStep);
this.object.dicesList[this.object.currentStep].forEach((die, idx) => {
if (!die) {
return;
}
if (
die.choice === RollnKeepDialog.CHOICES.reroll ||
(!haveReroll &&
die.choice === RollnKeepDialog.CHOICES.keep &&
game.l5r5e[die.type].FACES[die.face].explosive)
) {
this.object.dicesList[nextStep][idx] = newRollsResults[die.type].shift();
}
});
}
}
/**
* Transform a array (of int or object) into a formula ring/skill
* @param rolls
* @returns {string}
* @private
*/
_arrayToFormula(rolls) {
const formula = [];
if (rolls["RingDie"]) {
const rings = Array.isArray(rolls["RingDie"]) ? rolls["RingDie"].length : rolls["RingDie"];
formula.push(rings + "dr");
}
if (rolls["AbilityDie"]) {
const skills = Array.isArray(rolls["AbilityDie"]) ? rolls["AbilityDie"].length : rolls["AbilityDie"];
formula.push(skills + "ds");
}
if (formula.length < 1) {
return "";
}
return formula.join("+");
}
/**
* Roll all new dice at once (better performance) and return the result
* @private
*/
async _newRoll(newRolls) {
const out = {
RingDie: [],
AbilityDie: [],
};
const roll = await new game.l5r5e.RollL5r5e(this._arrayToFormula(newRolls));
await roll.roll();
// Show DsN dice for the new roll
if (game.dice3d !== undefined) {
game.dice3d.showForRoll(roll, game.user, true);
}
roll.terms.forEach((term) => {
if (typeof term !== "object") {
return;
}
term.results.forEach((res) => {
out[term.constructor.name].push({
type: term.constructor.name,
face: res.result,
choice: RollnKeepDialog.CHOICES.nothing,
});
});
});
return out;
}
/**
* Rebuild the message roll
* @param {boolean} forceKeep If true keep all dice regardless their choice
* @returns {Promise<void>}
* @private
*/
async _rebuildRoll(forceKeep = false) {
// Get all kept dices + new (choice null)
const diceList = this.object.dicesList.reduce((acc, step, stepIdx) => {
const haveReroll = stepIdx > 0 && this._haveChoice(stepIdx - 1, RollnKeepDialog.CHOICES.reroll);
step.forEach((die, idx) => {
if (
!!die &&
(forceKeep ||
die.choice === RollnKeepDialog.CHOICES.keep ||
(haveReroll && die.choice === RollnKeepDialog.CHOICES.nothing))
) {
if (!acc[die.type]) {
acc[die.type] = [];
}
// Check previous dice, to add html classes in chat
if (stepIdx > 0 && this.object.dicesList[stepIdx - 1][idx]) {
switch (this.object.dicesList[stepIdx - 1][idx].choice) {
case RollnKeepDialog.CHOICES.reroll:
die.class = "rerolled";
break;
case RollnKeepDialog.CHOICES.swap:
die.class = "swapped";
break;
}
}
acc[die.type].push(die);
}
});
return acc;
}, {});
// Re create a new roll
const roll = await new game.l5r5e.RollL5r5e(this._arrayToFormula(diceList));
roll.l5r5e = {
...this.roll.l5r5e,
summary: roll.l5r5e.summary,
};
// Fill the data
roll.evaluate();
// Modify results
roll.terms.map((term) => {
if (term instanceof game.l5r5e.L5rBaseDie) {
term.results.map((res) => {
const die = diceList[term.constructor.name].shift();
res.result = die.face;
// add class to term result
if (die.class) {
res[die.class] = true;
}
return res;
});
term.l5rSummary();
}
return term;
});
// Recompute summary
roll.l5rSummary();
// Add roll & history to message
this.roll = roll;
this.roll.l5r5e.history = this.object.dicesList;
}
/**
* Send the new roll in chat and delete the old message
* @returns {Promise<void>}
* @private
*/
async _toChatMessage() {
// Keep old Ids
const appOldId = this.id;
const msgOldId = this._message._id;
if (this.roll.l5r5e.isInitiativeRoll) {
await this.roll.l5r5e.actor.rollInitiative({
rerollInitiative: true,
initiativeOptions: {
messageOptions: {
rnkRoll: this.roll,
},
},
});
// Adhesive tape to get the message :/
this.message = this.roll.l5r5e.actor.rnkMessage;
delete this.roll.l5r5e.actor.rnkMessage;
} else {
// Send it to chat, switch to new message
this.message = await this.roll.toMessage();
}
// Refresh viewers
game.l5r5e.sockets.updateMessageIdAndRefresh(appOldId, this._message._id);
// Delete old chat message related to this series
if (game.settings.get("l5r5e", "rnk.deleteOldMessage")) {
if (game.user.isGM) {
const message = game.messages.get(msgOldId);
if (message) {
message.delete();
}
} else {
game.l5r5e.sockets.deleteChatMessage(msgOldId);
}
}
}
/** /**
* This method is called upon form submission after form data is validated * This method is called upon form submission after form data is validated
* @param event The initial triggering submission event * @param event The initial triggering submission event
@@ -274,32 +653,66 @@ export class RollnKeepDialog extends FormApplication {
* @override * @override
*/ */
async _updateObject(event, formData) { async _updateObject(event, formData) {
console.log("**** _updateObject"); // *** Everything below here is only needed if the sheet is editable ***
if (!this.options.editable) {
return;
}
// Notify the change to other players // Discard all dices without a choice for the current step
// game.l5r5e.sockets.refreshAppId(this.id); this._forceChoiceForDiceWithoutOne(RollnKeepDialog.CHOICES.discard);
// this.message._roll.l5r5e.history = {test: "yahooo"}; // Apply all choices to build the next step
await this._applyChoices();
// await message.update({ // *** Below this the current step become the next step ***
// data: { this.object.currentStep++;
// roll: roll
// }
// });
// message.render(false);
// console.log(roll.toJSON(), this.message); // Rebuild the roll
await this._rebuildRoll(false);
// ui.chat.updateMessage(message); // Send the new roll in chat and delete the old message
// ui.chat.postOne(message, false); await this._toChatMessage();
// if (game.user.isGM) { // If a next step exist, rerender, else close
// message.delete(); if (this.object.dicesList[this.object.currentStep]) {
// } else { return this.render(false);
// game.l5r5e.sockets.deleteChatMessage(messageId); }
// } return this.close();
}
// return this.close(); /**
* Undo the last step choice
* @returns {Promise<Application|any>}
* @private
*/
async _undoLastStepChoices() {
// Find the step to work to
this.object.currentStep = this.object.dicesList[this.object.currentStep]
? this.object.currentStep
: Math.max(0, this.object.currentStep - 1);
// If all clear, delete this step
if (this._haveChoice(this.object.currentStep, RollnKeepDialog.CHOICES.nothing)) {
if (this.object.currentStep === 0) {
return;
}
this.object.dicesList.pop();
this.object.dicesList = this.object.dicesList.filter((e) => !!e);
this.object.currentStep--;
}
// Clear choices
this.object.dicesList[this.object.currentStep]
.filter((e) => !!e)
.map((e) => {
e.choice = RollnKeepDialog.CHOICES.nothing;
return e;
});
this.options.editable = true;
await this._rebuildRoll(true);
await this._toChatMessage();
return this.render(false);
} }
/** /**
@@ -309,21 +722,22 @@ export class RollnKeepDialog extends FormApplication {
*/ */
static async onChatAction(event) { static async onChatAction(event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
// Extract card data // Extract card data
const button = $(event.currentTarget); const button = $(event.currentTarget);
button.attr("disabled", true); button.attr("disabled", true);
const card = button.parents(".l5r5e.item-display.dices-l5r"); const card = button.parents(".l5r5e.item-display.dices-l5r");
const messageId = card.parents(".chat-message").data("message-id"); const messageId = card.parents(".chat-message").data("message-id");
const message = game.messages.get(messageId);
// Validate permission to proceed with the roll n keep // Already open ? close it
if (!message || !message._roll.l5r5e.actor.owner) { const app = Object.values(ui.windows).find((e) => e.id === `l5r5e-roll-n-keep-dialog-${messageId}`);
return; if (app) {
app.close();
} else {
new RollnKeepDialog(messageId).render(true);
} }
new RollnKeepDialog(message).render(true);
// Re-enable the button // Re-enable the button
button.attr("disabled", false); button.attr("disabled", false);
} }

View File

@@ -13,15 +13,20 @@ export class RollL5r5e extends Roll {
skillId: "", skillId: "",
skillCatId: "", skillCatId: "",
actor: null, actor: null,
difficulty: 2,
difficultyHidden: false,
voidPointUsed: false,
keepLimit: null,
isInitiativeRoll: false,
skillAssistance: 0,
initialFormula: null,
dicesTypes: { dicesTypes: {
std: false, std: false,
l5r: false, l5r: false,
}, },
summary: { summary: {
difficulty: 2, totalSuccess: 0,
difficultyHidden: false, totalBonus: 0,
voidPointUsed: false,
ringsUsed: 0,
success: 0, success: 0,
explosive: 0, explosive: 0,
opportunity: 0, opportunity: 0,
@@ -40,8 +45,6 @@ export class RollL5r5e extends Roll {
this.l5r5e.skillId = res[2]; this.l5r5e.skillId = res[2];
} }
}); });
// TODO parse difficulty stance skillId from cmd line ?
} }
set actor(actor) { set actor(actor) {
@@ -68,23 +71,15 @@ export class RollL5r5e extends Roll {
// Roll // Roll
super.evaluate({ minimize, maximize }); super.evaluate({ minimize, maximize });
// Current terms - L5R Summary
this.terms.forEach((term) => this._l5rSummary(term));
// Check inner L5R rolls - L5R Summary
this._dice.forEach((term) => this._l5rSummary(term));
// Store final outputs
this._rolled = true; this._rolled = true;
this.l5r5e.dicesTypes.std = this.dice.some(
(term) => term instanceof DiceTerm && !(term instanceof game.l5r5e.L5rBaseDie) // Save initial formula
); // ignore math symbols if (!this.l5r5e.initialFormula) {
this.l5r5e.dicesTypes.l5r = this.dice.some((term) => term instanceof game.l5r5e.L5rBaseDie); this.l5r5e.initialFormula = this.formula;
this.l5r5e.summary.ringsUsed = this.dice.reduce( }
(acc, term) => (term instanceof game.l5r5e.RingDie ? acc + term.number : acc),
0 // Compute summary
); this.l5rSummary();
return this; return this;
} }
@@ -92,10 +87,54 @@ export class RollL5r5e extends Roll {
/** /**
* Summarise the total of success, strife... for L5R dices for the current roll * Summarise the total of success, strife... for L5R dices for the current roll
* *
* @private
*/
l5rSummary() {
const summary = this.l5r5e.summary;
// Reset totals
summary.success = 0;
summary.explosive = 0;
summary.opportunity = 0;
summary.strife = 0;
summary.totalSuccess = 0;
// Current terms - L5R Summary
this.terms.forEach((term) => this._l5rTermSummary(term));
// Check inner L5R rolls - L5R Summary
this._dice.forEach((term) => this._l5rTermSummary(term));
// Store final outputs
this.l5r5e.dicesTypes.std = this.dice.some(
(term) => term instanceof DiceTerm && !(term instanceof game.l5r5e.L5rBaseDie)
); // ignore math symbols
this.l5r5e.dicesTypes.l5r = this.dice.some((term) => term instanceof game.l5r5e.L5rBaseDie);
summary.totalBonus = Math.max(0, summary.totalSuccess - this.l5r5e.difficulty);
if (!this.l5r5e.keepLimit) {
// count ring die + skill assistance
this.l5r5e.keepLimit =
this.dice.reduce((acc, term) => (term instanceof game.l5r5e.RingDie ? acc + term.number : acc), 0) +
Math.max(0, this.l5r5e.skillAssistance || 0);
// if only bulk skill dice, count the skill dice
if (!this.l5r5e.keepLimit) {
this.l5r5e.keepLimit = this.dice.reduce(
(acc, term) => (term instanceof game.l5r5e.AbilityDie ? acc + term.number : acc),
0
);
}
}
}
/**
* Summarise the total of success, strife... for L5R dices for the current term
*
* @param term * @param term
* @private * @private
*/ */
_l5rSummary(term) { _l5rTermSummary(term) {
if (!(term instanceof game.l5r5e.L5rBaseDie)) { if (!(term instanceof game.l5r5e.L5rBaseDie)) {
return; return;
} }
@@ -103,6 +142,8 @@ export class RollL5r5e extends Roll {
["success", "explosive", "opportunity", "strife"].forEach((props) => { ["success", "explosive", "opportunity", "strife"].forEach((props) => {
this.l5r5e.summary[props] += parseInt(term.l5r5e[props]); this.l5r5e.summary[props] += parseInt(term.l5r5e[props]);
}); });
this.l5r5e.summary.totalSuccess += term.totalSuccess;
// TODO Others advantage/disadvantage // TODO Others advantage/disadvantage
} }
@@ -160,8 +201,9 @@ export class RollL5r5e extends Roll {
classes: [ classes: [
cls.name.toLowerCase(), cls.name.toLowerCase(),
"d" + term.faces, "d" + term.faces,
!isL5rDie && r.rerolled ? "rerolled" : null, isL5rDie && r.swapped ? "swapped" : null,
!isL5rDie && r.exploded ? "exploded" : null, r.rerolled ? "rerolled" : null,
r.exploded ? "exploded" : null,
!isL5rDie && r.discarded ? "discarded" : null, !isL5rDie && r.discarded ? "discarded" : null,
!isL5rDie && r.result === 1 ? "min" : null, !isL5rDie && r.result === 1 ? "min" : null,
!isL5rDie && r.result === term.faces ? "max" : null, !isL5rDie && r.result === term.faces ? "max" : null,
@@ -204,13 +246,6 @@ export class RollL5r5e extends Roll {
this.roll(); this.roll();
} }
const canRnK = false; // TODO TMP dev in progress
// const canRnK = !this.l5r5e.dicesTypes.std
// && this.l5r5e.dicesTypes.l5r
// && this.dice.length > 1
// && this.l5r5e.actor // pb with dice with no actor
// && this.l5r5e.actor.owner;
// Define chat data // Define chat data
const chatData = { const chatData = {
formula: isPrivate ? "???" : this._formula, formula: isPrivate ? "???" : this._formula,
@@ -224,13 +259,20 @@ export class RollL5r5e extends Roll {
? {} ? {}
: { : {
...this.l5r5e, ...this.l5r5e,
canRnK: canRnK, dices: this.dice.map((term) => {
dices: this.dice.map((d) => { const isL5rDie = term instanceof game.l5r5e.L5rBaseDie;
return { return {
diceTypeL5r: d instanceof game.l5r5e.L5rBaseDie, diceTypeL5r: isL5rDie,
rolls: d.results.map((r) => { rolls: term.results.map((r) => {
return { return {
result: d.constructor.getResultLabel(r.result), result: term.constructor.getResultLabel(r.result),
classes: [
isL5rDie && r.swapped ? "swapped" : null,
r.rerolled ? "rerolled" : null,
r.exploded ? "exploded" : null,
]
.filter((c) => !!c)
.join(" "),
}; };
}), }),
}; };
@@ -294,10 +336,16 @@ export class RollL5r5e extends Roll {
roll.l5r5e = duplicate(data.l5r5e); roll.l5r5e = duplicate(data.l5r5e);
// get real Actor object // get real Actor object
if (data.l5r5e.actor && !(data.l5r5e.actor instanceof game.l5r5e.ActorL5r5e)) { if (data.l5r5e.actor) {
const actor = game.actors.get(data.l5r5e.actor.id); if (data.l5r5e.actor instanceof game.l5r5e.ActorL5r5e) {
if (actor) { // duplicate break the object, relink it
roll.l5r5e.actor = actor; roll.l5r5e.actor = data.l5r5e.actor;
} else {
// only id, get the object
const actor = game.actors.get(data.l5r5e.actor.id);
if (actor) {
roll.l5r5e.actor = actor;
}
} }
} }

View File

@@ -29,6 +29,13 @@ export const RegisterHandlebars = function () {
return game.i18n.localize("l5r5e.techniques." + techniqueName.toLowerCase()); return game.i18n.localize("l5r5e.techniques." + techniqueName.toLowerCase());
}); });
/* ------------------------------------ */
/* Dice */
/* ------------------------------------ */
Handlebars.registerHelper("getDiceFaceUrl", function (diceClass, faceId) {
return game.l5r5e[diceClass].getResultSrc(faceId);
});
/* ------------------------------------ */ /* ------------------------------------ */
/* Utility */ /* Utility */
/* ------------------------------------ */ /* ------------------------------------ */

View File

@@ -68,6 +68,11 @@ export class HelpersL5r5e {
*/ */
static async getObjectGameOrPack(id, type, pack = null) { static async getObjectGameOrPack(id, type, pack = null) {
try { try {
// If no pack passed, but it's a core item, we know the pack to get it
if (!pack && id.substr(0, 7) === "L5RCore") {
pack = HelpersL5r5e.getPackNameForCoreItem(id);
}
// Named pack // Named pack
if (pack) { if (pack) {
const data = await game.packs.get(pack).getEntity(id); const data = await game.packs.get(pack).getEntity(id);
@@ -184,4 +189,65 @@ export class HelpersL5r5e {
static escapeRegExp(str) { static escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
} }
/**
* Get the associated pack for a core item (time saving)
*/
static getPackNameForCoreItem(itemId) {
const core = new Map();
core.set("Pro", "l5r5e.core-properties");
core.set("Kat", "l5r5e.core-techniques-kata");
core.set("Kih", "l5r5e.core-techniques-kiho");
core.set("Ins", "l5r5e.core-techniques-inversion");
core.set("Inv", "l5r5e.core-techniques-invocations");
core.set("Rit", "l5r5e.core-techniques-rituals");
core.set("Shu", "l5r5e.core-techniques-shuji");
core.set("Mah", "l5r5e.core-techniques-maho");
core.set("Nin", "l5r5e.core-techniques-ninjutsu");
core.set("Sch", "l5r5e.core-techniques-school");
core.set("Mas", "l5r5e.core-techniques-mastery");
core.set("Ite", "l5r5e.core-items");
core.set("Arm", "l5r5e.core-armors");
core.set("Wea", "l5r5e.core-weapons");
core.set("Dis", "l5r5e.core-peculiarities-distinctions");
core.set("Pas", "l5r5e.core-peculiarities-passions");
core.set("Adv", "l5r5e.core-peculiarities-adversities");
core.set("Anx", "l5r5e.core-peculiarities-anxieties");
return core.get(itemId.replace(/L5RCore(\w{3})\d+/gi, "$1"));
}
/**
* Show a confirm dialog before a deletion
* @param {string} content
* @param {function} callback The callback function for confirmed action
*/
static confirmDeleteDialog(content, callback) {
new Dialog({
title: game.i18n.localize("Delete"),
content,
buttons: {
confirm: {
icon: '<i class="fas fa-trash"></i>',
label: game.i18n.localize("Yes"),
callback,
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: game.i18n.localize("No"),
},
},
}).render(true);
}
/**
* Notify Applications using Difficulty settings that the values was changed
*/
static notifyDifficultyChange() {
["l5r5e-dice-picker-dialog", "l5r5e-gm-tools-dialog"].forEach((appId) => {
const app = Object.values(ui.windows).find((e) => e.id === appId);
if (app && typeof app.refresh === "function") {
app.refresh();
}
});
}
} }

View File

@@ -122,27 +122,21 @@ export default class HooksL5r5e {
.then(() => HooksL5r5e._gmCombatBar(app, html, data)); .then(() => HooksL5r5e._gmCombatBar(app, html, data));
}); });
html.find(".prepared-control").on("click", (event) => { html.find(".prepared-control").on("mousedown", (event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
let preparedId = $(event.currentTarget).data("id"); const preparedId = $(event.currentTarget).data("id");
if (!Object.hasOwnProperty.call(prepared, preparedId)) { if (!Object.hasOwnProperty.call(prepared, preparedId)) {
return; return;
} }
let value = prepared[preparedId]; const rev = event.which === 3;
switch (value) { const nextValue = {
case "false": false: rev ? "true" : "null",
value = "true"; true: rev ? "null" : "false",
break; null: rev ? "false" : "true",
case "true": };
value = "null";
break;
case "null":
value = "false";
break;
}
game.settings game.settings
.set("l5r5e", `initiative.prepared.${preparedId}`, value) .set("l5r5e", `initiative.prepared.${preparedId}`, nextValue[prepared[preparedId]])
.then(() => HooksL5r5e._gmCombatBar(app, html, data)); .then(() => HooksL5r5e._gmCombatBar(app, html, data));
}); });
} }
@@ -174,7 +168,7 @@ export default class HooksL5r5e {
} }
/** /**
* DiceSoNice Hook * DiceSoNice - Add L5R DicePresets
*/ */
static diceSoNiceReady(dice3d) { static diceSoNiceReady(dice3d) {
const texturePath = `${CONFIG.l5r5e.paths.assets}dices/default/3d/`; const texturePath = `${CONFIG.l5r5e.paths.assets}dices/default/3d/`;
@@ -218,4 +212,16 @@ export default class HooksL5r5e {
"d12" "d12"
); );
} }
/**
* DiceSoNice - Do not show 3D roll for the Roll n Keep series
*
* @param {string} messageId
* @param {object} context
*/
static diceSoNiceRollStart(messageId, context) {
if (context.roll.l5r5e?.history) {
context.blind = true;
}
}
} }

View File

@@ -4,7 +4,9 @@ export class ItemL5r5e extends Item {
* @override * @override
*/ */
static async create(data, options = {}) { static async create(data, options = {}) {
data.img = `${CONFIG.l5r5e.paths.assets}icons/items/${data.type}.svg`; if (data.img === undefined) {
data.img = `${CONFIG.l5r5e.paths.assets}icons/items/${data.type}.svg`;
}
return super.create(data, options); return super.create(data, options);
} }
} }

View File

@@ -105,12 +105,7 @@ export class ItemSheetL5r5e extends ItemSheet {
}); });
// Delete a property // Delete a property
html.find(`.property-delete`).on("click", (event) => { html.find(`.property-delete`).on("click", this._deleteProperty.bind(this));
event.preventDefault();
event.stopPropagation();
const li = $(event.currentTarget).parents(".property");
this._deleteProperty(li.data("propertyId"));
});
} }
/** /**
@@ -174,20 +169,37 @@ export class ItemSheetL5r5e extends ItemSheet {
* Delete a property from the current item * Delete a property from the current item
* @private * @private
*/ */
_deleteProperty(id) { _deleteProperty(event) {
if ( event.preventDefault();
!Array.isArray(this.entity.data.data.properties) || event.stopPropagation();
this.entity.data.data.properties.findIndex((p) => p.id === id) === -1
) { if (!Array.isArray(this.entity.data.data.properties)) {
return; return;
} }
this.entity.data.data.properties = this.entity.data.data.properties.filter((p) => p.id !== id); const id = $(event.currentTarget).parents(".property").data("propertyId");
const tmpProps = this.entity.data.data.properties.find((p) => p.id === id);
if (!tmpProps) {
return;
}
this.entity.update({ const callback = async () => {
data: { this.entity.data.data.properties = this.entity.data.data.properties.filter((p) => p.id !== id);
properties: this.entity.data.data.properties, this.entity.update({
}, data: {
}); properties: this.entity.data.data.properties,
},
});
};
// Holing Ctrl = without confirm
if (event.ctrlKey) {
return callback();
}
game.l5r5e.HelpersL5r5e.confirmDeleteDialog(
game.i18n.format("l5r5e.global.delete_confirm", { name: tmpProps.name }),
callback
);
} }
} }

View File

@@ -113,6 +113,40 @@ Hooks.once("init", async () => {
// Journal // Journal
Items.unregisterSheet("core", JournalSheet); Items.unregisterSheet("core", JournalSheet);
Items.registerSheet("l5r5e", BaseJournalSheetL5r5e, { makeDefault: true }); Items.registerSheet("l5r5e", BaseJournalSheetL5r5e, { makeDefault: true });
// Override the default Token _drawBar function to allow fatigue bar reversing.
Token.prototype._drawBar = function (number, bar, data) {
const reverseBar = data.attribute === "fatigue" && game.settings.get("l5r5e", "token.reverseFatigueBar");
// Bar value
const pct = Math.clamped(Number(data.value), 0, data.max) / data.max;
// Modify color
let color = number === 0 ? [pct / 1.2, 1 - pct, 0] : [0.5 * pct, 0.7 * pct, 0.5 + pct / 2];
// Red if compromised
if (data.attribute === "strife" && data.value > data.max) {
color = [1, 0.1, 0.1];
}
// Enlarge the bar for large tokens
let h = Math.max(canvas.dimensions.size / 12, 8);
if (this.data.height >= 2) {
h *= 1.6;
}
// Draw the bar
bar.clear()
.beginFill(0x000000, 0.5)
.lineStyle(2, 0x000000, 0.9)
.drawRoundedRect(0, 0, this.w, h, 3)
.beginFill(PIXI.utils.rgb2hex(color), 0.8)
.lineStyle(1, 0x000000, 0.8)
.drawRoundedRect(1, 1, (reverseBar ? 1 - pct : pct) * (this.w - 2), h - 2, 2);
// Set position
bar.position.set(0, number === 0 ? this.h - h : 0);
};
}); });
/* ------------------------------------ */ /* ------------------------------------ */
@@ -129,3 +163,4 @@ Hooks.on("renderSidebarTab", (app, html, data) => HooksL5r5e.renderSidebarTab(ap
Hooks.on("renderChatMessage", (message, html, data) => HooksL5r5e.renderChatMessage(message, html, data)); Hooks.on("renderChatMessage", (message, html, data) => HooksL5r5e.renderChatMessage(message, html, data));
Hooks.on("renderCombatTracker", (app, html, data) => HooksL5r5e.renderCombatTracker(app, html, data)); Hooks.on("renderCombatTracker", (app, html, data) => HooksL5r5e.renderCombatTracker(app, html, data));
Hooks.on("renderCompendium", async (app, html, data) => HooksL5r5e.renderCompendium(app, html, data)); Hooks.on("renderCompendium", async (app, html, data) => HooksL5r5e.renderCompendium(app, html, data));
Hooks.on("diceSoNiceRollStart", (messageId, context) => HooksL5r5e.diceSoNiceRollStart(messageId, context));

View File

@@ -2,6 +2,33 @@
* Custom system settings register * Custom system settings register
*/ */
export const RegisterSettings = function () { export const RegisterSettings = function () {
/* ------------------------------------ */
/* User settings */
/* ------------------------------------ */
game.settings.register("l5r5e", "rnk.deleteOldMessage", {
name: "SETTINGS.RollNKeep.DeleteOldMessage",
hint: "SETTINGS.RollNKeep.DeleteOldMessageHint",
scope: "world",
config: true,
default: true,
type: Boolean,
});
game.settings.register("l5r5e", "initiative.setTn1OnTypeChange", {
name: "SETTINGS.Initiative.SetTn1OnTypeChange",
hint: "SETTINGS.Initiative.SetTn1OnTypeChangeHint",
scope: "world",
config: true,
type: Boolean,
default: true,
});
game.settings.register("l5r5e", "token.reverseFatigueBar", {
name: "SETTINGS.ReverseFatigueBar",
scope: "world",
config: true,
type: Boolean,
default: false,
});
/* ------------------------------------ */ /* ------------------------------------ */
/* Update */ /* Update */
/* ------------------------------------ */ /* ------------------------------------ */
@@ -22,6 +49,7 @@ export const RegisterSettings = function () {
config: false, config: false,
type: Boolean, type: Boolean,
default: false, default: false,
onChange: () => game.l5r5e.HelpersL5r5e.notifyDifficultyChange(),
}); });
game.settings.register("l5r5e", "initiative.difficulty.value", { game.settings.register("l5r5e", "initiative.difficulty.value", {
name: "Initiative difficulty value", name: "Initiative difficulty value",
@@ -29,6 +57,7 @@ export const RegisterSettings = function () {
config: false, config: false,
type: Number, type: Number,
default: 2, default: 2,
onChange: () => game.l5r5e.HelpersL5r5e.notifyDifficultyChange(),
}); });
game.settings.register("l5r5e", "initiative.encounter", { game.settings.register("l5r5e", "initiative.encounter", {
name: "Initiative encounter type", name: "Initiative encounter type",
@@ -36,6 +65,11 @@ export const RegisterSettings = function () {
config: false, config: false,
type: String, type: String,
default: "skirmish", default: "skirmish",
onChange: () => {
if (game.settings.get("l5r5e", "initiative.setTn1OnTypeChange")) {
game.settings.set("l5r5e", "initiative.difficulty.value", 1);
}
},
}); });
game.settings.register("l5r5e", "initiative.prepared.character", { game.settings.register("l5r5e", "initiative.prepared.character", {
name: "Initiative PC prepared or not", name: "Initiative PC prepared or not",

View File

@@ -25,6 +25,10 @@ export class SocketHandlerL5r5e {
this._onRefreshAppId(data); this._onRefreshAppId(data);
break; break;
case "updateMessageIdAndRefresh":
this._onUpdateMessageIdAndRefresh(data);
break;
default: default:
console.warn(new Error("This socket event is not supported"), data); console.warn(new Error("This socket event is not supported"), data);
break; break;
@@ -40,9 +44,13 @@ export class SocketHandlerL5r5e {
}); });
} }
_onDeleteChatMessage(data) { _onDeleteChatMessage(data) {
// Only delete the message if the user is a GM (otherwise it have no real effect)
// Currently only used in RnK
if (!game.user.isGM || !game.settings.get("l5r5e", "rnk.deleteOldMessage")) {
return;
}
const message = game.messages.get(data.messageId); const message = game.messages.get(data.messageId);
// only delete the message if the user is a GM and the event emitter is one of the recipients if (message) {
if (game.user.isGM && message.data["whisper"].includes(data.userId)) {
message.delete(); message.delete();
} }
} }
@@ -65,4 +73,25 @@ export class SocketHandlerL5r5e {
} }
app.refresh(); app.refresh();
} }
/**
* Change in app message and refresh (used in RnK)
* @param appId
* @param msgId
*/
updateMessageIdAndRefresh(appId, msgId) {
game.socket.emit(SocketHandlerL5r5e.SOCKET_NAME, {
type: "updateMessageIdAndRefresh",
appId,
msgId,
});
}
_onUpdateMessageIdAndRefresh(data) {
const app = Object.values(ui.windows).find((e) => e.id === data.appId);
if (!app || !app.message || typeof app.refresh !== "function") {
return;
}
app.message = game.messages.get(data.msgId);
app.refresh();
}
} }

View File

@@ -7,7 +7,7 @@
@import "../scss/ui"; @import "../scss/ui";
.l5r5e { .l5r5e {
@import "../scss/dices"; @import "../scss/dices-chat";
@import "../scss/sheets"; @import "../scss/sheets";
@import "../scss/npc"; @import "../scss/npc";
@import "../scss/nav"; @import "../scss/nav";

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,73 @@
// Dice in chat
.chat-dice {
display: inline;
position: relative;
padding: 0.25rem;
&:after {
content: "";
position: absolute;
bottom: 0;
right: 0;
border-radius: 0.15rem;
padding: 0 0.1rem 0 0.15rem;
font-size: 0.65rem;
line-height: 1rem;
width: 0.75rem;
text-align: center;
color: white;
background: transparent;
}
&.rerolled {
> img {
border-bottom: 0 none;
}
&:after {
content: "\f2f9";
background: orangered;
}
}
&.swapped {
> img {
border-bottom: 0 none;
}
&:after {
content: "\f337";
background: fuchsia;
}
}
> img {
border: 1px solid transparent;
height: auto;
width: calc(100% / 6 - 0.255rem);
margin: auto;
}
}
.chat-profil {
text-align: center;
vertical-align: middle;
.profile-img {
margin: 0.25rem 0.25rem 0 0;
}
&-stance {
font-size: 2.5rem;
line-height: 2.5rem;
margin: 0.25rem;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
}
&-element {
flex-wrap: wrap;
flex-grow: 1;
&-skill {
flex-grow: 3;
}
&:last-child {
flex-grow: 2;
}
}
}

View File

@@ -1,46 +1,67 @@
// -- Dices.scss // -- Dices.scss
.dice-roll { .dice-roll {
.dice-formula, .dice-formula,
.dice-total { .dice-total {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
border: rgba(255, 255, 255, 0.75); border: rgba(255, 255, 255, 0.75);
text-align: center;
margin: 0.5rem 0;
padding: 0.25rem 0.5rem 0.25rem 0.25rem;
&-rnk {
line-height: 2rem;
i {
margin-left: 0.5rem;
}
}
} }
} button {
&.chat-dice-rnk {
// Dice in chat cursor: default;
.chat-dice > img { color: $white;
border: 1px solid transparent; background: linear-gradient(
background-repeat: no-repeat; $l5r5e-linear-gradient-third,
background-position: center; $l5r5e-linear-gradient-third-dark,
background-size: 100%; $l5r5e-linear-gradient-third
height: 44px; );
width: 44px; background-origin: padding-box;
//cursor: pointer; border-image: url("../assets/ui/macro-button.webp") 10 repeat;
//-webkit-appearance: none; border-image-width: 0.5rem;
//appearance: none; border-image-outset: 0px;
outline: none; margin: 0.5rem 0 0;
margin: 0; &:hover {
flex: 0 0 20px; background: linear-gradient(
display: inline-block; $l5r5e-linear-gradient-first-dark,
} $l5r5e-linear-gradient-first,
$l5r5e-linear-gradient-first-dark
.chat-profil { );
text-align: center; }
vertical-align: middle; }
&-stance {
font-size: 40px;
position: relative;
top: 8px;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
} }
&-element { .dice-result-rnk {
flex-wrap: wrap; background: rgba(0, 0, 255, 0.1);
flex-grow: 1; border: 1px solid rgba(55, 55, 155, 0.75);
padding: 0.25rem;
&-skill { color: rgba(55, 55, 155, 0.75);
flex-grow: 3; text-align: center;
font-weight: bold;
text-shadow: 0 0 0 $black;
&.success {
background: rgba(0, 255, 0, 0.1);
border-color: rgba(55, 155, 55, 0.75);
color: rgba(55, 155, 55, 0.75);
i.i_success {
font-size: 1rem;
}
}
&.unknown {
background: rgba(121, 121, 121, 0.1);
border-color: rgba(124, 124, 124, 0.75);
color: rgba(91, 91, 91, 0.75);
}
&.fail {
background: rgba(255, 0, 0, 0.1);
border-color: rgba(155, 55, 55, 0.75);
color: rgba(155, 55, 55, 0.75);
} }
} }
} }
@@ -52,6 +73,8 @@
// Dice Picker // Dice Picker
.dice-picker-dialog { .dice-picker-dialog {
min-width: 600px;
min-height: auto;
// Utility // Utility
* { * {
transition: none; transition: none;
@@ -72,18 +95,26 @@
text-align: center; text-align: center;
background: none; background: none;
border: none; border: none;
height: calc(100% - 3rem); border: 0 none;
margin: 0;
td:first-child { padding: 0;
width: 200px; tbody {
} tr {
td {
td { width: 250px;
width: 240px; padding: 0 0.5rem;
} &:first-child,
&:last-child {
td:last-child { width: 150px;
width: 200px; }
}
&:last-child {
td {
width: 100%;
padding: 0.5rem;
}
}
}
} }
} }
@@ -151,17 +182,75 @@
} }
.roll-n-keep-dialog { .roll-n-keep-dialog {
min-width: 600px;
max-width: 800px;
&.finalized {
width: auto;
min-width: 400px;
}
img { img {
border: 0; border: 0;
} }
table {
display: table;
min-height: 9rem;
border: 0 none;
margin: 0.25rem 0;
padding: 0;
tbody {
tr {
background: transparent;
td {
margin: 0;
padding: 0;
}
}
}
}
.rnk-ct {
margin: 0;
display: flex;
flex-wrap: wrap;
border-radius: 0.25rem;
background: rgba(0, 0, 0, 0.05);
border: 1px solid rgba(255, 255, 255, 0.5);
.rnk-center {
flex: 350px;
flex-wrap: wrap;
display: flex;
}
}
.profil { .profil {
border-bottom: 1px solid #782e22; border-bottom: 1px solid rgba(0, 0, 0, 0.1);
} }
.dropbox { .dropbox {
min-height: 100px; position: relative;
min-height: 7rem;
legend {
i:last-child {
position: absolute;
top: 0;
right: 0;
border-radius: 0.15rem;
padding: 0 0.1rem 0 0.15rem;
font-size: 0.65rem;
line-height: 1rem;
width: 1rem;
margin: 0.25rem;
text-align: center;
color: white;
background: $l5r5e-label;
}
}
&.faces-change {
min-height: 40px;
margin: 0.5rem auto;
}
&.discards { &.discards {
border: 1px solid gray; border: 1px solid gray;
} }
@@ -169,31 +258,142 @@
border: 1px solid orangered; border: 1px solid orangered;
} }
&.keeps { &.keeps {
flex: 100%;
border: 1px solid green; border: 1px solid green;
} }
&.swap {
flex: 0 0 calc(100px + 1rem);
flex-direction: column;
border: 1px solid fuchsia;
}
&.discards,
&.rerolls {
flex: 0 0 calc(50% - 0.5rem);
margin-bottom: 0.5rem;
}
}
/* Dice Marker */
.dice-ct {
position: relative;
padding: 0.25rem;
&:before {
content: "";
position: absolute;
height: 0.5rem;
width: 2px;
top: -0.3rem;
right: calc(50% - 1px);
background: $l5r5e-black-light;
}
&:after {
content: "\f128";
position: absolute;
bottom: 0;
right: 0;
border-radius: 0.15rem;
padding: 0 0.1rem 0 0.15rem;
font-size: 0.65rem;
line-height: 1rem;
width: 0.65rem;
text-align: center;
color: white;
background: gray;
}
&.discard {
filter: opacity(0.5);
&:after {
content: "\f00d";
background: gray;
}
}
&.reroll {
filter: opacity(0.5);
&:after {
content: "\f2f9";
background: orangered;
}
}
&.keep {
&:after {
content: "\f00c";
background: green;
}
}
&.swap {
&:after {
content: "\f337";
background: fuchsia;
}
}
}
tr:first-child .dice-ct {
&:before {
display: none;
}
} }
.dice { .dice {
height: 40px; height: 40px;
width: 40px; width: 40px;
&.discard {
filter: opacity(0.5);
border: 0 none;
}
&.reroll {
filter: opacity(0.5);
border: 0 none;
}
&.keep {
border: 0 none;
}
&.swap {
border: 0 none;
}
} }
.discard { #finalize {
filter: opacity(0.5); width: 100%;
border: 3px solid gray; margin: 0.5rem 0.25rem 0.25rem;
} }
.reroll { .section-header {
filter: opacity(0.5); i {
border: 3px solid orangered; font-size: 0.75rem;
margin: 0 0.25rem;
}
} }
.keep { .fa-sign-in-alt {
border: 3px solid green; transform: rotate(90deg);
}
.chat-profil {
ul {
display: flex;
flex-direction: row;
li {
&:nth-child(1),
&:nth-child(2) {
flex: 0 0 4rem;
padding: 0 0.25rem 0.25rem;
}
&:nth-child(4) {
flex: 0 0 4rem;
padding: 0 0.25rem 0.25rem;
}
}
.profile-img {
width: 4rem;
}
.chat-profil-stance {
font-size: 3.5rem;
line-height: 3.5rem;
}
}
} }
} }
#l5r5e-gm-tools-dialog { #l5r5e-gm-tools-dialog {
bottom: 0; //bottom: 0;
right: 0.5rem; //right: 0.5rem;
display: flex; display: flex;
background-position: center; background-position: center;
background-size: 100%; background-size: 100%;
@@ -208,13 +408,15 @@
border-image: url("../assets/ui/macro-button.webp") 10 repeat; border-image: url("../assets/ui/macro-button.webp") 10 repeat;
border-image-width: 0.5rem; border-image-width: 0.5rem;
border-image-outset: 0px; border-image-outset: 0px;
padding: 0;
margin: 0.5rem;
.window-header { .window-header {
text-align: center; text-align: center;
border-bottom: 1px solid rgb(195, 165, 130); border-bottom: 1px solid rgb(195, 165, 130);
h4 { h4 {
font-family: $font-primary; letter-spacing: 0.25rem;
text-transform: uppercase; line-height: 2.25rem;
letter-spacing: 0.15rem; color: $white-light;
} }
} }
.window-content { .window-content {
@@ -222,22 +424,50 @@
vertical-align: middle; vertical-align: middle;
background: transparent; background: transparent;
color: $white-light; color: $white-light;
form {
padding: 0;
}
.gm-tools-container { .gm-tools-container {
flex: 1;
display: flex; display: flex;
flex-flow: wrap; font-size: 2rem;
a { line-height: 2rem;
min-height: 2rem;
margin: 0;
li {
flex: 1; flex: 1;
display: flex;
margin: 0;
padding: 0;
border-right: 1px solid #c3a582;
cursor: url("../assets/cursors/pointer.webp"), pointer; cursor: url("../assets/cursors/pointer.webp"), pointer;
i { &:last-child {
font-size: 3rem; margin: 0;
line-height: 4rem; border: 0 none;
vertical-align: middle; }
:hover {
text-shadow: 0 0 $red;
} }
} }
.difficulty { .difficulty_hidden {
flex: 1; .fa {
font-size: 3rem; width: 3rem;
}
.difficulty {
flex: 1rem;
width: 2rem;
font-size: 2rem;
text-align: center;
margin: 0;
padding: 0.5rem;
}
}
.fa {
padding: 0.5rem;
}
.fa-bed,
.fa-star-half-alt {
width: 100%;
padding: 0.5rem;
} }
} }
} }
@@ -246,3 +476,34 @@
display: none; display: none;
} }
} }
.dice-picker-dialog,
.roll-n-keep-dialog {
button {
cursor: default;
color: $white;
background: linear-gradient(
$l5r5e-linear-gradient-third,
$l5r5e-linear-gradient-third-dark,
$l5r5e-linear-gradient-third
);
background-origin: padding-box;
border-image: url("../assets/ui/macro-button.webp") 10 repeat;
border-image-width: 0.5rem;
border-image-outset: 0px;
margin: 0.5rem 0 0;
&:hover {
background: linear-gradient(
$l5r5e-linear-gradient-first-dark,
$l5r5e-linear-gradient-first,
$l5r5e-linear-gradient-first-dark
);
}
&[disabled] {
opacity: 0.25;
&:hover {
box-shadow: none;
}
}
}
}

View File

@@ -186,6 +186,7 @@ li {
// Fieldset // Fieldset
fieldset { fieldset {
flex: 1; flex: 1;
flex-wrap: wrap;
display: flex; display: flex;
margin: 0 0.25rem; margin: 0 0.25rem;
padding: 0.5rem; padding: 0.5rem;

View File

@@ -96,7 +96,7 @@
width: 100%; width: 100%;
line-height: 2rem; line-height: 2rem;
font-size: 0.75rem; font-size: 0.75rem;
margin: 0.25rem 0.25rem 0.5rem; margin: 0 0 0.5rem;
text-align: center; text-align: center;
li { li {
flex: 1; flex: 1;
@@ -133,24 +133,32 @@
} }
} }
article { article {
.weapons-content {
flex: 1;
}
min-height: auto; min-height: auto;
display: flex; fieldset,
fieldset { .checklist {
flex: 0 0 calc(100% - 0.5rem); flex: 0 0 calc(100% - 0.5rem);
} }
.items-content { .items-content {
flex: 0 0 calc(100% - 0.5rem); flex: 0 0 calc(100% - 0.5rem);
margin: 1rem 0.25rem 0; margin: 1rem 0.25rem 0;
} }
.weapons-content {
flex: 1;
}
.initiative-wrapper { .initiative-wrapper {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
&:last-child { &:last-child {
padding-bottom: 1rem; padding-bottom: 1rem;
} }
.techniques-wrapper {
padding-left: 0.5rem;
fieldset,
.checklist {
flex: 100%;
margin: 0;
}
}
} }
.npc-note { .npc-note {
.editor { .editor {

View File

@@ -17,13 +17,6 @@
.sheet-body { .sheet-body {
height: calc(100% - 27rem); height: calc(100% - 27rem);
} }
.techniques-wrapper {
fieldset {
&:last-child {
margin: 0 0 0 0.5rem;
}
}
}
fieldset { fieldset {
&.advancement { &.advancement {
display: block; display: block;
@@ -501,6 +494,31 @@
padding: 0.5rem; padding: 0.5rem;
flex-wrap: wrap; flex-wrap: wrap;
min-height: calc(100% - 3.25rem); min-height: calc(100% - 3.25rem);
fieldset {
h3 {
font-size: 1.25rem;
width: 100%;
text-align: left;
line-height: 2rem;
color: $l5r5e-bold;
border-bottom: 1px solid;
.item-control {
&.item-add {
float: right;
font-size: 0.75rem;
line-height: 0.75rem;
border: 1px solid;
padding: 0.25rem;
margin: 0.25rem;
color: $white;
background: $l5r5e-bold;
&:hover {
opacity: 0.75;
}
}
}
}
}
&.tab[data-tab] { &.tab[data-tab] {
&.active { &.active {
display: flex; display: flex;
@@ -517,11 +535,15 @@
} }
} }
.techniques-wrapper { .techniques-wrapper {
padding-left: 0.25rem;
fieldset {
margin: 0 0 0 0.25rem;
}
.checklist { .checklist {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
font-size: 0.85rem; font-size: 0.85rem;
margin: 0 0 0.25rem 0.5rem; margin: 0 0 0.25rem 0.25rem;
padding: 0.5rem; padding: 0.5rem;
background: $l5r5e-title; background: $l5r5e-title;
--notchSize: 0.25rem; --notchSize: 0.25rem;

View File

@@ -2,7 +2,7 @@
"name": "l5r5e", "name": "l5r5e",
"title": "Legend of the Five Rings (5th Edition)", "title": "Legend of the Five Rings (5th Edition)",
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>", "description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
"version": "1.1.2", "version": "1.2.1",
"minimumCoreVersion": "0.7.9", "minimumCoreVersion": "0.7.9",
"compatibleCoreVersion": "0.7.9", "compatibleCoreVersion": "0.7.9",
"manifestPlusVersion": "1.0.0", "manifestPlusVersion": "1.0.0",
@@ -185,5 +185,5 @@
], ],
"url": "https://gitlab.com/teaml5r/l5r5e", "url": "https://gitlab.com/teaml5r/l5r5e",
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json", "manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.1.2/raw/l5r5e.zip?job=build" "download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.2.1/raw/l5r5e.zip?job=build"
} }

View File

@@ -102,8 +102,7 @@
"ritual": false, "ritual": false,
"shuji": false, "shuji": false,
"maho": false, "maho": false,
"ninjutsu": false, "ninjutsu": false
"list": []
} }
} }
}, },

View File

@@ -62,7 +62,10 @@
<input name="data.money.zeni" type="number" value="{{actor.data.money.zeni}}" data-dtype="Number" min="0" placeholder="0"/> <input name="data.money.zeni" type="number" value="{{actor.data.money.zeni}}" data-dtype="Number" min="0" placeholder="0"/>
</label> </label>
</fieldset> </fieldset>
{{> 'systems/l5r5e/templates/items/item/items.html' }} <fieldset class="items-wrapper">
<legend>{{localize 'l5r5e.equipment' }}</legend>
{{> 'systems/l5r5e/templates/items/item/items.html' }}
</fieldset>
</article> </article>
{{!-- Experience Tab --}} {{!-- Experience Tab --}}

View File

@@ -1,35 +1,35 @@
<ul class="rings"> <ul class="rings">
<li id="earth"> <li id="earth">
<label class="earth"> <label class="earth">
<i class="i_earth"></i> <i class="i_earth dice-picker rollable" data-ring="earth"></i>
<strong>{{ localizeRing 'earth' }}</strong> <strong>{{ localizeRing 'earth' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.earth" value="{{data.rings.earth}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.earth" value="{{data.rings.earth}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="air"> <li id="air">
<label class="air"> <label class="air">
<i class="i_air"></i> <i class="i_air dice-picker rollable" data-ring="air"></i>
<strong>{{ localizeRing 'air' }}</strong> <strong>{{ localizeRing 'air' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.air" value="{{data.rings.air}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.air" value="{{data.rings.air}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="water"> <li id="water">
<label class="water"> <label class="water">
<i class="i_water"></i> <i class="i_water dice-picker rollable" data-ring="water"></i>
<strong>{{ localizeRing 'water' }}</strong> <strong>{{ localizeRing 'water' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.water" value="{{data.rings.water}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.water" value="{{data.rings.water}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="fire"> <li id="fire">
<label class="fire"> <label class="fire">
<i class="i_fire"></i> <i class="i_fire dice-picker rollable" data-ring="fire"></i>
<strong>{{ localizeRing 'fire' }}</strong> <strong>{{ localizeRing 'fire' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.fire" value="{{data.rings.fire}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.fire" value="{{data.rings.fire}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="void"> <li id="void">
<label class="void"> <label class="void">
<i class="i_void"></i> <i class="i_void dice-picker rollable" data-ring="void"></i>
<strong>{{ localizeRing 'void' }}</strong> <strong>{{ localizeRing 'void' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.void" value="{{data.rings.void}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.void" value="{{data.rings.void}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>

View File

@@ -8,19 +8,19 @@
</label> </label>
{{/each}} {{/each}}
</div> </div>
<fieldset class="section-header flexrow"> {{#each actor.data.splitTechniquesList as |list technique|}}
<legend class="technique-controls"> <fieldset class="section-header flexrow">
{{ localize 'l5r5e.techniques.title' }} <legend class="technique-controls">
{{#if editable}} {{localize (localize 'l5r5e.techniques.{technique}' technique=technique) }}
<a data-item-type="technique" class="technique-control item-add" title="{{ localize 'l5r5e.global.add' }}"><i class="fas fa-plus"></i></a> {{#ifCond ../editable '&&' (lookup ../actor.data.techniques technique)}}
{{/if}} <a data-item-type="technique" class="technique-control item-add" data-tech-type="{{technique}}" title="{{ localize 'l5r5e.global.add' }}"><i class="fas fa-plus"></i></a>
</legend>
<ul class="item-list">
{{#each actor.items as |item id|}}
{{#ifCond item.type '==' 'technique'}}
{{> 'systems/l5r5e/templates/items/technique/technique-entry.html' technique=item editable=../editable }}
{{/ifCond}} {{/ifCond}}
{{/each}} </legend>
</ul> <ul class="item-list">
</fieldset> {{#each list as |item id|}}
{{> 'systems/l5r5e/templates/items/technique/technique-entry.html' technique=item editable=../../editable }}
{{/each}}
</ul>
</fieldset>
{{/each}}
</div> </div>

View File

@@ -20,20 +20,31 @@
</header> </header>
{{!-- Sheet Body --}} {{!-- Sheet Body --}}
<section class="sheet-body"> <section class="sheet-body">
<article> {{!-- Skills No Tab --}}
{{> 'systems/l5r5e/templates/actors/npc/skill.html' }} {{> 'systems/l5r5e/templates/actors/npc/skill.html' }}
{{> 'systems/l5r5e/templates/actors/npc/conflict.html' }} {{!-- Sheet Tab Navigation --}}
</article> <nav class="sheet-tabs tabs" data-group="primary">
<article> <a class="item" data-tab="skills">{{ localize 'l5r5e.skills.title' }}</a>
<a class="item" data-tab="conflict">{{ localize 'l5r5e.conflict.title' }}</a>
<a class="item" data-tab="inventory">{{ localize 'l5r5e.inventory' }}</a>
</nav>
{{!-- Techniques Tab --}}
<article class="tab skills" data-group="primary" data-tab="skills">
{{> 'systems/l5r5e/templates/actors/npc/narrative.html' }} {{> 'systems/l5r5e/templates/actors/npc/narrative.html' }}
{{> 'systems/l5r5e/templates/actors/npc/techniques.html' }}
</article> </article>
<article> {{!-- Conflict Tab --}}
<article class="tab conflict" data-group="primary" data-tab="conflict">
{{> 'systems/l5r5e/templates/actors/npc/conflict.html' }}
{{> 'systems/l5r5e/templates/items/weapon/weapons.html' }} {{> 'systems/l5r5e/templates/items/weapon/weapons.html' }}
{{> 'systems/l5r5e/templates/items/armor/armors.html' }} {{> 'systems/l5r5e/templates/items/armor/armors.html' }}
{{> 'systems/l5r5e/templates/items/item/items.html' }}
</article> </article>
<article> {{!-- Inventory Tab --}}
{{> 'systems/l5r5e/templates/actors/npc/techniques.html' }} <article class="tab inventory" data-group="primary" data-tab="inventory">
<fieldset class="items-wrapper">
<legend>{{localize 'l5r5e.equipment' }}</legend>
{{> 'systems/l5r5e/templates/items/item/items.html' }}
</fieldset>
</article> </article>
</section> </section>
</form> </form>

View File

@@ -1,35 +1,35 @@
<ul class="rings"> <ul class="rings">
<li id="earth"> <li id="earth">
<label class="earth"> <label class="earth">
<i class="i_earth"></i> <i class="i_earth dice-picker rollable" data-ring="earth"></i>
<strong>{{ localizeRing 'earth' }}</strong> <strong>{{ localizeRing 'earth' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.earth" value="{{data.rings.earth}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.earth" value="{{data.rings.earth}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="air"> <li id="air">
<label class="air"> <label class="air">
<i class="i_air"></i> <i class="i_air dice-picker rollable" data-ring="air"></i>
<strong>{{ localizeRing 'air' }}</strong> <strong>{{ localizeRing 'air' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.air" value="{{data.rings.air}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.air" value="{{data.rings.air}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="water"> <li id="water">
<label class="water"> <label class="water">
<i class="i_water"></i> <i class="i_water dice-picker rollable" data-ring="water"></i>
<strong>{{ localizeRing 'water' }}</strong> <strong>{{ localizeRing 'water' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.water" value="{{data.rings.water}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.water" value="{{data.rings.water}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="fire"> <li id="fire">
<label class="fire"> <label class="fire">
<i class="i_fire"></i> <i class="i_fire dice-picker rollable" data-ring="fire"></i>
<strong>{{ localizeRing 'fire' }}</strong> <strong>{{ localizeRing 'fire' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.fire" value="{{data.rings.fire}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.fire" value="{{data.rings.fire}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>
</li> </li>
<li id="void"> <li id="void">
<label class="void"> <label class="void">
<i class="i_void"></i> <i class="i_void dice-picker rollable" data-ring="void"></i>
<strong>{{ localizeRing 'void' }}</strong> <strong>{{ localizeRing 'void' }}</strong>
<input class="centered-input select-on-focus" type="number" name="data.rings.void" value="{{data.rings.void}}" data-dtype="Number" min="1" max="9" placeholder="0"/> <input class="centered-input select-on-focus" type="number" name="data.rings.void" value="{{data.rings.void}}" data-dtype="Number" min="1" max="9" placeholder="0"/>
</label> </label>

View File

@@ -1,13 +1,29 @@
<fieldset class="techniques-wrapper section-header flexrow"> <fieldset class="techniques-wrapper section-header flexrow">
<legend class="technique-controls"> <legend class="technique-controls">
{{ localize 'l5r5e.techniques.title' }} {{ localize 'l5r5e.techniques.title' }}
<a data-item-type="technique" class="technique-control item-add" title="{{ localize 'l5r5e.global.add' }}"><i class="fas fa-plus"></i></a>
</legend> </legend>
<ul class="item-list"> <div class="checklist">
{{#each actor.items as |item id|}} <i>{{ localize 'l5r5e.techniques.type'}}</i>
{{#ifCond item.type '==' 'technique'}} {{#each actor.data.techniquesList as |technique|}}
{{> 'systems/l5r5e/templates/items/technique/technique-entry.html' technique=item editable=../editable }} <label>
{{/ifCond}} <input type="checkbox" name="data.techniques.{{technique}}" {{checked (lookup ../actor.data.techniques technique)}} />
{{localizeTechnique technique}}
</label>
{{/each}} {{/each}}
</ul> </div>
{{#each actor.data.splitTechniquesList as |list technique|}}
<fieldset class="section-header flexrow">
<legend class="technique-controls">
{{localize (localize 'l5r5e.techniques.{technique}' technique=technique) }}
{{#ifCond ../editable '&&' (lookup ../actor.data.techniques technique)}}
<a data-item-type="technique" class="technique-control item-add" data-tech-type="{{technique}}" title="{{ localize 'l5r5e.global.add' }}"><i class="fas fa-plus"></i></a>
{{/ifCond}}
</legend>
<ul class="item-list">
{{#each list as |item id|}}
{{> 'systems/l5r5e/templates/items/technique/technique-entry.html' technique=item editable=../../editable }}
{{/each}}
</ul>
</fieldset>
{{/each}}
</fieldset> </fieldset>

View File

@@ -1,17 +1,11 @@
<div class="l5r5e dice-roll"> <div class="l5r5e dice-roll">
{{#if isPublicRoll }} {{#if isPublicRoll}}
{{#if l5r5e.stance}} {{#if l5r5e.stance}}
<div class="l5r5e profil"> <div class="l5r5e profil">
<header class="part-header flexrow chat-profil"> <header class="part-header flexrow chat-profil">
<span class="chat-profil-element"> <span class="chat-profil-element">
<img class="profile-img" <img class="profile-img" src="{{#if l5r5e.actor.img}}{{l5r5e.actor.img}}{{else}}icons/svg/mystery-man.svg{{/if}}" data-edit="img" alt="{{#if l5r5e.actor.name}}{{l5r5e.actor.name}}{{else}}mystery-man{{/if}}" />
src="{{#if l5r5e.actor.img}}{{l5r5e.actor.img}}{{else}}icons/svg/mystery-man.svg{{/if}}"
data-edit="img"
height="40"
width="40"
alt="{{#if l5r5e.actor.name}}{{l5r5e.actor.name}}{{else}}mystery-man{{/if}}"
>
</span> </span>
<span class="chat-profil-element"> <span class="chat-profil-element">
@@ -27,57 +21,81 @@
</span> </span>
<span class="chat-profil-element"> <span class="chat-profil-element">
{{#if l5r5e.summary.difficultyHidden}} {{#if l5r5e.difficultyHidden}}
{{localize 'l5r5e.chatdices.difficulty_hidden'}} {{localize 'l5r5e.chatdices.difficulty_hidden'}}
{{else}} {{else}}
{{localize 'l5r5e.chatdices.difficulty'}} {{l5r5e.summary.difficulty}} {{localize 'l5r5e.chatdices.difficulty'}} {{l5r5e.difficulty}}
{{/if}} {{/if}}
{{#if l5r5e.summary.voidPointUsed}} <br>
<br><i class="i_void" title="{{localize 'l5r5e.chatdices.void_point_used'}}"></i> {{#if l5r5e.voidPointUsed}}
<i class="i_void" title="{{localize 'l5r5e.chatdices.void_point_used'}}"></i>
{{/if}}
{{#if l5r5e.skillAssistance}}
<i class="i_skill" title="{{l5r5e.skillAssistance}}x {{localize 'l5r5e.chatdices.assistance_used'}}"></i>
{{/if}} {{/if}}
</span> </span>
</header> </header>
</div> </div>
{{/if}} {{/if}}
<div class="l5r5e dice-formula">{{formula}}</div> <div class="l5r5e dice-formula">{{#if l5r5e.initialFormula}}{{l5r5e.initialFormula}}{{else}}{{formula}}{{/if}}</div>
<div class="l5r5e dice-result"> <div class="l5r5e dice-result">
{{#if l5r5e.dicesTypes.l5r}} {{#if l5r5e.dicesTypes.l5r}}
<div class="l5r5e item-display dices-l5r"> <div class="l5r5e item-display dices-l5r">
{{!-- Dices list --}}
{{#each l5r5e.dices}} {{#each l5r5e.dices}}
{{#if this.diceTypeL5r}} {{#if this.diceTypeL5r}}
{{#each this.rolls}} {{#each this.rolls}}
<span class="l5r5e chat-dice">{{{this.result}}}</span> <span class="l5r5e fas chat-dice {{this.classes}}">{{{this.result}}}</span>
{{/each}} {{/each}}
{{/if}} {{/if}}
{{/each}} {{/each}}
{{!-- Roll & Keep Button --}} {{!-- Roll & Keep Button --}}
{{#if l5r5e.canRnK}} {{^if l5r5e.dicesTypes.std}}
<button class="l5r5e chat-dice-rnk">{{localize "l5r5e.chatdices.roll_n_keep"}}</button> <button class="l5r5e chat-dice-rnk">{{localize "l5r5e.chatdices.roll_n_keep"}}</button>
{{/if}} {{/if}}
{{#l5r5e.summary}} {{#l5r5e.summary}}
<ul> {{!-- summary symbols --}}
<li>{{localize "l5r5e.chatdices.successes"}}: {{this.success}}</li> <div class="l5r5e dice-total dice-total-rnk">
{{#if success}}
<i class="i_success" title="{{localize 'l5r5e.chatdices.successes'}}"></i>x{{success}}
{{/if}}
{{#if explosive}} {{#if explosive}}
<li>{{localize "l5r5e.chatdices.explosives"}}: {{this.explosive}}</li> <i class="i_explosive" title="{{localize 'l5r5e.chatdices.explosives'}}"></i>x{{explosive}}
{{/if}} {{/if}}
{{#if opportunity}} {{#if opportunity}}
<li>{{localize "l5r5e.chatdices.opportunities"}}: {{this.opportunity}}</li> <i class="i_opportunity" title="{{localize 'l5r5e.chatdices.opportunities'}}"></i>x{{opportunity}}
{{/if}} {{/if}}
{{#if strife}} {{#if strife}}
<li>{{localize "l5r5e.chatdices.strife"}}: {{this.strife}}</li> <i class="i_strife" title="{{localize 'l5r5e.chatdices.strife'}}"></i>x{{strife}}
{{/if}} {{/if}}
</ul> </div>
{{!-- Result text --}}
{{#if ../l5r5e.difficultyHidden}}
<div class="l5r5e dice-result-rnk unknown">
{{totalSuccess}} {{localize 'l5r5e.chatdices.successes'}}
</div>
{{else}}
<div class="l5r5e dice-result-rnk {{#ifCond totalSuccess '>=' ../l5r5e.difficulty}}success{{else}}fail{{/ifCond}}">
{{#ifCond totalSuccess '>=' ../l5r5e.difficulty}}
{{localize "l5r5e.chatdices.success_text"}} <i title="{{totalBonus}} {{localize 'l5r5e.chatdices.successes'}}">({{totalBonus}} {{localize "l5r5e.chatdices.bonus_text"}})</i>
{{else}}
{{localize "l5r5e.chatdices.fail_text"}}
{{/ifCond}}
</div>
{{/if}}
{{/l5r5e.summary}} {{/l5r5e.summary}}
</div> </div>
{{/if}} {{/if}}
{{!-- Regular dices --}}
{{#if l5r5e.dicesTypes.std}} {{#if l5r5e.dicesTypes.std}}
<div class="l5r5e dices-std"> <div class="l5r5e dices-std">
{{#each results}} {{#each results}}
@@ -90,7 +108,6 @@
{{{tooltip}}} {{{tooltip}}}
<h4 class="l5r5e dice-total dice-total-std">{{total}}</h4> <h4 class="l5r5e dice-total dice-total-std">{{total}}</h4>
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/if}}

View File

@@ -3,28 +3,16 @@
{{!-- First line--}} {{!-- First line--}}
<tr> <tr>
<td class="profil center"> <td class="profil center">
<img class="profile-img" <img class="profile-img" src="{{#if actor.img}}{{actor.img}}{{else}}icons/svg/mystery-man.svg{{/if}}" data-edit="img" alt="{{#if actor.name}}{{actor.name}}{{else}}mystery-man{{/if}}" />
src="{{#if actor.img}}{{actor.img}}{{else}}icons/svg/mystery-man.svg{{/if}}"
data-edit="img"
height="200"
width="200"
alt="{{#if actor.name}}{{actor.name}}{{else}}mystery-man{{/if}}"
>
</td> </td>
<td class="rings center"> <td class="center">
<ul class="rings"> <ul class="rings">
{{#each ringsList}} {{#each ringsList}}
<li id="{{this.id}}"> <li id="{{this.id}}">
<label class="attribute-label {{this.id}} centered-input ring-selection pointer-choice {{#ifCond ../data.ring.id '==' this.id}}ring-selected{{/ifCond}}"> <label class="attribute-label {{this.id}} centered-input ring-selection pointer-choice {{#ifCond ../data.ring.id '==' this.id}}ring-selected{{/ifCond}}">
<i class="i_{{this.id}}"></i> <i class="i_{{this.id}}"></i>
<strong>{{this.label}}</strong> <strong>{{this.label}}</strong>
<input class="centered-input approach_{{this.id}}" <input class="centered-input approach_{{this.id}}" type="text" name="approach" data-ringid="{{this.id}}" value="{{this.value}}" readonly="readonly" />
type="text"
name="approach"
data-ringid="{{this.id}}"
value="{{this.value}}"
readonly="readonly"
/>
</label> </label>
</li> </li>
{{/each}} {{/each}}
@@ -32,33 +20,19 @@
</td> </td>
<td class="skill"> <td class="skill">
{{#if data.skill.name}} {{#if data.skill.name}}
<div>
<label>{{localizeSkill data.skill.cat 'title'}}</label> <label>{{localizeSkill data.skill.cat 'title'}}</label>
</div>
{{#if actorIsPc}} {{#if actorIsPc}}
<div>
<label>{{data.skill.name}}</label> <label>{{data.skill.name}}</label>
</div>
{{/if}} {{/if}}
<label id="stance_label">{{localizeSkill data.skill.cat data.ring.id}}</label>
<div> <div id="skill_default_value" class="dice-container pointer-choice">
<label id="stance_label">{{localizeSkill data.skill.cat data.ring.id}}</label> <img src="systems/l5r5e/assets/dices/default/skill_blank.svg" alt="1">
</div> <div class="dice-value">
<div id="skill_default_value" class="dice-container pointer-choice"> <span class="dice-skill" type="text" name="skill_{{data.skill.name}}">{{data.skill.defaultValue}}</span>
<img src="systems/l5r5e/assets/dices/default/skill_blank.svg" alt="1"> </div>
<div class="dice-value"> </div>
<span class="dice-skill" type="text" name="skill_{{data.skill.name}}">{{data.skill.default_value}}</span>
</div>
</div>
{{else}} {{else}}
<img class="profile-img" <img class="profile-img" src="systems/l5r5e/assets/imgs/noskill.webp" data-edit="img" alt="no skill selected" />
src="systems/l5r5e/assets/imgs/noskill.webp"
data-edit="img"
height="200"
width="200"
alt="no skill selected"
>
{{/if}} {{/if}}
</td> </td>
</tr> </tr>
@@ -81,7 +55,7 @@
<td> <td>
{{#if data.difficulty.hidden}} {{#if data.difficulty.hidden}}
<label> <label>
<input type="checkbox" id="diff_add_void_point" name="difficulty.add_void_point" value="1" {{checked data.difficulty.add_void_point}}> <input type="checkbox" id="diff_add_void_point" name="difficulty.addVoidPoint" value="1" {{checked data.difficulty.addVoidPoint}} />
+1 <i class="i_void" title="{{localize 'l5r5e.dicepicker.void_point_tooltip'}}"></i> +1 <i class="i_void" title="{{localize 'l5r5e.dicepicker.void_point_tooltip'}}"></i>
</label> </label>
{{else}} {{else}}
@@ -92,9 +66,9 @@
<div class="third"> <div class="third">
<div class="dice-container"> <div class="dice-container">
<img src="systems/l5r5e/assets/dices/default/3d/blank.png" alt="1"> <img src="systems/l5r5e/assets/dices/default/3d/blank.png" alt="1" />
<div class="dice-value"> <div class="dice-value">
<input class="input-dice" type="text" name="difficulty.value" value="{{data.difficulty.value}}" readonly="readonly"> <input class="input-dice" type="text" name="difficulty.value" value="{{data.difficulty.value}}" readonly="readonly" />
</div> </div>
</div> </div>
</div> </div>
@@ -113,9 +87,9 @@
<div class="third"> <div class="third">
<div class="dice-container"> <div class="dice-container">
<img src="systems/l5r5e/assets/dices/default/ring_blank.svg" alt="1"> <img src="systems/l5r5e/assets/dices/default/ring_blank.svg" alt="1" />
<div class="dice-value"> <div class="dice-value">
<input class="input-dice input-dice-ring" type="text" name="ring.value" value="{{data.ring.value}}" readonly="readonly"> <input class="input-dice input-dice-ring" type="text" name="ring.value" value="{{data.ring.value}}" readonly="readonly" />
</div> </div>
</div> </div>
</div> </div>
@@ -132,9 +106,9 @@
<div class="third"> <div class="third">
<div class="dice-container"> <div class="dice-container">
<img src="systems/l5r5e/assets/dices/default/skill_blank.svg" alt="1"> <img src="systems/l5r5e/assets/dices/default/skill_blank.svg" alt="1" />
<div class="dice-value"> <div class="dice-value">
<input class="input-dice input-dice-skill" type="text" name="skill.value" value="{{data.skill.value}}" readonly="readonly"> <input class="input-dice input-dice-skill" type="text" name="skill.value" value="{{data.skill.value}}" readonly="readonly" />
</div> </div>
</div> </div>
</div> </div>
@@ -150,7 +124,7 @@
<td> <td>
{{^if difficultyHiddenIsLock}} {{^if difficultyHiddenIsLock}}
<label> <label>
<input type="checkbox" id="diff_hidden" name="difficulty.hidden" value="1" {{checked data.difficulty.hidden}}> <input type="checkbox" id="diff_hidden" name="difficulty.hidden" value="1" {{checked data.difficulty.hidden}} />
{{localize 'l5r5e.dicepicker.difficulty_hidden_label'}} {{localize 'l5r5e.dicepicker.difficulty_hidden_label'}}
</label> </label>
{{/if}} {{/if}}
@@ -158,18 +132,35 @@
<td> <td>
{{#if canUseVoidPoint}} {{#if canUseVoidPoint}}
<label> <label>
<input type="checkbox" id="use_void_point" name="useVoidPoint" value="1" {{checked data.useVoidPoint}}> <input type="checkbox" id="use_void_point" name="useVoidPoint" value="1" {{checked data.useVoidPoint}} />
{{localize 'l5r5e.dicepicker.use_void_point_label'}} <i class="i_void" title="{{localize 'l5r5e.dicepicker.void_point_tooltip'}}"></i> {{localize 'l5r5e.dicepicker.use_void_point_label'}} <i class="i_void" title="{{localize 'l5r5e.dicepicker.void_point_tooltip'}}"></i>
</label> </label>
{{/if}} {{/if}}
</td> </td>
<td> <td>
<div class="third">
<i class="assistance pointer-choice fa fa-minus-square" data-item="assistance" data-value="-1"></i>
</div>
<div class="third">
<i class="i_skill"></i> {{localize 'l5r5e.dicepicker.skill_assistance_label'}}
<div class="dice-container">
<img src="systems/l5r5e/assets/dices/default/3d/blank.png" alt="1" />
<div class="dice-value">
<input class="input-dice" type="text" name="skill.assistance" value="{{data.skill.assistance}}" readonly="readonly" />
</div>
</div>
</div>
<div class="third">
<i class="assistance pointer-choice fa fa-plus-square" data-item="assistance" data-value="1"></i>
</div>
</td>
</tr>
<tr>
<td colspan="3">
<button name="roll" type="submit" {{#if disableSubmit}}disabled{{/if}}>{{localize 'l5r5e.dicepicker.roll_label'}} <i class='fas fa-arrow-circle-right'></i></button>
</td> </td>
</tr> </tr>
</table> </table>
</form>
<div class="form-group">
<button name="roll" type="submit" {{#if disableSubmit}}disabled{{/if}}>{{localize 'l5r5e.dicepicker.roll_label'}} <i class='fas fa-arrow-circle-right'></i></button>
</div>
</form>

View File

@@ -1,6 +1,14 @@
<form class="l5r5e gm-tools-dialog" autocomplete="off"> <form class="l5r5e gm-tools-dialog" autocomplete="off">
<p class="gm-tools-container"> <ul class="gm-tools-container">
<a class="difficulty_hidden"><i class="fa fa-eye{{#if data.difficultyHidden}}-slash{{/if}}"></i></a> <li class="difficulty_hidden" title="{{localize 'l5r5e.gm_toolbox.difficulty_hidden'}}">
<strong class="difficulty">{{data.difficulty}}</strong> <i class="fa fa-eye{{#if data.difficultyHidden}}-slash{{/if}}"></i>
</p> <strong class="difficulty" title="{{localize 'l5r5e.gm_toolbox.difficulty'}}">{{data.difficulty}}</strong>
</form> </li>
<li class="gm_actor_updates sleep" data-type="sleep" title="{{localize 'l5r5e.gm_toolbox.sleep'}}">
<i class="fa fa-bed"></i>
</li>
<li class="gm_actor_updates scene_end" data-type="scene_end" title="{{localize 'l5r5e.gm_toolbox.scene_end'}}">
<i class="fas fa-star-half-alt"></i>
</li>
</ul>
</form>

View File

@@ -1,90 +1,130 @@
<form class="l5r5e roll-n-keep-dialog" autocomplete="off"> <form class="{{cssClass}}" autocomplete="off">
{{!-- Profil --}} {{!-- Profil --}}
<div class="l5r5e profil"> <header class="l5r5e profil part-header flexrow chat-profil">
<header class="part-header flexrow chat-profil"> <ul>
<span class="chat-profil-element"> <li class="chat-profil-element">
<img class="profile-img" <img class="profile-img" src="{{#if l5r5e.actor.img}}{{l5r5e.actor.img}}{{else}}icons/svg/mystery-man.svg{{/if}}" data-edit="img" alt="{{#if l5r5e.actor.name}}{{l5r5e.actor.name}}{{else}}mystery-man{{/if}}" />
src="{{#if l5r5e.actor.img}}{{l5r5e.actor.img}}{{else}}icons/svg/mystery-man.svg{{/if}}" </li>
data-edit="img" <li class="chat-profil-element">
height="40"
width="40"
alt="{{#if l5r5e.actor.name}}{{l5r5e.actor.name}}{{else}}mystery-man{{/if}}"
>
</span>
<span class="chat-profil-element">
<i class="chat-profil-stance {{l5r5e.stance}} i_{{l5r5e.stance}}" title="{{localizeRing l5r5e.stance}}"></i> <i class="chat-profil-stance {{l5r5e.stance}} i_{{l5r5e.stance}}" title="{{localizeRing l5r5e.stance}}"></i>
</span> </li>
<li class="chat-profil-element-skill">
<span class="chat-profil-element-skill">
{{#if l5r5e.skillId}} {{#if l5r5e.skillId}}
{{localizeSkillId l5r5e.skillId}} {{localizeSkillId l5r5e.skillId}}
{{else}} {{else}}
{{#if l5r5e.skillCatId}}{{localizeSkill l5r5e.skillCatId 'title'}}{{/if}} {{#if l5r5e.skillCatId}}{{localizeSkill l5r5e.skillCatId 'title'}}{{/if}}
{{/if}} {{/if}}
</span> </li>
<li class="chat-profil-element">
<span class="chat-profil-element"> {{#if l5r5e.difficultyHidden}}
{{#if l5r5e.summary.difficultyHidden}}
{{localize 'l5r5e.chatdices.difficulty_hidden'}} {{localize 'l5r5e.chatdices.difficulty_hidden'}}
{{else}} {{else}}
{{localize 'l5r5e.chatdices.difficulty'}} {{l5r5e.summary.difficulty}} {{localize 'l5r5e.chatdices.difficulty'}} {{l5r5e.difficulty}}
{{/if}} {{/if}}
{{#if l5r5e.summary.voidPointUsed}} <br />
<br><i class="i_void" title="{{localize 'l5r5e.chatdices.void_point_used'}}"></i> {{#if l5r5e.voidPointUsed}}
<i class="i_void" title="{{localize 'l5r5e.chatdices.void_point_used'}}"></i>
{{/if}} {{/if}}
</span> {{#if l5r5e.skillAssistance}}
</header> <i class="i_skill" title="{{l5r5e.skillAssistance}}x {{localize 'l5r5e.chatdices.assistance_used'}}"></i>
</div> {{/if}}
</li>
</ul>
</header>
<section class="rnk-ct">
{{!-- Body --}}
{{#if options.editable}}
{{!-- Face Rings --}}
<fieldset class="dropbox swap">
<legend class="section-header">
<i class="fa fa-sign-in-alt" aria-hidden="true"></i> {{localize 'l5r5e.roll_n_keep.swap_drop_here'}} <i class="fa fa-arrows-alt-h"></i>
</legend>
{{!-- Discard & ReRoll --}} {{#each data.swapDiceFaces.rings}}
<table> <div class="dice dropbox faces-change" data-type="swap" data-face="{{this}}" data-die="RingDie">
<tr> <img src="{{getDiceFaceUrl 'RingDie' this}}" alt="{{this}}" />
<td> </div>
{{/each}}
</fieldset>
{{!-- Center --}}
<article class="rnk-center">
{{!-- Discard & ReRoll --}}
<fieldset class="dropbox discards" data-type="discard"> <fieldset class="dropbox discards" data-type="discard">
<legend class="section-header"><i class="fa fa-arrow-down" aria-hidden="true"></i> {{ localize 'l5r5e.roll_n_keep.discard_drop_here' }}</legend> <legend class="section-header">
<i class="fa fa-sign-in-alt" aria-hidden="true"></i> {{localize 'l5r5e.roll_n_keep.discard_drop_here'}} <i class="fa fa-times"></i>
</legend>
</fieldset> </fieldset>
</td>
<td>
&nbsp;
</td>
<td>
<fieldset class="dropbox rerolls" data-type="reroll"> <fieldset class="dropbox rerolls" data-type="reroll">
<legend class="section-header"><i class="fa fa-arrow-down" aria-hidden="true"></i> {{ localize 'l5r5e.roll_n_keep.reroll_drop_here' }}</legend> <legend class="section-header">
<i class="fa fa-sign-in-alt" aria-hidden="true"></i> {{localize 'l5r5e.roll_n_keep.reroll_drop_here'}} <i class="fa fa-redo-alt"></i>
</legend>
</fieldset> </fieldset>
</td> {{!-- DiceList history --}}
</tr> <table>
</table> {{#each data.dicesList as |item idxStep|}}
<tr>
{{!-- DiceList history --}} {{#each item as |dice idxDie|}}
<table> <td>
{{#each data.dicesList as |item idxStep|}} {{#if dice.face}}
<tr> {{#if dice.newFace}}
{{#each item as |dice idxDie|}} <span class="fas dice-ct {{dice.choice}}">
<td> <img class="dice {{dice.choice}}{{#ifCond ../../data.currentStep '==' idxStep}} draggable{{/ifCond}}" data-step="{{idxStep}}" data-die="{{idxDie}}" src="{{getDiceFaceUrl dice.type dice.newFace}}" alt="{{idxStep}}_{{idxDie}}" />
<div class="dice {{this.choice}} {{#ifCond (lookup ../../draggableList idxDie) '==' idxStep }}draggable{{/ifCond}}" data-step="{{idxStep}}" data-die="{{idxDie}}"> </span>
{{#if this.img}} {{else}}
<img src="{{this.img}}" alt="{{idxStep}}_{{idxDie}}" /> <span class="fas dice-ct {{dice.choice}}">
{{/if}} <img class="dice {{dice.choice}}{{#ifCond ../../data.currentStep '==' idxStep}} draggable{{/ifCond}}" data-step="{{idxStep}}" data-die="{{idxDie}}" src="{{getDiceFaceUrl dice.type dice.face}}" alt="{{idxStep}}_{{idxDie}}" />
</div> </span>
</td> {{/if}}
{{/each}} {{/if}}
</tr> </td>
{{/each}} {{/each}}
</table> </tr>
{{/each}}
{{!-- Keep --}} </table>
<table> {{!-- Keep --}}
<tr>
<td>
<fieldset class="dropbox keeps" data-type="keep"> <fieldset class="dropbox keeps" data-type="keep">
<legend class="section-header"><i class="fa fa-arrow-down" aria-hidden="true"></i> {{ localize 'l5r5e.roll_n_keep.keep_drop_here' }}</legend> <legend class="section-header">
<i class="fa fa-sign-in-alt" aria-hidden="true"></i> {{localize 'l5r5e.roll_n_keep.keep_drop_here'}} <i class="fa fa-check"></i>
</legend>
</fieldset> </fieldset>
</td> </article>
</tr> {{!-- Face Skills --}}
</table> <fieldset class="dropbox swap">
<legend class="section-header">
<button id="finalize" name="finalize" type="button">{{ localize 'l5r5e.roll_n_keep.bt_validate' }} <i class='fas fa-arrow-circle-right'></i></button> <i class="fa fa-sign-in-alt" aria-hidden="true"></i> {{localize 'l5r5e.roll_n_keep.swap_drop_here'}} <i class="fa fa-arrows-alt-h"></i>
</legend>
{{#each data.swapDiceFaces.skills}}
<div class="dice dropbox faces-change" data-type="swap" data-face="{{this}}" data-die="AbilityDie">
<img src="{{getDiceFaceUrl 'AbilityDie' this}}" alt="{{this}}" />
</div>
{{/each}}
</fieldset>
<button id="finalize" name="finalize" type="button" {{#if data.submitDisabled}}disabled{{/if}}>
{{ localize 'l5r5e.roll_n_keep.bt_validate' }} <i class="fas fa-arrow-circle-right"></i>
</button>
{{else}}
<table>
{{!-- Non editable DiceList history --}}
{{#each data.dicesList as |item idxStep|}}
<tr>
{{#each item as |dice idxDie|}}
<td>
{{#if dice.face}}
{{#if dice.newFace}}
<span class="fas dice-ct {{dice.choice}}">
<img class="dice {{dice.choice}}" src="{{getDiceFaceUrl dice.type dice.newFace}}" alt="{{idxStep}}_{{idxDie}}" />
</span>
{{else}}
<span class="fas dice-ct {{dice.choice}}">
<img class="dice {{dice.choice}}" src="{{getDiceFaceUrl dice.type dice.face}}" alt="{{idxStep}}_{{idxDie}}" />
</span>
{{/if}}
{{/if}}
</td>
{{/each}}
</tr>
{{/each}}
</table>
{{/if}}
</section>
</form> </form>

View File

@@ -4,7 +4,7 @@
<li class="item-name">{{ advancement.name }}</li> <li class="item-name">{{ advancement.name }}</li>
{{#if editable}} {{#if editable}}
<li data-item-id="{{advancement._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li> <li data-item-id="{{advancement._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{advancement._id}}" class="item-control item-delete" title="{{localize 'l5r5e.global.delete'}}"><i class="fas fa-trash"></i></li> <li data-item-id="{{advancement._id}}" class="item-control item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}} {{/if}}
</ul> </ul>
{{#if advancement.data.description}} {{#if advancement.data.description}}

View File

@@ -8,7 +8,7 @@
</li> </li>
{{#if editable}} {{#if editable}}
<li data-item-id="{{item._id}}" class="item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li> <li data-item-id="{{item._id}}" class="item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{item._id}}" class="item-delete" title="{{localize 'l5r5e.global.delete'}}"><i class="fas fa-trash"></i></li> <li data-item-id="{{item._id}}" class="item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}} {{/if}}
</ul> </ul>
<ul class="item-properties"> <ul class="item-properties">

View File

@@ -1,8 +1,8 @@
<fieldset class="armors-content"> <fieldset class="armors-content">
<legend class="section-header"> <legend class="section-header">
{{ localize 'l5r5e.armors.title' }} {{localize 'l5r5e.armors.title'}}
{{#if editable}} {{#if editable}}
<a data-item-type="armor" class="armor-control item-add" title="{{ localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a> <a data-item-type="armor" data-item-eqquiped="true" class="armor-control item-add" title="{{localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a>
{{/if}} {{/if}}
</legend> </legend>
<ul class="item-list"> <ul class="item-list">

View File

@@ -5,7 +5,7 @@
{{#if editable}} {{#if editable}}
<li data-item-id="{{item._id}}" data-type="equipped" class="item-equip equip-readied-control" title="{{localize 'l5r5e.armors.equipped'}}"><i class="fas {{#if item.data.equipped}}fa-tshirt{{else}}fa-weight-hanging{{/if}}"></i></li> <li data-item-id="{{item._id}}" data-type="equipped" class="item-equip equip-readied-control" title="{{localize 'l5r5e.armors.equipped'}}"><i class="fas {{#if item.data.equipped}}fa-tshirt{{else}}fa-weight-hanging{{/if}}"></i></li>
<li data-item-id="{{item._id}}" class="item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li> <li data-item-id="{{item._id}}" class="item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{item._id}}" class="item-delete" title="{{localize 'l5r5e.global.delete'}}"><i class="fas fa-trash"></i></li> <li data-item-id="{{item._id}}" class="item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}} {{/if}}
</ul> </ul>
<ul class="item-properties"> <ul class="item-properties">

View File

@@ -1,15 +1,13 @@
<fieldset class="items-content"> {{#each data.splitItemsList as |cat type|}}
<legend> <h3>
{{ localize 'l5r5e.equipment' }} {{localize (localize 'l5r5e.{type}s.title' type=type) }}
{{#if editable}} {{#if ../editable}}
<a data-item-type="item" class="item-control item-add" title="{{ localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a> <a data-item-type="{{type}}" class="item-control item-add" title="{{ localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a>
{{/if}} {{/if}}
</legend> </h3>
<ul class="item-list"> <ul class="item-list">
{{#each actor.items as |item id|}} {{#each cat as |item id|}}
{{#ifCond '["item", "armor", "weapon"]' 'includes' item.type}} {{> 'systems/l5r5e/templates/items/item/item-entry.html' item=item id=id editable=../../editable }}
{{> 'systems/l5r5e/templates/items/item/item-entry.html' item=item id=id editable=../editable }}
{{/ifCond}}
{{/each}} {{/each}}
</ul> </ul>
</fieldset> {{/each}}

View File

@@ -4,7 +4,7 @@
<li class="item-name">{{ peculiarity.name }}</li> <li class="item-name">{{ peculiarity.name }}</li>
{{#if editable}} {{#if editable}}
<li data-item-id="{{peculiarity._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li> <li data-item-id="{{peculiarity._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{peculiarity._id}}" class="item-control item-delete" title="{{localize 'l5r5e.global.delete'}}"><i class="fas fa-trash"></i></li> <li data-item-id="{{peculiarity._id}}" class="item-control item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}} {{/if}}
</ul> </ul>
{{#if peculiarity.data.types}} {{#if peculiarity.data.types}}

View File

@@ -3,7 +3,7 @@
<li class="item-img"><img src="{{item.img}}" title="{{item.name}}" width="32px" height="32px"/></li> <li class="item-img"><img src="{{item.img}}" title="{{item.name}}" width="32px" height="32px"/></li>
<li class="item-name">{{ item.name }}</li> <li class="item-name">{{ item.name }}</li>
{{#if editable}} {{#if editable}}
<li class="property-delete" title="{{localize 'l5r5e.global.delete'}}"><i class="fas fa-trash"></i></li> <li class="property-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}} {{/if}}
</ul> </ul>
{{#if item.data.data.description}} {{#if item.data.data.description}}

View File

@@ -4,7 +4,7 @@
<li class="item-name">{{ technique.name }}</li> <li class="item-name">{{ technique.name }}</li>
{{#if editable}} {{#if editable}}
<li data-item-id="{{technique._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li> <li data-item-id="{{technique._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{technique._id}}" class="item-control item-delete" title="{{localize 'l5r5e.global.delete'}}"><i class="fas fa-trash"></i></li> <li data-item-id="{{technique._id}}" class="item-control item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}} {{/if}}
</ul> </ul>
{{#if technique.data.description}} {{#if technique.data.description}}

View File

@@ -9,7 +9,7 @@
</li> </li>
{{#if editable}} {{#if editable}}
<li data-item-id="{{item._id}}" class="item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li> <li data-item-id="{{item._id}}" class="item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
<li data-item-id="{{item._id}}" class="item-delete" title="{{localize 'l5r5e.global.delete'}}"><i class="fas fa-trash"></i></li> <li data-item-id="{{item._id}}" class="item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
{{/if}} {{/if}}
</ul> </ul>
<ul class="item-properties"> <ul class="item-properties">

View File

@@ -1,8 +1,8 @@
<fieldset class="weapons-content"> <fieldset class="weapons-content">
<legend class="section-header"> <legend class="section-header">
{{ localize 'l5r5e.weapons.title' }} {{localize 'l5r5e.weapons.title'}}
{{#if editable}} {{#if editable}}
<a data-item-type="weapon" class="weapon-control item-add" title="{{ localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a> <a data-item-type="weapon" data-item-eqquiped="true" class="weapon-control item-add" title="{{localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a>
{{/if}} {{/if}}
</legend> </legend>
<ul class="item-list"> <ul class="item-list">