diff --git a/css/fvtt-cthulhu-eternal.css b/css/fvtt-cthulhu-eternal.css index 5f5e982..82f2a94 100644 --- a/css/fvtt-cthulhu-eternal.css +++ b/css/fvtt-cthulhu-eternal.css @@ -170,10 +170,62 @@ i.fvtt-cthulhu-eternal { background-position: 0%; background-size: 100% 100%; } +.chat-lethal-damage ul { + list-style-type: none; + padding: 0; + margin: 0; + justify-content: center; + align-items: center; +} +.chat-lethal-damage ul .result-lethal { + color: var(--color-critical-failure); + font-family: var(--font-title); +} +.chat-lethal-damage ul .result-non-lethal { + color: var(--color-failure); + font-family: var(--font-title); +} +.chat-lethal-damage ul li { + margin: 0 10px; + font-family: var(--font-primary); + font-size: calc(var(--font-size-standard) * 1.02); +} .fvtt-cthulhu-eternal .protagonist-sheet-common label { font-family: var(--font-secondary); font-size: calc(var(--font-size-standard) * 1); } +.fvtt-cthulhu-eternal .protagonist-sheet-common .hp-unconscious { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); + color: #b4710c; +} +.fvtt-cthulhu-eternal .protagonist-sheet-common .hp-dead { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); + color: #b40000; +} +.fvtt-cthulhu-eternal .protagonist-sheet-common .protagonist-luck { + display: flex; + min-width: 8rem; + max-width: 8rem; +} +.fvtt-cthulhu-eternal .protagonist-sheet-common .protagonist-luck .rollable:hover, +.fvtt-cthulhu-eternal .protagonist-sheet-common .protagonist-luck .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; + font-size: 0.9rem; +} +.fvtt-cthulhu-eternal .protagonist-sheet-common .damage-bonus { + display: flex; +} +.fvtt-cthulhu-eternal .protagonist-sheet-common .damage-bonus label { + max-width: 5rem; + min-width: 5rem; +} +.fvtt-cthulhu-eternal .protagonist-sheet-common .damage-bonus input { + max-width: 2rem; + min-width: 2rem; +} .fvtt-cthulhu-eternal .vehicle-sheet-common label { font-family: var(--font-secondary); font-size: calc(var(--font-size-standard) * 1); @@ -203,6 +255,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; overflow: scroll; } .fvtt-cthulhu-eternal .protagonist-content .sheet-tabs a { @@ -250,7 +303,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .protagonist-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -258,6 +311,38 @@ i.fvtt-cthulhu-eternal { font-family: var(--font-secondary); font-size: calc(var(--font-size-standard) * 1); } +.fvtt-cthulhu-eternal .protagonist-content .hp-unconscious { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); + color: #b4710c; +} +.fvtt-cthulhu-eternal .protagonist-content .hp-dead { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); + color: #b40000; +} +.fvtt-cthulhu-eternal .protagonist-content .protagonist-luck { + display: flex; + min-width: 8rem; + max-width: 8rem; +} +.fvtt-cthulhu-eternal .protagonist-content .protagonist-luck .rollable:hover, +.fvtt-cthulhu-eternal .protagonist-content .protagonist-luck .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; + font-size: 0.9rem; +} +.fvtt-cthulhu-eternal .protagonist-content .damage-bonus { + display: flex; +} +.fvtt-cthulhu-eternal .protagonist-content .damage-bonus label { + max-width: 5rem; + min-width: 5rem; +} +.fvtt-cthulhu-eternal .protagonist-content .damage-bonus input { + max-width: 2rem; + min-width: 2rem; +} .fvtt-cthulhu-eternal .sheet-tabs { background-color: var(--color-light-1); } @@ -295,9 +380,6 @@ i.fvtt-cthulhu-eternal { width: 2rem; margin-left: 4px; } -.fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-left .protagonist-hp .damage-bonus { - font-size: calc(var(--font-size-standard) * 0.8); -} .fvtt-cthulhu-eternal .protagonist-main .protagonist-pc .protagonist-left .protagonist-hp .hp-separator { font-size: calc(var(--font-size-standard) * 1.2); display: flex; @@ -867,6 +949,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; overflow: scroll; } .fvtt-cthulhu-eternal .vehicle-content .sheet-tabs a { @@ -914,7 +997,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .vehicle-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -1124,6 +1207,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; overflow: scroll; } .fvtt-cthulhu-eternal .creature-content .sheet-tabs a { @@ -1171,7 +1255,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .creature-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -1782,6 +1866,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .skill-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -1828,7 +1913,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .skill-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -1876,6 +1961,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .injury-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -1922,7 +2008,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .injury-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -1970,6 +2056,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .weapon-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2016,7 +2103,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .weapon-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2056,6 +2143,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .armor-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2102,7 +2190,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .armor-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2142,6 +2230,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .motivation-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2188,7 +2277,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .motivation-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2228,6 +2317,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .mentaldisorder-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2274,7 +2364,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .mentaldisorder-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2314,6 +2404,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .bond-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2360,7 +2451,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .bond-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2416,6 +2507,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .gear-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2462,7 +2554,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .gear-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2502,6 +2594,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .arcane-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2548,7 +2641,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .arcane-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2588,6 +2681,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .archetype-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2634,7 +2728,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .archetype-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2674,6 +2768,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .ritual-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2720,7 +2815,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .ritual-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2768,6 +2863,7 @@ i.fvtt-cthulhu-eternal { background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; } .fvtt-cthulhu-eternal .tome-content .sheet-tabs a { color: rgba(32, 31, 31, 0.8); @@ -2814,7 +2910,7 @@ i.fvtt-cthulhu-eternal { } .fvtt-cthulhu-eternal .tome-content legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -2940,6 +3036,11 @@ i.fvtt-cthulhu-eternal { margin-left: 2rem; display: none; } +.dice-roll .intro-chat .intro-right ul .healing-roll { + font-size: calc(var(--font-size-standard) * 1); + margin-left: 2rem; + display: none; +} .dice-roll .intro-chat .intro-right ul .roll-damage { font-size: calc(var(--font-size-standard) * 1); margin-left: 2rem; diff --git a/cthulhu-eternal.mjs b/cthulhu-eternal.mjs index 44082f9..b59828b 100644 --- a/cthulhu-eternal.mjs +++ b/cthulhu-eternal.mjs @@ -124,12 +124,12 @@ Hooks.once("ready", function () { } preLocalizeConfig() - if (game.user.isGM && game.i18n.lang === 'fr' && !game.modules.find(m => m.id == "babele")) { + if (game.user.isGM && game.i18n.lang === 'fr' && typeof Babele === 'undefined') { ChatMessage.create({ user: game.user.id, whisper: [game.user.id], content: `
- ATTENTION ! Français détecte, mais le module Babele n'est pas installé !
Installez Babele pour bénéficier de la traduction des compendiums` + ATTENTION ! Français détecté, mais le module Babele n'est pas installé !
Installez Babele pour bénéficier de la traduction des compendiums` }) } @@ -144,12 +144,18 @@ Hooks.on("renderChatMessageHTML", (message, html, data) => { $(html).find(".damage-roll").each((i, btn) => { btn.style.display = "inline" }) + $(html).find(".healing-roll").each((i, btn) => { + btn.style.display = "inline" + }) $(html).find(".nudge-roll").click((event) => { CthulhuEternalUtils.nudgeRoll(message) }) $(html).find(".damage-roll").click((event) => { CthulhuEternalUtils.damageRoll(message) }) + $(html).find(".healing-roll").click((event) => { + CthulhuEternalUtils.healingRoll(message) + }) } }) diff --git a/lang/en.json b/lang/en.json index 8c55692..629e152 100644 --- a/lang/en.json +++ b/lang/en.json @@ -57,6 +57,12 @@ "label": "Storage" } }, + "hp": { + "label": "HP", + "stunned": { + "label": "Stun." + } + }, "biodata": { "feature": { "label": "Feature" @@ -207,6 +213,12 @@ "RangedWeapons": "Ranged Weapons", "FirearmsBeams": "Firearms / Beam Weapons", "FIELDS": { + "isHealing": { + "label": "Healing skill" + }, + "healingFormula": { + "label": "Healing PV roll" + }, "isAdversary": { "label": "Adversary" }, @@ -278,6 +290,15 @@ "directSkillValue": { "label": "Direct skill value" }, + "ammo": { + "label": "Ammo", + "value": { + "label": "Ammo value" + }, + "max": { + "label": "Max ammo" + } + }, "state": { "label": "State" }, @@ -495,9 +516,14 @@ } }, "Label": { + "rollNudge": "Roll Nudge", + "rollDamage": "Roll Damage", + "rollHealing": "Roll Healing", + "result": "Result", + "damageMessage": "Damage to apply", "lethalityRoll": "Lethality Roll", - "lethalityWounded": "The target is lethally wounded", - "lethalityNotWounded": "The target is not lethally wounded", + "lethalityWounded": "The target is lethally wounded (HP = 0)", + "lethalityNotWounded": "The target is not lethally wounded, apply damage", "damageRoll": "Damage Roll", "vehicle":"Vehicle", "Weapon": "Weapon", @@ -622,7 +648,21 @@ "noActorFound": "No actor found", "skillFailed": "Skill roll failed : the skill has been ticked for progression", "rollProgress": "Roll Progress", - "skillProgress": "Skill Progress" + "skillProgress": "Skill Progress", + "unconscious": "Unconscious", + "dying": "Dying", + "stunnedWarning": "The Protagonist is stunned. He cannot act until he recovers by successfully rolling a CONx5 check.", + "deadWarning": "The Protagonist is dead. He cannot act until he is revived by a successful First Aid roll.", + "unconsciousWarning": "The Protagonist is unconscious. He cannot act until he has at least 3 HP.", + "Luck": "Luck", + "titleLuck": "Luck Roll", + "healingRoll": "Healing Roll succes, the target gains", + "healingRollFailure": "Healing roll failed ! The target looses", + "killRadius": "Kill Radius", + "killRadiusInfo": "All targets within the kill radius suffer the damage", + "ammoUsed": "Ammo used", + "lethalityLethal": "Lethal !!", + "lethalityNotLethal": "Non-Lethal" }, "ChatMessage": { "exhausted": "Your protagonist is exhausted. He loses [[/r 1d6]] Willpower Points." @@ -651,7 +691,9 @@ "NoWeaponSkill": "No weapon skill found for this weapon. Check Weapon definition or available skills/era", "NoWeaponType": "No weapon type found for this weapon subtype. Check Weapon definition or available skills/era", "skillAlreadyExists": "Skill already exists", - "WrongEra": "The era of the item does not match the ear of the system" + "WrongEra": "The era of the item does not match the ear of the system", + "NoSelectiveFireChoices": "Not enough ammo fo Selective Fire choices for this weapon.", + "NoAmmo": "No more ammo for this weapon. " } } } diff --git a/lang/fr.json b/lang/fr.json index af0f364..4524ecc 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -42,6 +42,12 @@ "FIELDS": { "damageBonus": { "label": "Bonus D." + }, + "hp": { + "label": "HP", + "stunned": { + "label": "Etourdi" + } }, "resources": { "permanentRating": { @@ -207,6 +213,12 @@ "RangedWeapons": "Armes de tir", "FirearmsBeams": "Armes à feu / à rayons", "FIELDS": { + "isHealing": { + "label": "Compétence de soin" + }, + "healingFormula": { + "label": "PV soignés" + }, "isAdversary": { "label": "Adversaire" }, @@ -272,6 +284,15 @@ "longspray": "Barrage long" }, "FIELDS": { + "ammo": { + "label": "Munitions", + "value": { + "label": "Munitions (actuelles)" + }, + "max": { + "label": "Munitions (max)" + } + }, "hasDirectSkill": { "label": "Compétence intégrée" }, @@ -495,9 +516,14 @@ } }, "Label": { + "rollNudge": "Modifier le jet", + "rollDamage": "Jet de dégâts", + "rollHealing": "Jet de soin", + "result": "Resultat", + "damageMessage": "Dégâts à appliquer", "lethalityRoll": "Jet de Létalité", - "lethalityWounded": "La cible est mortellement blessée", - "lethalityNotWounded": "La cible n'est PAS mortellement blessée", + "lethalityWounded": "La cible est mortellement blessée (PV = 0)", + "lethalityNotWounded": "La cible n'est PAS mortellement blessée, encaissement des dégâts", "damageRoll": "Jet de dégâts", "vehicle":"Véhicule", "Weapon": "Arme", @@ -559,7 +585,7 @@ "conLong": "Constitution", "chaLong": "Charisme", "total": "Total", - "skills": "Compétence", + "skills": "Compétences", "gear": "Matériel", "damage": "Dégâts", "resource": "Ressource", @@ -622,7 +648,21 @@ "noActorFound": "Aucun protagoniste trouvé", "skillFailed": "Jet de compétence échoué : la compétence a été marquée comme pouvant progresser.", "rollProgress": "Jet de progression", - "skillProgress": "Progression de compétence" + "skillProgress": "Progression de compétence", + "unconscious": "Inconscient", + "dying": "Mourant", + "stunnedWarning": "Votre protagoniste est étourdi. Il ne peut pas agir tant qu'il n'a pas réussi un test de CON x 5.", + "deadWarning": "Votre protagoniste est mourrant. Il mourra s'il n'est pas soigné dans les {con} minutes", + "unconsciousWarning": "Votre protagoniste est inconscient. Il ne peut pas agir tant qu'il n'a pas atteint 3 PV.", + "Luck": "Chance", + "titleLuck": "Jet de Chance", + "healingRoll": "Jet de soin, PV soignés", + "healingRollFailure": "Jet de soin échoué critique, PV perdus", + "killRadius": "Rayon de mortlalité", + "killRadiusInfo": "Si la cible est dans le rayon de mortalité, elle subit les dommages.", + "ammoUsed": "Munitions utilisées", + "lethalityLethal": "Létal !!", + "lethalityNotLethal": "Non létal" }, "ChatMessage": { "exhausted": "Votre protagoniste est épuisé. Il perd [[/r 1d6]] Points de Volonté." @@ -651,7 +691,9 @@ "NoWeaponSkill": "Aucune compétence associée n'a été trouvé pour cette arme. Vérifier la définition de l'arme ainsi que l'époque configurée.", "NoWeaponType": "Aucun type d'arme trouvé pour ce sous-type. Vérifier la définition de l'arme ainsi que l'époque configurée.", "skillAlreadyExists": "La compétence existe déja", - "WrongEra": "L'époque de l'item ne correspond pas à celle du jeu en cours." + "WrongEra": "L'époque de l'item ne correspond pas à celle du jeu en cours.", + "NoSelectiveFireChoices": "Aucune option de tir sélectif n'est disponible pour cette arme : pas assez de munitions.", + "NoAmmo": "Aucune munition disponible pour cette arme." } } } diff --git a/module/applications/sheets/protagonist-sheet.mjs b/module/applications/sheets/protagonist-sheet.mjs index c9eef8d..f517e5b 100644 --- a/module/applications/sheets/protagonist-sheet.mjs +++ b/module/applications/sheets/protagonist-sheet.mjs @@ -199,7 +199,7 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS * corresponding value from the document's system and performs the roll. */ async _onRoll(event, target) { - const rollType = $(event.currentTarget).data("roll-type") + let rollType = $(event.currentTarget).data("roll-type") let item let li // Debug : console.log(">>>>", event, target, rollType) @@ -231,6 +231,12 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS item.name = game.i18n.localize("CTHULHUETERNAL.Label.SAN") item.targetScore = item.value break; + case "luck": + item = foundry.utils.duplicate(this.actor.system.characteristics.int) + item.name = game.i18n.localize("CTHULHUETERNAL.Label.Luck") + item.value = 10 + item.targetScore = 50 + break; default: throw new Error(`Unknown roll type ${rollType}`) } diff --git a/module/applications/sheets/weapon-sheet.mjs b/module/applications/sheets/weapon-sheet.mjs index 7c51113..0bee717 100644 --- a/module/applications/sheets/weapon-sheet.mjs +++ b/module/applications/sheets/weapon-sheet.mjs @@ -18,4 +18,13 @@ export default class CthulhuEternalWeaponSheet extends CthulhuEternalItemSheet { template: "systems/fvtt-cthulhu-eternal/templates/weapon.hbs", }, } + + async _prepareContext() { + let context = await super._prepareContext() + context.isFireArm = this.item.system.isFireArm() + context.isRanged = this.item.system.isRanged() + + return context + } + } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index e0a358a..64c4937 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -31,7 +31,6 @@ export default class CthulhuEternalActor extends Actor { } _onUpdate(changed, options, userId) { - // DEBUG : console.log("CthulhuEternalActor.update", changed, options, userId) if (changed?.system?.wp?.exhausted) { ChatMessage.create({ user: userId, diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index ecaef37..23b8dde 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -105,6 +105,105 @@ export default class CthulhuEternalRoll extends Roll { $(".resource-score").text(`${rating} (${options.percentScore}%)`) } + static buildSelectiveFireChoices(actor, weapon) { + if (!weapon || !weapon?.system?.hasSelectiveFire) { + return {} + } + // Loop thru the selective fire choices and build the choices object when enough ammo in the weapon + let choices = {} + for (let choiceKey in SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES) { + let choice = SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES[choiceKey] + if (choice.ammoUsed > 0 && choice.ammoUsed <= weapon.system.ammo.value) { + choices[choiceKey] = choice + } + } + // If no choices available, warn the user + if (Object.keys(choices).length === 0) { + ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.NoSelectiveFireChoices")) + return {} + } + return choices + } + + static async processWeaponDamage(actor, options) { + let isLethal = false + let weapon = options.rollItem + let ammoUsed = weapon.system.weaponType.includes("ranged") ? 1 : 0 // Default ammo used for melee weapons is 0 + options.isNudge = false + + // Selective fire management + if (weapon.system.hasSelectiveFire && weapon.selectiveFireChoice) { + let choice = SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES[weapon.selectiveFireChoice] + if (choice.ammoUsed > weapon.system.ammo.value) { + ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.NoAmmo")) + return + } + weapon.system.selectiveFireChoiceLabel = choice.label // Store the choice in the weapon + weapon.system.lethality = choice.lethality // Override lethality + weapon.system.killRadius = choice.killRadius // Override kill radius + ammoUsed = choice.ammoUsed // Override ammo used + } + + if (weapon.system.lethality > 0) { + let lethalityRoll = new Roll("1d100") + await lethalityRoll.evaluate() + let lethalScore = (options?.previousResultType === "successCritical") ? weapon.system.lethality * 2 : weapon.system.lethality + isLethal = (lethalityRoll.total <= lethalScore) + if (ammoUsed > 0) { + await actor.updateEmbeddedDocuments("Item", [{ + _id: weapon._id, + "system.ammo.value": Math.max(0, weapon.system.ammo.value - ammoUsed) + }]) + } + let wounds = Math.floor(lethalityRoll.total / 10) + (lethalityRoll.total % 10) + let msgData = { + weapon, + wounds, + lethalScore, + isLethal, + ammoUsed, + rollResult: lethalityRoll.total, + } + let flavor = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-lethal-damage.hbs", msgData) + ChatMessage.create({ + user: game.user.id, + content: flavor, + speaker: ChatMessage.getSpeaker({ actor: actor }), + }, { rollMode: options.rollMode, create: true }) + + return + } + + // If the weapon is not lethal, we can proceed with the regular damage roll + let formula = weapon.system.damage + if (weapon.system.weaponType === "melee" || weapon.system.weaponType === "unarmed") { + formula += ` + ${weapon.damageBonus}` + } + if (options?.previousResultType === "successCritical") { + formula = `( ${formula} ) * 2` + } + if (ammoUsed > 0) { + await actor.updateEmbeddedDocuments("Item", [{ + _id: weapon._id, + "system.ammo.value": Math.max(0, weapon.system.ammo.value - ammoUsed) + }]) + } + let damageRoll = new Roll(formula) + await damageRoll.evaluate() + let msgData = { + weapon, + formula, + ammoUsed, + rollResult: damageRoll.total, + } + let flavor = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/chat-regular-damage.hbs", msgData) + ChatMessage.create({ + user: game.user.id, + content: flavor, + speaker: ChatMessage.getSpeaker({ actor: actor }), + }, { rollMode: options.rollMode, create: true }) + } + /** * Prompt the user with a dialog to configure and execute a roll. * @@ -124,12 +223,18 @@ export default class CthulhuEternalRoll extends Roll { let hasModifier = true let hasMultiplier = false options.isNudge = true + let actor = game.actors.get(options.actorId) switch (options.rollType) { case "skill": console.log(options.rollItem) options.initialScore = options.rollItem.system.computeScore() break + case "luck": + hasModifier = false + options.initialScore = 50 + options.isNudge = false + break case "san": case "char": options.initialScore = options.rollItem.targetScore @@ -146,40 +251,8 @@ export default class CthulhuEternalRoll extends Roll { options.rollItem.enableStorage = true options.isNudge = false break - case "damage": { - let isLethal = false - options.isNudge = false - if (options.rollItem.system.lethality > 0) { - let lethalityRoll = new Roll("1d100") - await lethalityRoll.evaluate() - let lethalScore = (options?.previousResultType === "successCritical") ? options.rollItem.system.lethality * 2 : options.rollItem.system.lethality - isLethal = (lethalityRoll.total <= lethalScore) - let flavor = `${options.rollItem.name} - ${game.i18n.localize("CTHULHUETERNAL.Label.lethalityRoll")} : ${lethalityRoll.total} <= ${lethalScore} => ${isLethal}` - if (isLethal) { - flavor += `
${game.i18n.localize("CTHULHUETERNAL.Label.lethalityWounded")} => HP = 0` - } else { - let wounds = Math.floor(lethalityRoll.total / 10) + (lethalityRoll.total % 10) - flavor += `
${game.i18n.localize("CTHULHUETERNAL.Label.lethalityNotWounded")} => HP loss = ${wounds}` - } - await lethalityRoll.toMessage({ - flavor: flavor - }); - return - } - let formula = options.rollItem.system.damage - if (options.rollItem.system.weaponType === "melee" || options.rollItem.system.weaponType === "unarmed") { - formula += ` + ${options.rollItem.damageBonus}` - } - if (options?.previousResultType === "successCritical") { - formula = `( ${formula} ) * 2` - } - let damageRoll = new Roll(formula) - await damageRoll.evaluate() - await damageRoll.toMessage({ - flavor: `${options.rollItem.name} - ${game.i18n.localize("CTHULHUETERNAL.Label.damageRoll")}` - }); - } - return + case "damage": + return this.processWeaponDamage(actor, options) case "weapon": { let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era") if (era !== options.rollItem.system.settings) { @@ -192,6 +265,11 @@ export default class CthulhuEternalRoll extends Roll { console.log("WP Not found", era, options.rollItem.system.weaponType) return } + // Check if the weapon has enouth ammo in case of a firearm + if (options.rollItem.system.isFireArm() && options.rollItem.system.ammo.value <= 0) { + ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.NoAmmo")) + return + } options.weapon = options.rollItem if (options.rollItem.system.hasDirectSkill) { let skillName = options.rollItem.name @@ -199,7 +277,6 @@ export default class CthulhuEternalRoll extends Roll { options.initialScore = options.weapon.system.directSkillValue } else { let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) - let actor = game.actors.get(options.actorId) options.rollItem = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase()) if (!options.rollItem) { ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill")) @@ -215,7 +292,6 @@ export default class CthulhuEternalRoll extends Roll { break } - console.log("Roll options", CONFIG.Dice.rollModes); const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes); //Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)])) const fieldRollMode = new foundry.data.fields.StringField({ choices: rollModes, @@ -225,7 +301,7 @@ export default class CthulhuEternalRoll extends Roll { const choiceModifier = SYSTEM.MODIFIER_CHOICES const choiceMultiplier = SYSTEM.MULTIPLIER_CHOICES - const choiceSelectiveFire = SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES + const choiceSelectiveFire = this.buildSelectiveFireChoices(actor, options?.weapon) let modifier = "+0" let multiplier = "5" @@ -318,6 +394,10 @@ export default class CthulhuEternalRoll extends Roll { } rollData.targetScore = Math.min(Math.max(rollData.targetScore, 0), 100) } + if (!rollData.targetScore) { + rollData.targetScore = options.initialScore + rollData.modifier = "0" + } if (Hooks.call("fvtt-cthulhu-eternal.preRoll", options, rollData) === false) return @@ -390,6 +470,8 @@ export default class CthulhuEternalRoll extends Roll { */ static createTitle(type, target) { switch (type) { + case "luck": + return `${game.i18n.localize("CTHULHUETERNAL.Label.titleLuck")}` case "skill": return `${game.i18n.localize("CTHULHUETERNAL.Label.titleSkill")}` case "weapon": diff --git a/module/models/protagonist.mjs b/module/models/protagonist.mjs index d012817..be0bd60 100644 --- a/module/models/protagonist.mjs +++ b/module/models/protagonist.mjs @@ -35,7 +35,9 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData schema.hp = new fields.SchemaField({ value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }), max: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }), - stunned: new fields.BooleanField({ required: true, initial: false }) + stunned: new fields.BooleanField({ required: true, initial: false }), + unconscious: new fields.BooleanField({ required: true, initial: false }), + dead: new fields.BooleanField({ required: true, initial: false }) }) schema.san = new fields.SchemaField({ @@ -130,6 +132,22 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData updates[`system.damageBonus`] = dmgBonus } + // Unconsciousness management + if (!this.hp.unconscious && this.hp.value <= 2) { + updates[`system.hp.unconscious`] = true + } + if (this.hp.unconscious && this.hp.value > 2) { + updates[`system.hp.unconscious`] = false + } + + // Dead management + if (!this.hp.dead && this.hp.value <= 0) { + updates[`system.hp.dead`] = true + } + if (this.hp.dead && this.hp.value > 0) { + updates[`system.hp.dead`] = false + } + // Sanity check if (this.san.value > this.san.max) { updates[`system.san.value`] = this.san.max @@ -165,6 +183,10 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData } } + isStunned() { + return this.hp.stunned + } + isLowWP() { return this.wp.value <= 2 } @@ -207,6 +229,32 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData * @returns {Promise} - A promise that resolves to null if the roll is cancelled. */ async roll(rollType, rollItem) { + + if (this.hp.dead ) { + // Warn with chat message + ChatMessage.create({ + content: `

${game.i18n.format("CTHULHUETERNAL.Label.deadWarning", {con: this.characteristics.con.value} )}

`, + speaker: ChatMessage.getSpeaker({ actor: this.parent }) + }) + return null + } + if (this.hp.unconscious ) { + // Warn with chat message + ChatMessage.create({ + content: `

${game.i18n.localize("CTHULHUETERNAL.Label.unconsciousWarning")}

`, + speaker: ChatMessage.getSpeaker({ actor: this.parent }) + }) + return null + } + if (this.hp.stunned && rollType === "skill") { + // Warn with chat message + ChatMessage.create({ + content: `

${game.i18n.localize("CTHULHUETERNAL.Label.stunnedWarning")}

`, + speaker: ChatMessage.getSpeaker({ actor: this.parent }) + }) + return null + } + let opponentTarget const hasTarget = opponentTarget !== undefined diff --git a/module/models/skill.mjs b/module/models/skill.mjs index 428b79b..08e5d84 100644 --- a/module/models/skill.mjs +++ b/module/models/skill.mjs @@ -15,6 +15,8 @@ export default class CthulhuEternalSkill extends foundry.abstract.TypeDataModel schema.diceEvolved = new fields.BooleanField({ required: true, initial: true }) schema.rollFailed = new fields.BooleanField({ required: true, initial: false }) schema.isAdversary = new fields.BooleanField({ required: true, initial: false }) + schema.isHealing = new fields.BooleanField({ required: true, initial: false }) + schema.healingFormula = new fields.StringField({ required: true, initial: "1d4" }) return schema } @@ -36,11 +38,11 @@ export default class CthulhuEternalSkill extends foundry.abstract.TypeDataModel return `${this.base} + ${ String(this.bonus)}`; } - // Split the base value per stat : + // Split the base value per stat : let base = this.base.toLowerCase(); let char = actor.system.characteristics[base]; if (!char) { - ui.notifications.error(`The characteristic ${base} is wrong for actor ${actor.name}`); + ui.notifications.error(`The characteristic ${base} is wrong for actor ${actor.name}`); return `${this.base } + ${ String(this.bonus)}`; } let charValue = char.value; diff --git a/module/models/weapon.mjs b/module/models/weapon.mjs index e000b5a..a6709a6 100644 --- a/module/models/weapon.mjs +++ b/module/models/weapon.mjs @@ -25,6 +25,10 @@ export default class CthulhuEternalWeapon extends foundry.abstract.TypeDataModel schema.armorPiercing = new fields.NumberField({ required: true, initial: 0, min: 0 }) schema.weaponSubtype = new fields.StringField({ required: true, initial: "basicfirearm", choices: SYSTEM.WEAPON_SUBTYPE }) schema.state = new fields.StringField({ required: true, initial: "pristine", choices: SYSTEM.EQUIPMENT_STATES }) + schema.ammo = new fields.SchemaField({ + value: new fields.NumberField({ ...requiredInteger, initial: 6, min: 0 }), + max: new fields.NumberField({ ...requiredInteger, initial: 6, min: 0 }) + }) schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 }) @@ -37,4 +41,12 @@ export default class CthulhuEternalWeapon extends foundry.abstract.TypeDataModel get weaponCategory() { return game.i18n.localize(CATEGORY[this.category].label) } + + isRanged() { + return this.weaponType.includes("ranged") + } + + isFireArm() { + return this.weaponType === "rangedfirearm" + } } diff --git a/module/utils.mjs b/module/utils.mjs index 0ae23cc..444608e 100644 --- a/module/utils.mjs +++ b/module/utils.mjs @@ -180,6 +180,30 @@ export default class CthulhuEternalUtils { }); } + static async healingRoll(rollMessage) { + let rollData = rollMessage.rolls[0]?.options?.rollData + let healingFormula = rollData.rollItem.system.healingFormula + let healingMsg = "CTHULHUETERNAL.Label.healingRoll" + if (rollData.resultType === "successCritical") { + healingFormula += " * 2" + } + if (rollData.resultType === "failureCritical") { + healingMsg = "CTHULHUETERNAL.Label.healingRollFailure" + } + // Now display the result in chat message + let roll = new Roll(healingFormula) + await roll.evaluate() + roll.toMessage({ + speaker: ChatMessage.getSpeaker({ actor: rollData.actorId }), + flavor: `${game.i18n.localize(healingMsg)} : ${roll.total}`, + rolls: [roll], + options: { + rollData: rollData, + resultType: rollData.resultType + } + }) + } + static async damageRoll(rollMessage) { let rollData = rollMessage.rolls[0]?.options?.rollData let actor = game.actors.get(rollData.actorId) @@ -187,7 +211,9 @@ export default class CthulhuEternalUtils { ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Label.noActorFound")) return } + console.log("Damage roll data", rollData) rollData.weapon.resultType = rollData.resultType // Keep the result type from the roll message + rollData.weapon.selectiveFireChoice = rollData.selectiveFireChoice // Keep the selected fire choice from the roll message actor.system.roll("damage", rollData.weapon) } diff --git a/packs-system/rituals/000083.log b/packs-system/rituals/000132.log similarity index 100% rename from packs-system/rituals/000083.log rename to packs-system/rituals/000132.log diff --git a/packs-system/rituals/CURRENT b/packs-system/rituals/CURRENT index 635f1ad..d5731e9 100644 --- a/packs-system/rituals/CURRENT +++ b/packs-system/rituals/CURRENT @@ -1 +1 @@ -MANIFEST-000081 +MANIFEST-000131 diff --git a/packs-system/rituals/LOG b/packs-system/rituals/LOG index 585200c..6dc438c 100644 --- a/packs-system/rituals/LOG +++ b/packs-system/rituals/LOG @@ -1,7 +1,3 @@ -2025/06/12-21:40:36.466688 7f13a0ff96c0 Recovering log #79 -2025/06/12-21:40:36.523036 7f13a0ff96c0 Delete type=3 #77 -2025/06/12-21:40:36.523080 7f13a0ff96c0 Delete type=0 #79 -2025/06/12-22:19:34.910570 7f139fbff6c0 Level-0 table #84: started -2025/06/12-22:19:34.910598 7f139fbff6c0 Level-0 table #84: 0 bytes OK -2025/06/12-22:19:34.968716 7f139fbff6c0 Delete type=0 #82 -2025/06/12-22:19:35.027464 7f139fbff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) +2025/06/14-23:45:33.918294 7f78d8df86c0 Recovering log #129 +2025/06/14-23:45:34.040033 7f78d8df86c0 Delete type=3 #127 +2025/06/14-23:45:34.040084 7f78d8df86c0 Delete type=0 #129 diff --git a/packs-system/rituals/LOG.old b/packs-system/rituals/LOG.old index bcc655e..383bb1a 100644 --- a/packs-system/rituals/LOG.old +++ b/packs-system/rituals/LOG.old @@ -1,7 +1,7 @@ -2025/06/12-20:37:22.833913 7f13a0ff96c0 Recovering log #75 -2025/06/12-20:37:22.843981 7f13a0ff96c0 Delete type=3 #73 -2025/06/12-20:37:22.844063 7f13a0ff96c0 Delete type=0 #75 -2025/06/12-20:52:48.559109 7f139fbff6c0 Level-0 table #80: started -2025/06/12-20:52:48.559156 7f139fbff6c0 Level-0 table #80: 0 bytes OK -2025/06/12-20:52:48.723881 7f139fbff6c0 Delete type=0 #78 -2025/06/12-20:52:48.724064 7f139fbff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) +2025/06/14-13:49:17.890351 7f78d8df86c0 Recovering log #125 +2025/06/14-13:49:17.899990 7f78d8df86c0 Delete type=3 #123 +2025/06/14-13:49:17.900040 7f78d8df86c0 Delete type=0 #125 +2025/06/14-16:21:28.823932 7f78d37fe6c0 Level-0 table #130: started +2025/06/14-16:21:28.823960 7f78d37fe6c0 Level-0 table #130: 0 bytes OK +2025/06/14-16:21:28.831212 7f78d37fe6c0 Delete type=0 #128 +2025/06/14-16:21:28.848927 7f78d37fe6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) diff --git a/packs-system/rituals/MANIFEST-000081 b/packs-system/rituals/MANIFEST-000131 similarity index 75% rename from packs-system/rituals/MANIFEST-000081 rename to packs-system/rituals/MANIFEST-000131 index 59909fd..d76a4e8 100644 Binary files a/packs-system/rituals/MANIFEST-000081 and b/packs-system/rituals/MANIFEST-000131 differ diff --git a/packs-system/skills/000244.ldb b/packs-system/skills/000277.ldb similarity index 75% rename from packs-system/skills/000244.ldb rename to packs-system/skills/000277.ldb index 72a5b62..d05b856 100644 Binary files a/packs-system/skills/000244.ldb and b/packs-system/skills/000277.ldb differ diff --git a/packs-system/skills/000251.log b/packs-system/skills/000301.log similarity index 100% rename from packs-system/skills/000251.log rename to packs-system/skills/000301.log diff --git a/packs-system/skills/CURRENT b/packs-system/skills/CURRENT index 7ad1797..16abe4a 100644 --- a/packs-system/skills/CURRENT +++ b/packs-system/skills/CURRENT @@ -1 +1 @@ -MANIFEST-000249 +MANIFEST-000300 diff --git a/packs-system/skills/LOG b/packs-system/skills/LOG index d64bf9a..3318fbd 100644 --- a/packs-system/skills/LOG +++ b/packs-system/skills/LOG @@ -1,7 +1,3 @@ -2025/06/12-21:40:36.410156 7f13a17fa6c0 Recovering log #247 -2025/06/12-21:40:36.461712 7f13a17fa6c0 Delete type=3 #245 -2025/06/12-21:40:36.461765 7f13a17fa6c0 Delete type=0 #247 -2025/06/12-22:19:34.795093 7f139fbff6c0 Level-0 table #252: started -2025/06/12-22:19:34.795129 7f139fbff6c0 Level-0 table #252: 0 bytes OK -2025/06/12-22:19:34.852214 7f139fbff6c0 Delete type=0 #250 -2025/06/12-22:19:35.027439 7f139fbff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) +2025/06/14-23:45:33.811724 7f78d9dfa6c0 Recovering log #298 +2025/06/14-23:45:33.914052 7f78d9dfa6c0 Delete type=3 #296 +2025/06/14-23:45:33.914134 7f78d9dfa6c0 Delete type=0 #298 diff --git a/packs-system/skills/LOG.old b/packs-system/skills/LOG.old index 3c47fd4..a335865 100644 --- a/packs-system/skills/LOG.old +++ b/packs-system/skills/LOG.old @@ -1,7 +1,7 @@ -2025/06/12-20:37:22.815373 7f13a1ffb6c0 Recovering log #242 -2025/06/12-20:37:22.826434 7f13a1ffb6c0 Delete type=3 #240 -2025/06/12-20:37:22.826479 7f13a1ffb6c0 Delete type=0 #242 -2025/06/12-20:52:48.502299 7f139fbff6c0 Level-0 table #248: started -2025/06/12-20:52:48.502341 7f139fbff6c0 Level-0 table #248: 0 bytes OK -2025/06/12-20:52:48.558859 7f139fbff6c0 Delete type=0 #246 -2025/06/12-20:52:48.724054 7f139fbff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) +2025/06/14-13:49:17.875545 7f78d95f96c0 Recovering log #294 +2025/06/14-13:49:17.886122 7f78d95f96c0 Delete type=3 #292 +2025/06/14-13:49:17.886173 7f78d95f96c0 Delete type=0 #294 +2025/06/14-16:21:28.817422 7f78d37fe6c0 Level-0 table #299: started +2025/06/14-16:21:28.817477 7f78d37fe6c0 Level-0 table #299: 0 bytes OK +2025/06/14-16:21:28.823801 7f78d37fe6c0 Delete type=0 #297 +2025/06/14-16:21:28.848912 7f78d37fe6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) diff --git a/packs-system/skills/MANIFEST-000249 b/packs-system/skills/MANIFEST-000249 deleted file mode 100644 index d156317..0000000 Binary files a/packs-system/skills/MANIFEST-000249 and /dev/null differ diff --git a/packs-system/skills/MANIFEST-000300 b/packs-system/skills/MANIFEST-000300 new file mode 100644 index 0000000..86c4df1 Binary files /dev/null and b/packs-system/skills/MANIFEST-000300 differ diff --git a/styles/chat.less b/styles/chat.less index 3a378c4..17cc837 100644 --- a/styles/chat.less +++ b/styles/chat.less @@ -5,4 +5,4 @@ justify-content: center; font-family: var(--font-secondary); font-size: calc(var(--font-size-standard) * 1.1); -} \ No newline at end of file +} diff --git a/styles/global.less b/styles/global.less index a0446ab..86d1e7f 100644 --- a/styles/global.less +++ b/styles/global.less @@ -85,3 +85,26 @@ i.fvtt-cthulhu-eternal { background-position: 0%; background-size: 100% 100%; } + +.chat-lethal-damage { + ul { + list-style-type: none; + padding: 0; + margin: 0; + justify-content: center; + align-items: center; + .result-lethal { + color: var(--color-critical-failure); + font-family: var(--font-title); + } + .result-non-lethal { + color: var(--color-failure); + font-family: var(--font-title); + } + li { + margin: 0 10px; + font-family: var(--font-primary); + font-size: calc(var(--font-size-standard) * 1.02); + } + } +} diff --git a/styles/mixins.less b/styles/mixins.less index 361b06f..6667d6d 100644 --- a/styles/mixins.less +++ b/styles/mixins.less @@ -5,10 +5,11 @@ background-image: var(--background-image-base); background-repeat: no-repeat; background-size: 100% 100%; + --input-height: 1.4rem; .sheet-tabs { a { - color: rgba(32, 31, 31, 0.8); + color: rgba(32, 31, 31, 0.8); } } @@ -62,7 +63,7 @@ legend { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.1); font-weight: bold; letter-spacing: 1px; } @@ -73,6 +74,38 @@ font-family: var(--font-secondary); font-size: calc(var(--font-size-standard) * 1); } + .hp-unconscious { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); + color: #b4710c; + } + .hp-dead { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); + color: #b40000; + } + .protagonist-luck { + display: flex; + min-width: 8rem; + max-width: 8rem; + .rollable:hover, + .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; + font-size: 0.9rem; + } + } + .damage-bonus { + display: flex; + label { + max-width: 5rem; + min-width: 5rem; + } + input { + max-width: 2rem; + min-width: 2rem; + } + } } .vehicle-sheet-common { @@ -90,7 +123,6 @@ } .item-sheet-common { - .form-fields { padding-top: 4px; } diff --git a/styles/protagonist.less b/styles/protagonist.less index 4eb955a..9d6bdaa 100644 --- a/styles/protagonist.less +++ b/styles/protagonist.less @@ -42,9 +42,6 @@ width: 2rem; margin-left: 4px; } - .damage-bonus { - font-size: calc(var(--font-size-standard) * 0.8); - } .hp-separator { font-size: calc(var(--font-size-standard) * 1.2); display: flex; diff --git a/styles/roll.less b/styles/roll.less index 3a6890c..f63debf 100644 --- a/styles/roll.less +++ b/styles/roll.less @@ -98,6 +98,11 @@ margin-left: 2rem; display: none; } + .healing-roll { + font-size: calc(var(--font-size-standard) * 1.0); + margin-left: 2rem; + display: none; + } .roll-damage { font-size: calc(var(--font-size-standard) * 1.0); margin-left: 2rem; diff --git a/templates/chat-lethal-damage.hbs b/templates/chat-lethal-damage.hbs new file mode 100644 index 0000000..51620c9 --- /dev/null +++ b/templates/chat-lethal-damage.hbs @@ -0,0 +1,31 @@ +
+
+
    +
  • {{weapon.name}} : {{localize "CTHULHUETERNAL.Label.lethalityRoll"}}
  • +
  • {{localize "CTHULHUETERNAL.Label.result"}} :{{rollResult}} ({{lethalScore}})
  • + + + {{#if weapon.system.selectiveFireChoice}} +
  • {{weapon.system.selectiveFireChoiceLabel}}
  • + {{/if}} + {{#if weapon.system.killRadius}} +
  • {{localize "CTHULHUETERNAL.Label.killRadius"}} : {{weapon.system.killRadius}} {{weapon.system.rangeUnit}}
  • +
  • {{localize "CTHULHUETERNAL.Label.killRadiusInfo"}}
  • + {{/if}} + + {{#if ammoUsed}} +
  • {{localize "CTHULHUETERNAL.Label.ammoUsed"}}: {{ammoUsed}} / {{weapon.system.ammo.value}}
  • + {{/if}} + + {{#if isLethal}} +
  • {{localize "CTHULHUETERNAL.Label.lethalityLethal"}}
  • +
  • {{localize "CTHULHUETERNAL.Label.lethalityWounded"}}
  • + {{else}} +
  • {{localize "CTHULHUETERNAL.Label.lethalityNotLethal"}}
  • +
  • {{localize "CTHULHUETERNAL.Label.lethalityNotWounded"}}: {{wounds}}
  • + {{/if}} + +
+ +
+
\ No newline at end of file diff --git a/templates/chat-message.hbs b/templates/chat-message.hbs index 598ed21..369718f 100644 --- a/templates/chat-message.hbs +++ b/templates/chat-message.hbs @@ -51,30 +51,54 @@ {{#if isCritical}}
  • {{localize "CTHULHUETERNAL.Label.criticalSuccess"}} {{#if (eq rollType "weapon")}} - + {{#if (eq weapon.system.weaponType "rangedfirearm")}} + + {{else}} + + {{/if}} {{/if}} + {{#if (eq rollType "skill") }} + {{#if rollItem.system.isHealing}} + + {{/if}} + {{/if}} +
  • {{else}}
  • {{localize "CTHULHUETERNAL.Label.success"}} {{#if isNudge}} - + {{/if}} - {{#if (eq rollType "weapon")}} - + {{#if (eq weapon.system.weaponType "rangedfirearm")}} + + {{else}} + + {{/if}} + {{#if (eq rollType "skill") }} + {{#if rollItem.system.isHealing}} + + {{/if}} {{/if}}
  • {{/if}} + {{/if}} {{#if isFailure}} {{#if isCritical}} -
  • {{localize "CTHULHUETERNAL.Label.criticalFailure"}}
  • +
  • {{localize "CTHULHUETERNAL.Label.criticalFailure"}} + {{#if (eq rollType "skill") }} + {{#if rollItem.system.isHealing}} + + {{/if}} + {{/if}} +
  • {{else}}
  • {{localize "CTHULHUETERNAL.Label.failure"}} {{#if isNudge}} - + {{/if}}
  • {{/if}} diff --git a/templates/chat-regular-damage.hbs b/templates/chat-regular-damage.hbs new file mode 100644 index 0000000..354c17e --- /dev/null +++ b/templates/chat-regular-damage.hbs @@ -0,0 +1,20 @@ +
    +
    +
      +
    • {{weapon.name}} : {{localize "CTHULHUETERNAL.Label.damageRoll"}}
    • +
    • {{localize "CTHULHUETERNAL.Label.result"}} :{{rollResult}} ({{formula}})
    • + + {{#if weapon.system.killRadius}} +
    • {{localize "CTHULHUETERNAL.Label.killRadius"}} : {{weapon.system.killRadius}} {{weapon.system.rangeUnit}}
    • +
    • {{localize "CTHULHUETERNAL.Label.killRadiusInfo"}}
    • + {{/if}} + + {{#if ammoUsed}} +
    • {{localize "CTHULHUETERNAL.Label.ammoUsed"}}: {{ammoUsed}} / {{weapon.system.ammo.value}}
    • + {{/if}} +
    • {{localize "CTHULHUETERNAL.Label.damageMessage"}}: {{rollResult}}
    • + +
    + +
    +
    \ No newline at end of file diff --git a/templates/protagonist-main.hbs b/templates/protagonist-main.hbs index fbde7d5..f12eade 100644 --- a/templates/protagonist-main.hbs +++ b/templates/protagonist-main.hbs @@ -10,14 +10,20 @@ data-tooltip="{{actor.name}}" />
    - {{localize "CTHULHUETERNAL.Label.HP"}} + {{#if system.hp.dead}} + {{localize "CTHULHUETERNAL.Label.HP"}} {{localize "CTHULHUETERNAL.Label.dying"}} + {{else}} + {{#if system.hp.unconscious}} + {{localize "CTHULHUETERNAL.Label.HP"}} {{localize "CTHULHUETERNAL.Label.unconscious"}} + {{else}} + {{localize "CTHULHUETERNAL.Label.HP"}} + {{/if}} + {{/if}}
    {{formField systemFields.hp.fields.value value=system.hp.value}} / {{formField systemFields.hp.fields.max value=system.hp.max rootId=partId disabled=true}} -
    -
    - {{formField systemFields.damageBonus value=system.damageBonus classes="damage-bonus"}} + {{formField systemFields.hp.fields.stunned value=system.hp.stunned classes="stunned"}}
    @@ -158,6 +164,17 @@ rootId=partId disabled=isPlayMode }} + +
    + + +
    +
    + {{formField systemFields.damageBonus value=system.damageBonus tooltip="Etourdi" }} +
    + \ No newline at end of file diff --git a/templates/skill.hbs b/templates/skill.hbs index a009f6b..e2b9153 100644 --- a/templates/skill.hbs +++ b/templates/skill.hbs @@ -14,6 +14,10 @@ {{system.skillTotal}} {{#if isGM}} + {{formField systemFields.isHealing value=system.isHealing}} + {{#if system.isHealing}} + {{formField systemFields.healingFormula value=system.healingFormula}} + {{/if}} {{formField systemFields.isAdversary value=system.isAdversary }} {{formField systemFields.diceEvolved value=system.diceEvolved}} @@ -21,6 +25,10 @@ {{formField systemFields.rollFailed value=system.rollFailed}} {{/if}} {{else}} + {{formField systemFields.isHealing value=system.isHealing disabled=true}} + {{#if system.isHealing}} + {{formField systemFields.healingFormula value=system.healingFormula disabled=true}} + {{/if}} {{formField systemFields.isAdversary value=system.isAdversary disabled=true}} {{formField systemFields.diceEvolved value=system.diceEvolved disabled=true}} diff --git a/templates/weapon.hbs b/templates/weapon.hbs index ad1a5d9..100fc62 100644 --- a/templates/weapon.hbs +++ b/templates/weapon.hbs @@ -8,7 +8,7 @@ {{formField systemFields.settings value=system.settings localize=true}} {{formField systemFields.weaponType value=system.weaponType localize=true}} {{#if (eq system.weaponType "rangedfirearm")}} - {{formField systemFields.weaponSubtype value=system.weaponSubtype localize=true}} + {{formField systemFields.weaponSubtype value=system.weaponSubtype localize=true}} {{/if}} {{formField systemFields.state value=system.state localize=true}} @@ -18,12 +18,20 @@ {{formField systemFields.directSkillValue value=system.directSkillValue }} {{/if}} - {{formField systemFields.hasSelectiveFire value=system.hasSelectiveFire}} {{formField systemFields.applyDamageBonus value=system.applyDamageBonus}} {{formField systemFields.damage value=system.damage}} - {{formField systemFields.baseRange value=system.baseRange}} - {{formField systemFields.rangeUnit value=system.rangeUnit localize=true}} + {{#if isRanged}} + {{formField systemFields.baseRange value=system.baseRange}} + {{formField systemFields.rangeUnit value=system.rangeUnit localize=true}} + {{/if}} + + {{#if isFireArm}} + {{formField systemFields.hasSelectiveFire value=system.hasSelectiveFire}} + {{formField systemFields.ammo.fields.value value=system.ammo.value}} + {{formField systemFields.ammo.fields.max value=system.ammo.max}} + {{/if}} + {{formField systemFields.lethality value=system.lethality}} {{formField systemFields.killRadius value=system.killRadius}}