diff --git a/assets/icons/icon_combat.svg b/assets/icons/icon_combat.svg new file mode 100644 index 0000000..fc0bc21 --- /dev/null +++ b/assets/icons/icon_combat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/icon_knowledge.svg b/assets/icons/icon_knowledge.svg new file mode 100644 index 0000000..a278842 --- /dev/null +++ b/assets/icons/icon_knowledge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/icon_physical.svg b/assets/icons/icon_physical.svg new file mode 100644 index 0000000..7e02018 --- /dev/null +++ b/assets/icons/icon_physical.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/icon_social.svg b/assets/icons/icon_social.svg new file mode 100644 index 0000000..6798fc6 --- /dev/null +++ b/assets/icons/icon_social.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/icon_stealth.svg b/assets/icons/icon_stealth.svg new file mode 100644 index 0000000..752f18a --- /dev/null +++ b/assets/icons/icon_stealth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/icon_technology.svg b/assets/icons/icon_technology.svg new file mode 100644 index 0000000..6d215c6 --- /dev/null +++ b/assets/icons/icon_technology.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/icon_vehicles.svg b/assets/icons/icon_vehicles.svg new file mode 100644 index 0000000..b241ea9 --- /dev/null +++ b/assets/icons/icon_vehicles.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/css/fvtt-ftl-nomad.css b/css/fvtt-ftl-nomad.css index c17a149..eb1016c 100644 --- a/css/fvtt-ftl-nomad.css +++ b/css/fvtt-ftl-nomad.css @@ -197,11 +197,9 @@ i.fvtt-ftl-nomad { } .fvtt-ftl-nomad .character-main .character-pc .character-left .character-hp input { flex: none; - width: 2rem; - margin-left: 4px; -} -.fvtt-ftl-nomad .character-main .character-pc .character-left .character-hp .damage-bonus { - font-size: calc(var(--font-size-standard) * 0.8); + width: 2.5rem; + margin-left: 2px; + margin-right: 4px; } .fvtt-ftl-nomad .character-main .character-pc .character-left .character-hp .hp-separator { font-size: calc(var(--font-size-standard) * 1.2); @@ -227,6 +225,17 @@ i.fvtt-ftl-nomad { flex-direction: column; gap: 5px; } +.fvtt-ftl-nomad .character-main .character-pc .character-right .character-spec label { + max-width: 6rem; +} +.fvtt-ftl-nomad .character-main .character-pc .character-right .character-spec .hero-armor { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; +} +.fvtt-ftl-nomad .character-main .character-pc .character-right .character-spec .hero-armor input { + max-width: 3rem; +} .fvtt-ftl-nomad .character-main .character-pc .character-right .character-name { display: flex; } @@ -235,85 +244,6 @@ i.fvtt-ftl-nomad { font-size: var(--font-size-title); width: 400px; } -.fvtt-ftl-nomad .character-main .character-pc .character-right .san { - align-content: flex-start; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san input { - min-width: 2.2rem; - max-width: 2.2rem; - margin-bottom: 4px; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san select { - min-width: 6rem; - max-width: 6rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .rollable:hover, -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; - font-size: 0.9rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .button { - min-width: 4rem; - max-width: 4rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .san-checkbox { - min-width: 1rem; - max-width: 1rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .label-short-field { - font-size: 0.9rem; - max-width: 3rem; - min-width: 3rem; - flex-grow: 1; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .label-recovery { - margin-left: 4px; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .label-field { - font-size: 0.9rem; - max-width: 6rem; - min-width: 6rem; - flex-grow: 1; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .label-bp { - flex-grow: 1; - max-width: 3rem; - min-width: 3rem; - margin-left: 4px; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .label-insanity { - flex-grow: 1; - margin-left: 4px; - max-width: 8rem; - min-width: 8rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .spacing { - margin-left: 4px; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .san .d100 { - flex: 0; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .willpower input { - min-width: 2.4rem; - max-width: 2.4rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .willpower input[type="checkbox"] { - min-width: 1rem; - max-width: 1rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .willpower .label-field { - flex-grow: 1; - margin-left: 4px; - max-width: 5rem; - min-width: 5rem; - font-size: 0.9rem; -} -.fvtt-ftl-nomad .character-main .character-pc .character-right .willpower .checkbox { - flex-grow: 0; - min-width: 1rem; - max-width: 1rem; -} .fvtt-ftl-nomad .character-main .character-pc .character-right label { min-width: 120px; } @@ -334,6 +264,11 @@ i.fvtt-ftl-nomad { display: flex; align-items: center; } +.fvtt-ftl-nomad .character-main .character-skills .character-skill .icon-skill { + width: 24px; + height: 24px; + margin-right: 4px; +} .fvtt-ftl-nomad .character-main .character-skills .character-skill .rollable:hover, .fvtt-ftl-nomad .character-main .character-skills .character-skill .rollable:focus { text-shadow: 0 0 8px var(--color-shadow-primary); @@ -377,13 +312,24 @@ i.fvtt-ftl-nomad { .fvtt-ftl-nomad .character-biography .field-label { margin-left: 8px; } -.fvtt-ftl-nomad .character-biography .adapted { +.fvtt-ftl-nomad .character-biography .rank { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 8px; +} +.fvtt-ftl-nomad .character-biography .rank label { + min-width: 6rem; +} +.fvtt-ftl-nomad .character-biography .rank input { + max-width: 4rem; +} +.fvtt-ftl-nomad .character-biography .biodata { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; } -.fvtt-ftl-nomad .character-biography .adapted label { - min-width: 20rem; +.fvtt-ftl-nomad .character-biography .biodata label { + min-width: 12rem; } .fvtt-ftl-nomad .character-biography .resources { display: grid; @@ -581,6 +527,120 @@ i.fvtt-ftl-nomad { height: 24px; margin: 4px 0 0 0; } +.fvtt-ftl-nomad .tab.character-talents { + background-color: var(--color-light-1); + display: grid; + grid-template-columns: 1fr; +} +.fvtt-ftl-nomad .tab.character-talents legend a { + font-size: calc(var(--font-size-standard) * 1.4); + padding-left: 5px; +} +.fvtt-ftl-nomad .tab.character-talents .talents { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; +} +.fvtt-ftl-nomad .tab.character-talents .talents .talent { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; +} +.fvtt-ftl-nomad .tab.character-talents .talents .talent .rollable:hover, +.fvtt-ftl-nomad .tab.character-talents .talents .talent .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.character-talents .talents .talent .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; +} +.fvtt-ftl-nomad .tab.character-talents .talents .talent .damage { + min-width: 6rem; + max-width: 6rem; +} +.fvtt-ftl-nomad .tab.character-talents .talents .talent .name { + min-width: 10rem; + max-width: 10rem; +} +.fvtt-ftl-nomad .tab.character-talents .talents .talent .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; +} +.fvtt-ftl-nomad .tab.character-talents .languages { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; +} +.fvtt-ftl-nomad .tab.character-talents .languages .language { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; +} +.fvtt-ftl-nomad .tab.character-talents .languages .language .rollable:hover, +.fvtt-ftl-nomad .tab.character-talents .languages .language .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.character-talents .languages .language .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; +} +.fvtt-ftl-nomad .tab.character-talents .languages .language .damage { + min-width: 6rem; + max-width: 6rem; +} +.fvtt-ftl-nomad .tab.character-talents .languages .language .name { + min-width: 10rem; + max-width: 10rem; +} +.fvtt-ftl-nomad .tab.character-talents .languages .language .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; +} +.fvtt-ftl-nomad .tab.character-talents .psionics { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; +} +.fvtt-ftl-nomad .tab.character-talents .psionics .psionic { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; +} +.fvtt-ftl-nomad .tab.character-talents .psionics .psionic .rollable:hover, +.fvtt-ftl-nomad .tab.character-talents .psionics .psionic .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.character-talents .psionics .psionic .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; +} +.fvtt-ftl-nomad .tab.character-talents .psionics .psionic .damage { + min-width: 6rem; + max-width: 6rem; +} +.fvtt-ftl-nomad .tab.character-talents .psionics .psionic .name { + min-width: 10rem; + max-width: 10rem; +} +.fvtt-ftl-nomad .tab.character-talents .psionics .psionic .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; +} .fvtt-ftl-nomad .tab.character-equipment { background-color: var(--color-light-1); display: grid; @@ -590,6 +650,53 @@ i.fvtt-ftl-nomad { font-size: calc(var(--font-size-standard) * 1.4); padding-left: 5px; } +.fvtt-ftl-nomad .tab.character-equipment .encumbrance { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 4px; +} +.fvtt-ftl-nomad .tab.character-equipment .encumbrance input { + max-width: 4rem; +} +.fvtt-ftl-nomad .tab.character-equipment .encumbrance .encumbered { + color: red; + font-weight: bold; +} +.fvtt-ftl-nomad .tab.character-equipment .implants { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; +} +.fvtt-ftl-nomad .tab.character-equipment .implants .implant { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; +} +.fvtt-ftl-nomad .tab.character-equipment .implants .implant .rollable:hover, +.fvtt-ftl-nomad .tab.character-equipment .implants .implant .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; +} +.fvtt-ftl-nomad .tab.character-equipment .implants .implant .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; +} +.fvtt-ftl-nomad .tab.character-equipment .implants .implant .damage { + min-width: 6rem; + max-width: 6rem; +} +.fvtt-ftl-nomad .tab.character-equipment .implants .implant .name { + min-width: 10rem; + max-width: 10rem; +} +.fvtt-ftl-nomad .tab.character-equipment .implants .implant .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; +} .fvtt-ftl-nomad .tab.character-equipment .weapons { display: grid; grid-template-columns: repeat(2, 1fr); @@ -627,7 +734,7 @@ i.fvtt-ftl-nomad { } .fvtt-ftl-nomad .tab.character-equipment .armors { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(2, 1fr); gap: 4px; } .fvtt-ftl-nomad .tab.character-equipment .armors .armor { @@ -637,118 +744,51 @@ i.fvtt-ftl-nomad { min-width: 13rem; max-width: 13rem; } -.fvtt-ftl-nomad .tab.character-equipment .armors .armor .rollable:hover, -.fvtt-ftl-nomad .tab.character-equipment .armors .armor .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; -} .fvtt-ftl-nomad .tab.character-equipment .armors .armor .controls { font-size: 0.7rem; min-width: 1.8rem; max-width: 1.8rem; } .fvtt-ftl-nomad .tab.character-equipment .armors .armor .protection { - min-width: 5rem; - max-width: 5rem; + min-width: 6rem; + max-width: 6rem; } .fvtt-ftl-nomad .tab.character-equipment .armors .armor .name { - min-width: 8rem; - max-width: 8rem; + min-width: 10rem; + max-width: 10rem; } .fvtt-ftl-nomad .tab.character-equipment .armors .armor .item-img { width: 24px; height: 24px; margin: 4px 0 0 0; } -.fvtt-ftl-nomad .tab.character-equipment .gears { +.fvtt-ftl-nomad .tab.character-equipment .equipments { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; } -.fvtt-ftl-nomad .tab.character-equipment .gears .gear { +.fvtt-ftl-nomad .tab.character-equipment .equipments .equipment { display: flex; align-items: center; gap: 4px; min-width: 13rem; max-width: 13rem; } -.fvtt-ftl-nomad .tab.character-equipment .gears .gear .rollable:hover, -.fvtt-ftl-nomad .tab.character-equipment .gears .gear .rollable:focus { +.fvtt-ftl-nomad .tab.character-equipment .equipments .equipment .rollable:hover, +.fvtt-ftl-nomad .tab.character-equipment .equipments .equipment .rollable:focus { text-shadow: 0 0 8px var(--color-shadow-primary); cursor: pointer; } -.fvtt-ftl-nomad .tab.character-equipment .gears .gear .controls { +.fvtt-ftl-nomad .tab.character-equipment .equipments .equipment .controls { font-size: 0.7rem; min-width: 1.8rem; max-width: 1.8rem; } -.fvtt-ftl-nomad .tab.character-equipment .gears .gear .name { +.fvtt-ftl-nomad .tab.character-equipment .equipments .equipment .name { min-width: 10rem; max-width: 10rem; } -.fvtt-ftl-nomad .tab.character-equipment .gears .gear .item-img { - width: 24px; - height: 24px; - margin: 4px 0 0 0; -} -.fvtt-ftl-nomad .tab.character-equipment .rituals { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 4px; -} -.fvtt-ftl-nomad .tab.character-equipment .rituals .ritual { - display: flex; - align-items: center; - gap: 4px; - min-width: 20rem; - max-width: 20rem; -} -.fvtt-ftl-nomad .tab.character-equipment .rituals .ritual .rollable:hover, -.fvtt-ftl-nomad .tab.character-equipment .rituals .ritual .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; -} -.fvtt-ftl-nomad .tab.character-equipment .rituals .ritual .controls { - font-size: 0.7rem; - min-width: 1.8rem; - max-width: 1.8rem; -} -.fvtt-ftl-nomad .tab.character-equipment .rituals .ritual .name { - min-width: 17rem; - max-width: 17rem; -} -.fvtt-ftl-nomad .tab.character-equipment .rituals .ritual .item-img { - width: 24px; - height: 24px; - margin: 4px 0 0 0; -} -.fvtt-ftl-nomad .tab.character-equipment .tomes { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 4px; -} -.fvtt-ftl-nomad .tab.character-equipment .tomes .tome { - display: flex; - align-items: center; - gap: 4px; - min-width: 20rem; - max-width: 20rem; -} -.fvtt-ftl-nomad .tab.character-equipment .tomes .tome .rollable:hover, -.fvtt-ftl-nomad .tab.character-equipment .tomes .tome .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; -} -.fvtt-ftl-nomad .tab.character-equipment .tomes .tome .controls { - font-size: 0.7rem; - min-width: 1.8rem; - max-width: 1.8rem; -} -.fvtt-ftl-nomad .tab.character-equipment .tomes .tome .name { - min-width: 17rem; - max-width: 17rem; -} -.fvtt-ftl-nomad .tab.character-equipment .tomes .tome .item-img { +.fvtt-ftl-nomad .tab.character-equipment .equipments .equipment .item-img { width: 24px; height: 24px; margin: 4px 0 0 0; @@ -2687,7 +2727,7 @@ i.fvtt-ftl-nomad { border: none; background-color: rgba(0, 0, 0, 0.1); color: var(--color-dark-2); - width: 4rem; + width: 10rem; text-align: center; } .red-warning { diff --git a/lang/en.json b/lang/en.json index 91bb11b..e398348 100644 --- a/lang/en.json +++ b/lang/en.json @@ -21,6 +21,26 @@ }, "Character": { "FIELDS": { + "armor": { + "value": { + "label": "Protection" + } + }, + "heroPoints": { + "label": "Hero Points" + }, + "credits": { + "label": "Credits" + }, + "enc": { + "label": "Enc", + "value": { + "label": "Enc Curr." + }, + "max": { + "label": "Enc Max" + } + }, "age": { "label": "Age" }, @@ -51,9 +71,54 @@ "home": { "label": "Home" }, + "biodata": { + "label": "Biodata", + "gender": { + "label": "Gender" + }, + "height": { + "label": "Height" + }, + "weight": { + "label": "Weight" + }, + "age": { + "label": "Age" + }, + "hair": { + "label": "Hair" + }, + "eyes": { + "label": "Eyes" + }, + "home": { + "label": "Home" + }, + "birthplace": { + "label": "Birthplace" + } + }, + "rank": { + "label": "Rank", + "experienced": { + "label": "Experienced" + }, + "expert": { + "label": "Expert" + }, + "veteran": { + "label": "Veteran" + }, + "elite": { + "label": "Elite" + }, + "legend": { + "label": "Legend" + } + }, "health": { "staminaValue": { - "label": "Current" + "label": "Cur." }, "staminaMax": { "label": "Max" @@ -222,6 +287,11 @@ } }, "Label": { + "Easy": "Easy (+1D)", + "Moderate": "Moderate (+0D)", + "Difficult": "Difficult (-1D)", + "Formidable": "Formidable (-2D)", + "Impossible": "Impossible (-4D)", "combat": "Combat", "physical": "Physical", "social": "Social", @@ -243,7 +313,7 @@ "creature": "Creature", "criticalFailure": "Critical Failure", "criticalSuccess": "Critical Success", - "current": "Current", + "current": "Curr.", "damage": "Damage", "damageShort": "Dmg", "description": "Description", @@ -268,6 +338,7 @@ "status": "Status", "success": "Success", "talents": "Talents", + "implants": "Implants", "targetScore": "Target Score", "titleSkill": "Skill Roll", "titleWeapon": "Weapon Roll", @@ -299,7 +370,13 @@ "skill": "Skill" }, "Skill": { - "Athletics": "Athletics", + "Combat": "Combat", + "Knowledge": "Knowledge", + "Physical": "Physical", + "Social": "Social", + "Stealth": "Stealth", + "Technology": "Technology", + "Vehicles": "Vehicles", "FIELDS": { "base": { "label": "Base" @@ -367,7 +444,18 @@ "NoTech": "No Tech" }, "ToggleSheet": "Toggle Sheet", - "Tooltip": {}, + "Tooltip": { + "addTalent" : "Add Talent", + "addSkill" : "Add Skill", + "addWeapon" : "Add Weapon", + "addArmor" : "Add Armor", + "addEquipment" : "Add Equipment", + "addImplant" : "Add Implant", + "addLanguage" : "Add Language", + "addPsionic" : "Add Psionic", + "addCreatureAbility" : "Add Creature Ability", + "addCreatureTrait" : "Add Creature Trait" + }, "Vehicle": { "FIELDS": { "airSpeed": { @@ -423,9 +511,12 @@ }, "Range": { "Handgun": "Handgun", + "Assault": "Assault", "LongRange": "Long Range", "Melee": "Melee", - "Rifle": "Rifle" + "Rifle": "Rifle", + "HeavyWeapon": "Heavy Weapon", + "ThrownWeapon": "Thrown Weapon" }, "Types": { "Energy": "Energy", diff --git a/module/applications/sheets/base-actor-sheet.mjs b/module/applications/sheets/base-actor-sheet.mjs index c8ee550..986d643 100644 --- a/module/applications/sheets/base-actor-sheet.mjs +++ b/module/applications/sheets/base-actor-sheet.mjs @@ -66,6 +66,7 @@ export default class FTLNomadActorSheet extends HandlebarsApplicationMixin(found actor: this.document, system: this.document.system, source: this.document.toObject(), + isEncumbered: this.document.system.isEncumbered(), enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }), isEditMode: this.isEditMode, isPlayMode: this.isPlayMode, diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index e53bb21..5d05215 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -12,9 +12,14 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { contentClasses: ["character-content"], }, actions: { - createGear: FTLNomadCharacterSheet.#onCreateGear, + createEquipment: FTLNomadCharacterSheet.#onCreateEquipment, createArmor: FTLNomadCharacterSheet.#onCreateArmor, - createWeapon: FTLNomadCharacterSheet.#onCreateWeapon + createWeapon: FTLNomadCharacterSheet.#onCreateWeapon, + createTalent: FTLNomadCharacterSheet.#onCreateTalent, + createImplant: FTLNomadCharacterSheet.#onCreateImplant, + createPsionic: FTLNomadCharacterSheet.#onCreatePsionic, + createLanguage: FTLNomadCharacterSheet.#onCreateLanguage + }, } @@ -26,6 +31,9 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { tabs: { template: "templates/generic/tab-navigation.hbs", }, + talents: { + template: "systems/fvtt-ftl-nomad/templates/character-talents.hbs", + }, equipment: { template: "systems/fvtt-ftl-nomad/templates/character-equipment.hbs", }, @@ -36,7 +44,7 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { /** @override */ tabGroups = { - sheet: "main", + sheet: "talents", } /** @@ -45,6 +53,7 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { */ #getTabs() { const tabs = { + talents: { id: "talents", group: "sheet", icon: "fa-solid fa-compass", label: "FTLNOMAD.Label.talents" }, equipment: { id: "equipment", group: "sheet", icon: "fa-solid fa-shapes", label: "FTLNOMAD.Label.equipment" }, biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "FTLNOMAD.Label.biography" }, } @@ -62,7 +71,7 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true }) context.enrichedNotes = await TextEditor.enrichHTML(this.document.system.notes, { async: true }) - + return context } @@ -72,6 +81,17 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { switch (partId) { case "main": break + case "talents": + context.tab = context.tabs.talents + context.talents = doc.itemTypes.talent + context.talents.sort((a, b) => a.name.localeCompare(b.name)) + context.implants = doc.itemTypes.implant + context.implants.sort((a, b) => a.name.localeCompare(b.name)) + context.psionics = doc.itemTypes.psionic + context.psionics.sort((a, b) => a.name.localeCompare(b.name)) + context.languages = doc.itemTypes.language + context.languages.sort((a, b) => a.name.localeCompare(b.name)) + break case "equipment": context.tab = context.tabs.equipment context.weapons = doc.itemTypes.weapon @@ -90,8 +110,8 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { return context } - - static #onCreateGear(event, target) { + + static #onCreateEquipment(event, target) { this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("FTLNOMAD.Label.newGear"), type: "gear" }]) } @@ -103,6 +123,22 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("FTLNOMAD.Label.newArmor"), type: "armor" }]) } + static #onCreateTalent(event, target) { + this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("FTLNOMAD.Label.newTalent"), type: "talent" }]) + } + + static #onCreateImplant(event, target) { + this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("FTLNOMAD.Label.newImplant"), type: "implant" }]) + } + + static #onCreatePsionic(event, target) { + this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("FTLNOMAD.Label.newPsionic"), type: "psionic" }]) + } + + static #onCreateLanguage(event, target) { + this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("FTLNOMAD.Label.newLanguage"), type: "language" }]) + } + /** * Handles the roll action triggered by user interaction. @@ -122,35 +158,16 @@ export default class FTLNomadCharacterSheet extends FTLNomadActorSheet { const rollType = $(event.currentTarget).data("roll-type") let item let li - // Debug : console.log(">>>>", event, target, rollType) - // Deprecated : if (this.isEditMode) return switch (rollType) { - case "resource": - item = foundry.utils.duplicate(this.actor.system.resources) - item.name = game.i18n.localize(`FTLNOMAD.Label.Resources`) - item.targetScore = item.permanentRating - break - case "char": - let charId = $(event.currentTarget).data("char-id") - item = foundry.utils.duplicate(this.actor.system.characteristics[charId]) - item.name = game.i18n.localize(`FTLNOMAD.Label.${charId}Long`) - item.targetScore = item.value * 5 - break case "skill": - li = $(event.currentTarget).parents(".item"); - item = this.actor.items.get(li.data("item-id")); + let skillId = $(event.currentTarget).data("skill-id"); + item = this.actor.system.skills[skillId]; break case "weapon": case "damage": li = $(event.currentTarget).parents(".item"); item = this.actor.items.get(li.data("item-id")); - item.damageBonus = this.actor.system.damageBonus break - case "san": - item = foundry.utils.duplicate(this.actor.system.san) - item.name = game.i18n.localize("FTLNOMAD.Label.SAN") - item.targetScore = item.value - break; default: throw new Error(`Unknown roll type ${rollType}`) } diff --git a/module/config/system.mjs b/module/config/system.mjs index e1005fc..7f131cc 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -50,11 +50,26 @@ export const WEAPON_TYPES = { "grenade": { id: "grenade", label: "FTLNOMAD.Weapon.Types.Grenade" }, "vehicle": { id: "vehicle", label: "FTLNOMAD.Weapon.Types.Vehicle" } } + export const WEAPON_RANGE = { - "melee": { id: "melee", label: "FTLNOMAD.Weapon.Range.Melee" }, - "handgun": { id: "handgun", label: "FTLNOMAD.Weapon.Range.Handgun" }, - "rifle": { id: "rifle", label: "FTLNOMAD.Weapon.Range.Rifle" }, - "longrange": { id: "longrange", label: "FTLNOMAD.Weapon.Range.LongRange" } + "handgun": { id: "handgun", label: "FTLNOMAD.Weapon.Range.Handgun", range: {close: 0, near:0, far:-2} }, + "assault": { id: "assault", label: "FTLNOMAD.Weapon.Range.Assault", range: {close: -2, near:0, far:-1, distant: -2} }, + "rifle": { id: "rifle", label: "FTLNOMAD.Weapon.Range.Rifle", range: {close: -3, near:0, far:0, distant: -1} }, + "melee": { id: "melee", label: "FTLNOMAD.Weapon.Range.Melee", range: {close: 0} }, + "heavyweapon": { id: "heavyweapon", label: "FTLNOMAD.Weapon.Range.HeavyWeapon", range: {near:-1, far:0, distant: 0} }, + "thrownweapon": { id: "thrownweapon", label: "FTLNOMAD.Weapon.Range.ThrownWeapon", range: {close: 0, near:-1} } +} + +export const ATTACK_MODIFIERS = { + "two-attacks": -1, + "aiming": 1, + "dim": -1, + "darkness": -2, + "prone": -1, + "cover": -2, + "recoil-first": -1, + "recoil-third": -2, + "aware": -1 } export const TRIAGE_RESULTS = { @@ -98,12 +113,22 @@ export const CREATURE_SIZES = { "titanic": { id: "titanic", label: "FTLNOMAD.Creature.Size.Titanic" } } +export const MODIFIER_CHOICES = { + "easy": { id: "easy", label: "FTLNOMAD.Label.Easy", value :"1" }, + "moderate": { id: "moderate", label: "FTLNOMAD.Label.Moderate", value: "0" }, + "difficult": { id: "difficult", label: "FTLNOMAD.Label.Difficult", value: "-1" }, + "formidable": { id: "formidable", label: "FTLNOMAD.Label.Formidable", value: "-2" }, + "impossible": { id: "impossible", label: "FTLNOMAD.Label.Impossible", value: "-4" } +} + /** * Include all constant definitions within the SYSTEM global export * @type {Object} */ export const SYSTEM = { id: SYSTEM_ID, + MODIFIER_CHOICES, + ATTACK_MODIFIERS, TECH_AGES, WEAPON_TYPES, WEAPON_RANGE, diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index 5e7e0a9..3ca7144 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -40,14 +40,6 @@ export default class FTLNomadRoll extends Roll { return this.options.help } - get gene() { - return this.options.gene - } - - get modifier() { - return this.options.modifier - } - get resultType() { return this.options.resultType } @@ -68,41 +60,15 @@ export default class FTLNomadRoll extends Roll { return this.options.weapon } - get isLowWP() { - return this.options.isLowWP - } - - get isZeroWP() { - return this.options.isZeroWP - } - - get isExhausted() { - return this.options.isExhausted - } - - get isNudgedRoll() { - return this.options.isNudgedRoll - } - - get wpCost() { - return this.options.wpCost - } - - static updateResourceDialog(options) { - let rating = 0 - if (options.rollItem.enableHand) { - rating += options.rollItem.hand + static updateFullFormula(options) { + let fullFormula + if ( options.numericModifier >= 0) { + fullFormula = `${options.formula} + ${options.rollItem.value} + ${options.numericModifier}D` + } else { + fullFormula = `${options.formula} + ${options.rollItem.value} - ${Math.abs(options.numericModifier)}D` } - if (options.rollItem.enableStowed) { - rating += options.rollItem.stowed - } - if (options.rollItem.enableStorage) { - rating += options.rollItem.storage - } - let multiplier = Number($(`.roll-skill-multiplier`).val()) - options.initialScore = rating - options.percentScore = rating * multiplier - $(".resource-score").text(`${rating} (${options.percentScore}%)`) + $('#roll-dialog-full-formula').text(fullFormula) + options.fullFormula = fullFormula } /** @@ -120,84 +86,25 @@ export default class FTLNomadRoll extends Roll { * @returns {Promise} The roll result or null if the dialog was cancelled. */ static async prompt(options = {}) { - let formula = "1d100" - let hasModifier = true - let hasMultiplier = false - options.isNudge = true + let formula = "2d6" switch (options.rollType) { case "skill": - console.log(options.rollItem) - options.initialScore = options.rollItem.system.computeScore() - break - case "san": - case "char": - options.initialScore = options.rollItem.targetScore - options.isNudge = (options.rollType !== "san") - break - case "resource": - hasModifier = false - hasMultiplier = true - options.initialScore = options.rollItem.targetScore - options.totalRating = options.rollItem.targetScore - options.percentScore = options.rollItem.targetScore * 5 - options.rollItem.enableHand = true - options.rollItem.enableStowed = true - options.rollItem.enableStorage = true - options.isNudge = false break case "damage": let formula = options.rollItem.system.damage - if ( options.rollItem.system.weaponType === "melee" || options.rollItem.system.weaponType === "unarmed") { - formula += ` + ${options.rollItem.damageBonus}` - } let damageRoll = new Roll(formula) await damageRoll.evaluate() await damageRoll.toMessage({ flavor: `${options.rollItem.name} - Damage Roll` }); - let isLethal = false - options.isNudge = false - if (options.rollItem.system.lethality > 0) { - let lethalityRoll = new Roll("1d100") - await lethalityRoll.evaluate() - isLethal = (lethalityRoll.total <= options.rollItem.system.lethality) - await lethalityRoll.toMessage({ - flavor: `${options.rollItem.name} - Lethality Roll : ${lethalityRoll.total} <= ${options.rollItem.system.lethality} => ${isLethal}` - }); - } return case "weapon": - let era = game.settings.get("fvtt-ftl-nomad", "settings-era") - if (era !== options.rollItem.system.settings) { - ui.notifications.error(game.i18n.localize("FTLNOMAD.Notifications.WrongEra")) - console.log("WP Wrong Era", era, options.rollItem.system.weaponType) - return - } - if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) { - ui.notifications.error(game.i18n.localize("FTLNOMAD.Notifications.NoWeaponType")) - console.log("WP Not found", era, options.rollItem.system.weaponType) - return - } - options.weapon = options.rollItem - if (options.rollItem.system.hasDirectSkill) { - let skillName = options.rollItem.name - options.rollItem = {type: "skill", name: skillName, system: {base: 0, bonus: options.weapon.system.directSkillValue} } - 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("FTLNOMAD.Notifications.NoWeaponSkill")) - return - } - options.initialScore = options.rollItem.system.computeScore() - console.log("WEAPON", skillName, era, options.rollItem) - } + let actor = game.actors.get(options.actorId) + options.weapon = foundry.utils.duplicate(options.rollItem) + options.rollItem = actor.system.skills.combat break default: - options.initialScore = 50 break } @@ -209,37 +116,53 @@ export default class FTLNomadRoll extends Roll { }) const choiceModifier = SYSTEM.MODIFIER_CHOICES - const choiceMultiplier = SYSTEM.MULTIPLIER_CHOICES + let choiceRangeModifier = {} + let rangeModifier = 0 + if ( options.weapon) { + // Build the range modifiers + let range = SYSTEM.WEAPON_RANGE[options.weapon.system.rangeType] + for (let [key, value] of Object.entries(range.range)) { + choiceRangeModifier[key] = { label: `${key} (${value}D)`, value: value } + if (!rangeModifier && value) { + rangeModifier = value + } + } + } - let modifier = "+0" - let multiplier = "5" + let modifier = "0" + options.numericModifier = rangeModifier + let fullFormula = `${formula} + ${options.rollItem.value}` + if (options.isEncumbered) { + options.numericModifier += -1 + fullFormula += ` - ${options.numericModifier}D` + } else { + options.numericModifier += 0 + fullFormula += ` + ${options.numericModifier}D` + } + options.fullFormula = fullFormula + options.formula = formula let dialogContext = { + actorId: options.actorId, + actorName: options.actorName, rollType: options.rollType, rollItem: foundry.utils.duplicate(options.rollItem), // Object only, no class + fullFormula, weapon: options?.weapon, - initialScore: options.initialScore, - targetScore: options.initialScore, - isLowWP: options.isLowWP, - isZeroWP: options.isZeroWP, - isExhausted: options.isExhausted, - enableHand: options.rollItem.enableHand, - enableStowed: options.rollItem.enableStowed, - enableStorage: options.rollItem.enableStorage, + isEncumbered: options.isEncumbered, + talents: options.talents, rollModes, fieldRollMode, choiceModifier, - choiceMultiplier, + choiceRangeModifier, + rangeModifier, formula, hasTarget: options.hasTarget, - hasModifier, - hasMultiplier, modifier, - multiplier } const content = await renderTemplate("systems/fvtt-ftl-nomad/templates/roll-dialog.hbs", dialogContext) - const title = CthulhuEternalRoll.createTitle(options.rollType, options.rollTarget) + const title = FTLNomadRoll.createTitle(options.rollType, options.rollTarget) const label = game.i18n.localize("FTLNOMAD.Roll.roll") const rollContext = await foundry.applications.api.DialogV2.wait({ window: { title: title }, @@ -258,24 +181,27 @@ export default class FTLNomadRoll extends Roll { }, ], actions: { - "selectHand": (event, button, dialog) => { - options.rollItem.enableHand = !options.rollItem.enableHand - this.updateResourceDialog(options) - }, - "selectStowed": (event, button, dialog) => { - options.rollItem.enableStowed = !options.rollItem.enableStowed - this.updateResourceDialog(options) - }, - "selectStorage": (event, button, dialog) => { - options.rollItem.enableStorage = !options.rollItem.enableStorage - this.updateResourceDialog(options) - } }, rejectClose: false, // Click on Close button will not launch an error render: (event, dialog) => { - $(".roll-skill-multiplier").change(event => { - options.multiplier = Number(event.target.value) - this.updateResourceDialog(options) + $(".roll-skill-modifier").change(event => { + options.numericModifier += Number(event.target.value) + FTLNomadRoll.updateFullFormula(options) + }) + $(".roll-skill-range-modifier").change(event => { + options.numericModifier += Number(event.target.value) + FTLNomadRoll.updateFullFormula(options) + }) + $(".select-combat-option").change(event => { + console.log(event) + let field = $(event.target).data("field") + let modifier = SYSTEM.ATTACK_MODIFIERS[field] + if ( event.target.checked) { + options.numericModifier += modifier + } else { + options.numericModifier -= modifier + } + FTLNomadRoll.updateFullFormula(options) }) } }) @@ -285,25 +211,19 @@ export default class FTLNomadRoll extends Roll { let rollData = foundry.utils.mergeObject(foundry.utils.duplicate(options), rollContext) rollData.rollMode = rollContext.visibility - // Update target score - console.log("Rolldata", rollData, options) - if (options.rollType === "resource") { - rollData.targetScore = options.initialScore * Number(rollContext.multiplier) - } else { - rollData.targetScore = Math.min(Math.max(options.initialScore + Number(rollData.modifier), 0), 100) - if (rollData.isLowWP || rollData.isExhausted) { - rollData.targetScore -= 20 - } - if (rollData.isZeroWP) { - rollData.targetScore = 0 - } - rollData.targetScore = Math.min(Math.max(rollData.targetScore, 0), 100) - } + rollData.targetScore = 8 if (Hooks.call("fvtt-ftl-nomad.preRoll", options, rollData) === false) return + + let diceFormula = `${2+Math.abs(options.numericModifier)}D6` + if ( options.numericModifier > 0 ) { + diceFormula += `kh2 + ${options.rollItem.value}` + } else { + diceFormula += `kl2 + ${options.rollItem.value}` + } - const roll = new this(formula, options.data, rollData) + const roll = new this(diceFormula, options.data, rollData) await roll.evaluate() roll.displayRollResult(roll, options, rollData) @@ -317,34 +237,15 @@ export default class FTLNomadRoll extends Roll { // Compute the result quality let resultType = "failure" - let dec = Math.floor(this.total / 10) - let unit = this.total - (dec * 10) - if (this.total <= rollData.targetScore) { + if (this.total >= 8) { resultType = "success" // Detect if decimal == unit in the dire total result - if (dec === unit || this.total === 1) { - resultType = "successCritical" - } - } else { - // Detect if decimal == unit in the dire total result - if (dec === unit || this.total === 100) { - resultType = "failureCritical" - } } this.options.resultType = resultType - if (this.options.isNudgedRoll) { - this.options.isSuccess = resultType === "success" || resultType === "successCritical" - this.options.isFailure = resultType === "failure" || resultType === "failureCritical" - this.options.isCritical = false - } else { - this.options.isSuccess = resultType === "success" || resultType === "successCritical" - this.options.isFailure = resultType === "failure" || resultType === "failureCritical" - this.options.isCritical = resultType === "successCritical" || resultType === "failureCritical" - } - this.options.isLowWP = rollData.isLowWP - this.options.isZeroWP = rollData.isZeroWP - this.options.isExhausted = rollData.isExhausted + this.options.isSuccess = resultType === "success" + this.options.isFailure = resultType === "failure" + this.options.isEncumbered = rollData.isEncumbered this.options.rollData = foundry.utils.duplicate(rollData) } @@ -361,10 +262,6 @@ export default class FTLNomadRoll extends Roll { return `${game.i18n.localize("FTLNOMAD.Label.titleSkill")}` case "weapon": return `${game.i18n.localize("FTLNOMAD.Label.titleWeapon")}` - case "char": - return `${game.i18n.localize("FTLNOMAD.Label.titleCharacteristic")}` - case "san": - return `${game.i18n.localize("FTLNOMAD.Label.titleSAN")}` default: return game.i18n.localize("FTLNOMAD.Label.titleStandard") } @@ -407,6 +304,8 @@ export default class FTLNomadRoll extends Roll { cardData.diceTotal = this.dice.reduce((t, d) => t + d.total, 0) cardData.isGM = game.user.isGM cardData.formula = this.formula + cardData.fullFormula = this.options.fullFormula + cardData.numericModifier = this.options.numericModifier cardData.total = this.total cardData.actorId = this.actorId cardData.actingCharName = this.actorName @@ -418,11 +317,7 @@ export default class FTLNomadRoll extends Roll { cardData.realDamage = this.realDamage cardData.isPrivate = isPrivate cardData.weapon = this.weapon - cardData.isLowWP = this.isLowWP - cardData.isZeroWP = this.isZeroWP - cardData.isExhausted = this.isExhausted - cardData.isNudgedRoll = this.isNudgedRoll - cardData.wpCost = this.wpCost + cardData.isEncumbered = this.isEncumbered cardData.cssClass = cardData.css.join(" ") cardData.tooltip = isPrivate ? "" : await this.getTooltip() diff --git a/module/models/character.mjs b/module/models/character.mjs index 21bf424..cf32a01 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -18,6 +18,7 @@ export default class FTLNomadProtagonist extends foundry.abstract.TypeDataModel const skillField = (label) => { const schema = { value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 5 }), + label: new fields.StringField({ required: true, nullable: false, initial: label }) } return new fields.SchemaField(schema, { label }) } @@ -43,6 +44,10 @@ export default class FTLNomadProtagonist extends foundry.abstract.TypeDataModel max: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) }) + schema.armor = new fields.SchemaField({ + value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) + }) + schema.credits = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) schema.rank = new fields.SchemaField({ experienced: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 5 }), @@ -55,6 +60,7 @@ export default class FTLNomadProtagonist extends foundry.abstract.TypeDataModel schema.biodata = new fields.SchemaField({ age: new fields.NumberField({ ...requiredInteger, initial: 15, min: 6 }), height: new fields.NumberField({ ...requiredInteger, initial: 170, min: 50 }), + weight: new fields.NumberField({ ...requiredInteger, initial: 70, min: 1 }), gender: new fields.StringField({ required: true, nullable: false, initial: "" }), home: new fields.StringField({ required: true, nullable: false, initial: "" }), birthplace: new fields.StringField({ required: true, nullable: false, initial: "" }), @@ -70,9 +76,33 @@ export default class FTLNomadProtagonist extends foundry.abstract.TypeDataModel prepareDerivedData() { super.prepareDerivedData(); - + + let encMax = 10 + (2*this.skills.physical.value) + if (encMax !== this.enc.max) { + this.enc.max = encMax + } + let enc = 0 + let armor = 0 + for (let i of this.parent.items) { + if (i.system?.enc) { + enc += i.system.enc + } + if ( i.system?.protection) { + armor += i.system.protection + } + } + if (enc !== this.enc.value) { + this.enc.value = enc + } + if (armor !== this.armor.value) { + this.armor.value = armor + } } + isEncumbered() { + return this.enc.value > this.enc.max + } + /** */ /** * Rolls a dice for a character. @@ -84,12 +114,14 @@ export default class FTLNomadProtagonist extends foundry.abstract.TypeDataModel let opponentTarget const hasTarget = opponentTarget !== undefined - let roll = await CthulhuEternalRoll.prompt({ + let roll = await FTLNomadRoll.prompt({ rollType, rollItem, actorId: this.parent.id, actorName: this.parent.name, actorImage: this.parent.img, + talents: this.parent.items.filter(i => i.type === "talent" && i.system.isAdvantage), + isEncumbered: this.isEncumbered(), hasTarget, target: opponentTarget }) diff --git a/styles/character.less b/styles/character.less index f74ae14..e6e1d6a 100644 --- a/styles/character.less +++ b/styles/character.less @@ -39,11 +39,9 @@ align-items: center; input { flex: none; - width: 2rem; - margin-left: 4px; - } - .damage-bonus { - font-size: calc(var(--font-size-standard) * 0.8); + width: 2.5rem; + margin-left: 2px; + margin-right: 4px; } .hp-separator { font-size: calc(var(--font-size-standard) * 1.2); @@ -77,6 +75,19 @@ flex-direction: column; gap: 5px; + .character-spec { + label { + max-width: 6rem; + } + .hero-armor { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; + input { + max-width: 3rem; + } + } + } .character-name { display: flex; input { @@ -85,87 +96,6 @@ width: 400px; } } - .san { - align-content: flex-start; - input { - min-width: 2.2rem; - max-width: 2.2rem; - margin-bottom: 4px; - } - select { - min-width: 6rem; - max-width: 6rem; - } - .rollable:hover, - .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; - font-size: 0.9rem; - } - .button { - min-width: 4rem; - max-width: 4rem; - } - .san-checkbox { - min-width: 1rem; - max-width: 1rem; - } - .label-short-field { - font-size: 0.9rem; - max-width: 3rem; - min-width: 3rem; - flex-grow: 1; - } - .label-recovery { - margin-left: 4px; - } - .label-field { - font-size: 0.9rem; - max-width: 6rem; - min-width: 6rem; - flex-grow: 1; - } - .label-bp { - flex-grow: 1; - max-width: 3rem; - min-width: 3rem; - margin-left: 4px; - } - .label-insanity { - flex-grow: 1; - margin-left: 4px; - max-width: 8rem; - min-width: 8rem; - } - .spacing { - margin-left: 4px; - } - .d100 { - flex: 0; - } - } - .willpower { - input { - min-width: 2.4rem; - max-width: 2.4rem; - } - input[type="checkbox"] { - min-width: 1rem; - max-width: 1rem; - } - .label-field { - flex-grow: 1; - margin-left: 4px; - max-width: 5rem; - min-width: 5rem; - font-size: 0.9rem; - } - .checkbox { - flex-grow: 0; - min-width: 1rem; - max-width: 1rem; - } - } label { min-width: 120px; } @@ -190,6 +120,11 @@ .character-skill { display: flex; align-items: center; + .icon-skill { + width: 24px; + height: 24px; + margin-right: 4px; + } .rollable:hover, .rollable:focus { text-shadow: 0 0 8px var(--color-shadow-primary); @@ -239,12 +174,24 @@ margin-left: 8px; } - .adapted { + .rank { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 8px; + label { + min-width: 6rem; + } + input { + max-width: 4rem; + } + } + + .biodata { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; label { - min-width: 20rem; + min-width: 12rem; } } @@ -455,6 +402,127 @@ } } +.tab.character-talents { + background-color: var(--color-light-1); + display: grid; + grid-template-columns: 1fr; + legend { + a { + font-size: calc(var(--font-size-standard) * 1.4); + padding-left: 5px; + } + } + + .talents { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; + .talent { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; + .rollable:hover, + .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; + } + .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; + } + .damage { + min-width: 6rem; + max-width: 6rem; + } + .name { + min-width: 10rem; + max-width: 10rem; + } + .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; + } + } + } + + .languages { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; + .language { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; + .rollable:hover, + .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; + } + .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; + } + .damage { + min-width: 6rem; + max-width: 6rem; + } + .name { + min-width: 10rem; + max-width: 10rem; + } + .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; + } + } + } + + .psionics { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; + .psionic { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; + .rollable:hover, + .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; + } + .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; + } + .damage { + min-width: 6rem; + max-width: 6rem; + } + .name { + min-width: 10rem; + max-width: 10rem; + } + .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; + } + } + } + +} + .tab.character-equipment { background-color: var(--color-light-1); display: grid; @@ -465,6 +533,56 @@ padding-left: 5px; } } + .encumbrance { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 4px; + input { + max-width: 4rem; + } + .encumbered { + color: red; + font-weight: bold; + } + } + + .implants { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; + .implant { + display: flex; + align-items: center; + gap: 4px; + min-width: 13rem; + max-width: 13rem; + .rollable:hover, + .rollable:focus { + text-shadow: 0 0 8px var(--color-shadow-primary); + cursor: pointer; + } + .controls { + font-size: 0.7rem; + min-width: 1.8rem; + max-width: 1.8rem; + } + .damage { + min-width: 6rem; + max-width: 6rem; + } + .name { + min-width: 10rem; + max-width: 10rem; + } + .item-img { + width: 24px; + height: 24px; + margin: 4px 0 0 0; + } + } + } + + .weapons { display: grid; grid-template-columns: repeat(2, 1fr); @@ -500,9 +618,10 @@ } } } + .armors { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(2, 1fr); gap: 4px; .armor { display: flex; @@ -510,23 +629,18 @@ gap: 4px; min-width: 13rem; max-width: 13rem; - .rollable:hover, - .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; - } .controls { font-size: 0.7rem; min-width: 1.8rem; max-width: 1.8rem; } .protection { - min-width: 5rem; - max-width: 5rem; + min-width: 6rem; + max-width: 6rem; } .name { - min-width: 8rem; - max-width: 8rem; + min-width: 10rem; + max-width: 10rem; } .item-img { width: 24px; @@ -536,11 +650,11 @@ } } - .gears { + .equipments { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; - .gear { + .equipment { display: flex; align-items: center; gap: 4px; @@ -568,70 +682,6 @@ } } - .rituals { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 4px; - .ritual { - display: flex; - align-items: center; - gap: 4px; - min-width: 20rem; - max-width: 20rem; - .rollable:hover, - .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; - } - .controls { - font-size: 0.7rem; - min-width: 1.8rem; - max-width: 1.8rem; - } - .name { - min-width: 17rem; - max-width: 17rem; - } - .item-img { - width: 24px; - height: 24px; - margin: 4px 0 0 0; - } - } - } - - .tomes { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 4px; - .tome { - display: flex; - align-items: center; - gap: 4px; - min-width: 20rem; - max-width: 20rem; - .rollable:hover, - .rollable:focus { - text-shadow: 0 0 8px var(--color-shadow-primary); - cursor: pointer; - } - .controls { - font-size: 0.7rem; - min-width: 1.8rem; - max-width: 1.8rem; - } - .name { - min-width: 17rem; - max-width: 17rem; - } - .item-img { - width: 24px; - height: 24px; - margin: 4px 0 0 0; - } - } - } - prose-mirror.inactive { min-height: 40px; } diff --git a/styles/roll.less b/styles/roll.less index 0df4727..3053f8d 100644 --- a/styles/roll.less +++ b/styles/roll.less @@ -31,7 +31,7 @@ border: none; background-color: rgba(0, 0, 0, 0.1); color: var(--color-dark-2); - width: 4rem; + width: 10rem; text-align: center; } } diff --git a/system.json b/system.json index 0c82fb0..1c376f0 100644 --- a/system.json +++ b/system.json @@ -6,7 +6,7 @@ "download": "#{DOWNLOAD}#", "url": "https://www.uberwald.me/gitea/public/fvtt-ftl-nomad", "license": "LICENSE", - "version": "12.0.0", + "version": "12.0.1", "authors": [ { "name": "Uberwald", diff --git a/templates/character-biography.hbs b/templates/character-biography.hbs index 68ac23e..3c917ce 100644 --- a/templates/character-biography.hbs +++ b/templates/character-biography.hbs @@ -1,17 +1,24 @@
-
- {{localize "FTLNOMAD.Label.resources"}} -
-
+
+ Rank + {{formField systemFields.rank.fields.experienced value=system.rank.experienced type="number" rootId=partId disabled=isPlayMode}} + {{formField systemFields.rank.fields.expert value=system.rank.expert type="number" rootId=partId disabled=isPlayMode}} + {{formField systemFields.rank.fields.veteran value=system.rank.veteran type="number" rootId=partId disabled=isPlayMode}} + {{formField systemFields.rank.fields.elite value=system.rank.elite type="number" rootId=partId disabled=isPlayMode}} + {{formField systemFields.rank.fields.legend value=system.rank.legend type="number" rootId=partId disabled=isPlayMode}}
-
+
{{localize "FTLNOMAD.Label.biodata"}} -
-
-
-
+ {{formField systemFields.biodata.fields.gender value=system.biodata.gender rootId=partId disabled=isPlayMode classes="short"}} + {{formField systemFields.biodata.fields.age value=system.biodata.age rootId=partId disabled=isPlayMode classes="short"}} + {{formField systemFields.biodata.fields.height value=system.biodata.height rootId=partId disabled=isPlayMode classes="short"}} + {{formField systemFields.biodata.fields.weight value=system.biodata.weight rootId=partId disabled=isPlayMode classes="short"}} + {{formField systemFields.biodata.fields.eyes value=system.biodata.eyes rootId=partId disabled=isPlayMode classes="short"}} + {{formField systemFields.biodata.fields.hair value=system.biodata.hair rootId=partId disabled=isPlayMode classes="short"}} + {{formField systemFields.biodata.fields.home value=system.biodata.home rootId=partId disabled=isPlayMode}} + {{formField systemFields.biodata.fields.birthplace value=system.biodata.birthplace rootId=partId disabled=isPlayMode}}
diff --git a/templates/character-equipment.hbs b/templates/character-equipment.hbs index 70e3a0c..d0f3d34 100644 --- a/templates/character-equipment.hbs +++ b/templates/character-equipment.hbs @@ -1,5 +1,15 @@
+
+ {{#if isEncumbered}} + {{formField systemFields.enc.fields.value value=system.enc.value rootId=partId disabled=true classes="encumbered"}} + {{else }} + {{formField systemFields.enc.fields.value value=system.enc.value rootId=partId disabled=true}} + {{/if}} + {{formField systemFields.enc.fields.max value=system.enc.max rootId=partId disabled=isPlayMode}} + {{formField systemFields.credits value=system.credits rootId=partId }} +
+
{{localize "FTLNOMAD.Label.weapons"}}{{#if isEditMode}}
+
+ {{localize "FTLNOMAD.Label.implants"}}{{#if isEditMode}} + {{/if}} + +
+ {{#each implants as |item|}} + {{!log 'weapon' this}} + + {{/each}} +
+
+
{{localize "FTLNOMAD.Label.equipments"}}{{#if isEditMode}} {{localize "FTLNOMAD.Label.Stamina"}}
{{formField systemFields.health.fields.staminaValue value=health.staminaValue}} - / - {{formField systemFields.health.fields.staminaMax value=system.health.staminaMax rootId=partId - disabled=true}} + {{formField systemFields.health.fields.staminaMax value=system.health.staminaMax rootId=partId disabled=true}}
-
+
{{formField systemFields.health.fields.wounds value=system.health.wounds }}
@@ -30,68 +28,69 @@ -
+
{{formField systemFields.concept value=system.concept rootId=partId disabled=isPlayMode}} {{formField systemFields.species value=system.species rootId=partId disabled=isPlayMode}} {{formField systemFields.archetype value=system.archetype rootId=partId disabled=isPlayMode}} +
+ {{formField systemFields.heroPoints value=system.heroPoints rootId=partId disabled=isPlayMode}} + {{formField systemFields.armor.fields.value value=system.armor.value rootId=partId disabled=isPlayMode}} +
-
-
{{localize "FTLNOMAD.Label.skills"}}
- -
- -
- -
- -
- -
- -
- -
diff --git a/templates/character-talents.hbs b/templates/character-talents.hbs new file mode 100644 index 0000000..6ae3ac8 --- /dev/null +++ b/templates/character-talents.hbs @@ -0,0 +1,106 @@ +
+ +
+ {{localize "FTLNOMAD.Label.talents"}}{{#if isEditMode}} + {{/if}} + +
+ {{#each talents as |item|}} + {{!log 'weapon' this}} + + {{/each}} +
+
+ +
+ {{localize "FTLNOMAD.Label.psionics"}}{{#if isEditMode}} + {{/if}} + +
+ {{#each psionics as |item|}} + {{!log 'weapon' this}} + + {{/each}} +
+
+ +
+ {{localize "FTLNOMAD.Label.languages"}}{{#if isEditMode}} + {{/if}} + +
+ {{#each languages as |item|}} + {{!log 'weapon' this}} + + {{/each}} +
+
+ + +
\ No newline at end of file diff --git a/templates/chat-message.hbs b/templates/chat-message.hbs index 952b19d..d115c7e 100644 --- a/templates/chat-message.hbs +++ b/templates/chat-message.hbs @@ -6,74 +6,39 @@
    - {{#if (eq rollType "char")}} -
  • {{localize "FTLNOMAD.Label.charRoll"}}
  • - {{/if}} {{#if (eq rollType "skill")}}
  • {{localize "FTLNOMAD.Label.skillRoll"}}
  • {{/if}} - {{#if isNudgedRoll}} -
  • {{localize "FTLNOMAD.Label.nudgedRoll"}} : {{wpCost}} WP spent
  • - {{/if}} {{#if weapon}}
  • Weapon : {{weapon.name}}
  • {{/if}} - {{#if (eq rollType "resource")}} -
  • {{rollItem.name}} : {{initialScore}}
  • - {{else}} -
  • {{rollItem.name}} : {{initialScore}}%
  • +
  • {{localize rollItem.label}} : {{fullFormula}}
  • + + {{#if isEncumbered}} +
  • Encumbered : -1D
  • {{/if}} - {{#if isZeroWP}} -
  • Zero WP : Automatic failure (ie 0%)
  • - {{else}} - {{#if isLowWP}} -
  • Low WP : -20%
  • - {{/if}} - {{/if}} - - {{#if isExhausted}} -
  • Exhausted : -20%
  • - {{/if}} - - {{#if (eq rollType "resource")}} -
  • {{localize "FTLNOMAD.Label.multiplier"}} : {{multiplier}}
  • - {{else}} -
  • {{localize "FTLNOMAD.Label.modifier"}} : {{modifier}}%
  • - {{/if}} +
  • {{localize "FTLNOMAD.Label.modifier"}} : {{numericModifier}}D
  • -
  • {{localize "FTLNOMAD.Label.targetScore"}} : {{targetScore}}%
  • {{#if isSuccess}} - {{#if isCritical}} -
  • {{localize "FTLNOMAD.Label.criticalSuccess"}}
  • - {{else}}
  • {{localize "FTLNOMAD.Label.success"}} - {{#if isNudge}} - - {{/if}}
  • {{/if}} - {{/if}} + {{#if isFailure}} - {{#if isCritical}} -
  • {{localize "FTLNOMAD.Label.criticalFailure"}}
  • - {{else}}
  • {{localize "FTLNOMAD.Label.failure"}} - {{#if isNudge}} - - {{/if}}
  • {{/if}} - {{/if}}
+ {{#if isDamage}}
{{#if (and isGM hasTarget)}} diff --git a/templates/creature-biography.hbs b/templates/creature-biography.hbs index e0ebdce..230cafc 100644 --- a/templates/creature-biography.hbs +++ b/templates/creature-biography.hbs @@ -1,10 +1,12 @@
+
{{localize "FTLNOMAD.Label.description"}} - {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} + {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" + toggled=true}}
- +
{{localize "FTLNOMAD.Label.notes"}} {{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}} diff --git a/templates/roll-dialog.hbs b/templates/roll-dialog.hbs index 45d934d..0f9b62a 100644 --- a/templates/roll-dialog.hbs +++ b/templates/roll-dialog.hbs @@ -1,57 +1,53 @@ -
+
+
+ {{#if (eq rollType "skill")}} {{localize "FTLNOMAD.Label.skill"}} {{/if}} - {{#if (eq rollType "char")}} - {{localize "FTLNOMAD.Label.characteristic"}} - {{/if}} - {{#if (eq rollType "resource")}} - {{localize "FTLNOMAD.Label.resourceRating"}} -
{{rollItem.name}} : {{initialScore}} ({{mul initialScore 5}}%)
-
{{localize "FTLNOMAD.Label.Hand"}} : {{rollItem.hand}}
-
{{localize "FTLNOMAD.Label.Stowed"}} : {{rollItem.stowed}}
-
{{localize "FTLNOMAD.Label.Storage"}} : {{rollItem.storage}}
- {{else}} -
{{rollItem.name}} : {{initialScore}}%
- {{/if}} +
{{localize rollItem.label}} : 2d6+{{rollItem.value}}
{{#if weapon}}
Weapon : {{weapon.name}}
{{/if}} - {{#if isZeroWP}} -
Zero WP : Automatic failure (ie 0%)
- {{else}} - {{#if isLowWP}} -
Low WP : -20%
- {{/if}} - {{/if}} - - {{#if isExhausted}} -
Exhausted : -20%
+ {{#if isEncumbered}} +
Encumbered : -1D
{{/if}}
- {{#if hasModifier}}
{{localize "FTLNOMAD.Label.modifier"}} - -
- {{/if}} - {{#if hasMultiplier}} -
- {{localize "FTLNOMAD.Label.multiplier"}} - + {{selectOptions choiceModifier selected=modifier localize=true}} + + {{#if weapon}} + +
    +
  • Two Attacks :
  • +
  • Aiming :
  • +
  • Dim Lightning :
  • +
  • Darkness :
  • +
  • Target Prone/Obscured :
  • +
  • Target Cover :
  • +
  • 1/2 Auto Fire Recoil :
  • +
  • 2+ Auto Fire Recoil :
  • +
  • Target Aware :
  • +
+ {{/if}} + +
+ +
+ {{localize "FTLNOMAD.Label.formula"}} +
- {{/if}}
{{localize "FTLNOMAD.Label.rollView"}} @@ -59,4 +55,5 @@ {{selectOptions rollModes selected=visibility}}
+
\ No newline at end of file