diff --git a/.vscode/settings.json b/.vscode/settings.json index c46b4a1..75011bf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,14 @@ "[handlebars]": { "editor.defaultFormatter": "monosans.djlint" + }, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" } } diff --git a/css/deltagreen.css b/css/deltagreen.css index 58791d7..c4f44a8 100644 --- a/css/deltagreen.css +++ b/css/deltagreen.css @@ -737,6 +737,37 @@ div .exhausted-section { margin-bottom: 5px; } +.tab.about { + .dg-about-links { + gap: 0.5rem; + margin-bottom: 1rem; + + a { + display: inline-flex; + align-items: center; + gap: 0.5rem; + width: fit-content; + max-width: 100%; + + i { + flex: 0 0 auto; + } + + span { + flex: 1 1 auto; + line-height: 1.4; + text-align: left; + } + } + } + + .dg-about-legal { + p { + margin: 0.5rem 0; + } + } +} + textarea.wounds { resize: none; height: 100px; diff --git a/module/data/actor/agent.js b/module/data/actor/agent.js index 1797bf1..a3b1fc8 100644 --- a/module/data/actor/agent.js +++ b/module/data/actor/agent.js @@ -1,7 +1,7 @@ import HumanSkillsActorData from "./base/human-skills.js"; import CharacterData from "./base/character.js"; -const { SchemaField, NumberField, StringField, BooleanField } = +const { SchemaField, NumberField, StringField, BooleanField, HTMLField } = foundry.data.fields; export default class AgentData extends CharacterData { @@ -29,8 +29,10 @@ export default class AgentData extends CharacterData { }), }), physical: new SchemaField({ - description: new StringField({ + description: new HTMLField({ initial: "", + blank: true, + textSearch: true, }), wounds: new StringField({ initial: "" }), firstAidAttempted: new BooleanField({ initial: false }), diff --git a/module/data/actor/npc.js b/module/data/actor/npc.js index 623d360..412cfc1 100644 --- a/module/data/actor/npc.js +++ b/module/data/actor/npc.js @@ -1,7 +1,7 @@ import HumanSkillsActorData from "./base/human-skills.js"; import CharacterData from "./base/character.js"; -const { SchemaField, NumberField, StringField, BooleanField } = +const { SchemaField, NumberField, StringField, BooleanField, HTMLField } = foundry.data.fields; export default class NPCData extends CharacterData { @@ -19,7 +19,7 @@ export default class NPCData extends CharacterData { biography: new SchemaField({ profession: new StringField({ initial: "" }), }), - notes: new StringField({ initial: "" }), + notes: new HTMLField({ initial: "", blank: true, textSearch: true }), shortDescription: new StringField({ initial: "" }), showUntrainedSkills: new BooleanField({ initial: true }), }; diff --git a/module/data/actor/unnatural.js b/module/data/actor/unnatural.js index 6a32949..7e293b6 100644 --- a/module/data/actor/unnatural.js +++ b/module/data/actor/unnatural.js @@ -1,7 +1,7 @@ import UnnaturalSkillsActorData from "./base/unnatural-skills.js"; import CharacterData from "./base/character.js"; -const { SchemaField, NumberField, StringField, BooleanField } = +const { SchemaField, NumberField, StringField, BooleanField, HTMLField } = foundry.data.fields; export default class UnnaturalData extends CharacterData { @@ -17,7 +17,12 @@ export default class UnnaturalData extends CharacterData { successLoss: new StringField({ initial: "1" }), }), schemaVersion: new NumberField({ initial: 1.0 }), - notes: new StringField({ initial: "" }), + notes: new HTMLField({ + initial: "", + blank: true, + textSearch: true, + allowColor: true, + }), shortDescription: new StringField({ initial: "" }), showUntrainedSkills: new BooleanField({ initial: true }), }; diff --git a/module/data/actor/vehicle.js b/module/data/actor/vehicle.js index e21ff07..e6e75e3 100644 --- a/module/data/actor/vehicle.js +++ b/module/data/actor/vehicle.js @@ -1,6 +1,6 @@ import SheetSettingsActorData from "./base/sheet-settings.js"; -const { SchemaField, NumberField, StringField, ArrayField } = +const { SchemaField, NumberField, StringField, ArrayField, HTMLField } = foundry.data.fields; export default class VehicleData extends foundry.abstract.TypeDataModel { @@ -8,7 +8,11 @@ export default class VehicleData extends foundry.abstract.TypeDataModel { return { ...SheetSettingsActorData.defineSchema(), name: new StringField({ initial: "" }), - description: new StringField({ initial: "" }), + description: new HTMLField({ + initial: "", + blank: true, + textSearch: true, + }), shortDescription: new StringField({ initial: "" }), health: new SchemaField({ value: new NumberField({ initial: 10 }), diff --git a/module/data/item/armor.js b/module/data/item/armor.js new file mode 100644 index 0000000..58e47ef --- /dev/null +++ b/module/data/item/armor.js @@ -0,0 +1,14 @@ +import defineBaseItemSystemFields from "./base-fields.js"; + +const { NumberField, StringField, BooleanField } = foundry.data.fields; + +export default class ArmorItemData extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + ...defineBaseItemSystemFields(), + protection: new NumberField({ initial: 3, integer: true }), + equipped: new BooleanField({ initial: true }), + expense: new StringField({ initial: "Standard" }), + }; + } +} diff --git a/module/data/item/base-fields.js b/module/data/item/base-fields.js new file mode 100644 index 0000000..896b518 --- /dev/null +++ b/module/data/item/base-fields.js @@ -0,0 +1,11 @@ +const { HTMLField } = foundry.data.fields; + +/** + * Shared system fields for all Delta Green item types (from legacy template base). + * Item display name lives on the document (`Item#name`), not in system. + */ +export default function defineBaseItemSystemFields() { + return { + description: new HTMLField({ initial: "", blank: true, textSearch: true }), + }; +} diff --git a/module/data/item/bond.js b/module/data/item/bond.js new file mode 100644 index 0000000..81ff8df --- /dev/null +++ b/module/data/item/bond.js @@ -0,0 +1,14 @@ +import defineBaseItemSystemFields from "./base-fields.js"; + +const { NumberField, StringField, BooleanField } = foundry.data.fields; + +export default class BondItemData extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + ...defineBaseItemSystemFields(), + score: new NumberField({ initial: 10, integer: true }), + relationship: new StringField({ initial: "" }), + hasBeenDamagedSinceLastHomeScene: new BooleanField({ initial: false }), + }; + } +} diff --git a/module/data/item/gear.js b/module/data/item/gear.js new file mode 100644 index 0000000..8d54208 --- /dev/null +++ b/module/data/item/gear.js @@ -0,0 +1,13 @@ +import defineBaseItemSystemFields from "./base-fields.js"; + +const { StringField, BooleanField } = foundry.data.fields; + +export default class GearItemData extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + ...defineBaseItemSystemFields(), + equipped: new BooleanField({ initial: true }), + expense: new StringField({ initial: "Standard" }), + }; + } +} diff --git a/module/data/item/motivation.js b/module/data/item/motivation.js new file mode 100644 index 0000000..5d0831f --- /dev/null +++ b/module/data/item/motivation.js @@ -0,0 +1,14 @@ +import defineBaseItemSystemFields from "./base-fields.js"; + +const { StringField, BooleanField } = foundry.data.fields; + +export default class MotivationItemData extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + ...defineBaseItemSystemFields(), + disorder: new StringField({ initial: "" }), + crossedOut: new BooleanField({ initial: false }), + disorderCured: new BooleanField({ initial: false }), + }; + } +} diff --git a/module/data/item/ritual.js b/module/data/item/ritual.js new file mode 100644 index 0000000..7386cf8 --- /dev/null +++ b/module/data/item/ritual.js @@ -0,0 +1,33 @@ +import defineBaseItemSystemFields from "./base-fields.js"; + +const { NumberField, StringField, BooleanField, SchemaField, HTMLField } = + foundry.data.fields; + +export default class RitualItemData extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + ...defineBaseItemSystemFields(), + studyTime: new StringField({ initial: "" }), + sanity: new SchemaField({ + notes: new StringField({ initial: "" }), + failedLoss: new StringField({ initial: "1D10" }), + successLoss: new StringField({ initial: "0" }), + }), + learnedSanity: new SchemaField({ + notes: new StringField({ initial: "" }), + failedLoss: new StringField({ initial: "1D10" }), + successLoss: new StringField({ initial: "0" }), + }), + unnaturalSkillIncrease: new NumberField({ initial: 1, integer: true }), + activationCosts: new StringField({ initial: "" }), + activationTime: new StringField({ initial: "" }), + complexity: new StringField({ initial: "Simple" }), + handlerNotes: new HTMLField({ + initial: "", + blank: true, + textSearch: true, + }), + revealed: new BooleanField({ initial: false }), + }; + } +} diff --git a/module/data/item/tome.js b/module/data/item/tome.js new file mode 100644 index 0000000..2673153 --- /dev/null +++ b/module/data/item/tome.js @@ -0,0 +1,27 @@ +import defineBaseItemSystemFields from "./base-fields.js"; + +const { NumberField, StringField, BooleanField, SchemaField, HTMLField } = + foundry.data.fields; + +export default class TomeItemData extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + ...defineBaseItemSystemFields(), + language: new StringField({ initial: "" }), + studyTime: new StringField({ initial: "" }), + unnaturalSkillIncrease: new NumberField({ initial: 5, integer: true }), + occultSkillIncrease: new NumberField({ initial: 3, integer: true }), + sanity: new SchemaField({ + notes: new StringField({ initial: "" }), + failedLoss: new StringField({ initial: "1D6" }), + successLoss: new StringField({ initial: "1D4" }), + }), + handlerNotes: new HTMLField({ + initial: "", + blank: true, + textSearch: true, + }), + revealed: new BooleanField({ initial: false }), + }; + } +} diff --git a/module/data/item/weapon.js b/module/data/item/weapon.js new file mode 100644 index 0000000..11777a2 --- /dev/null +++ b/module/data/item/weapon.js @@ -0,0 +1,23 @@ +import defineBaseItemSystemFields from "./base-fields.js"; + +const { NumberField, StringField, BooleanField } = foundry.data.fields; + +export default class WeaponItemData extends foundry.abstract.TypeDataModel { + static defineSchema() { + return { + ...defineBaseItemSystemFields(), + skill: new StringField({ initial: "" }), + skillModifier: new NumberField({ initial: 0, integer: true }), + customSkillTarget: new NumberField({ initial: 50, integer: true }), + range: new StringField({ initial: "10M" }), + damage: new StringField({ initial: "1D8" }), + armorPiercing: new NumberField({ initial: 0, integer: true }), + lethality: new NumberField({ initial: 0, integer: true }), + isLethal: new BooleanField({ initial: false }), + killRadius: new StringField({ initial: "N/A" }), + ammo: new StringField({ initial: "" }), + expense: new StringField({ initial: "Standard" }), + equipped: new BooleanField({ initial: true }), + }; + } +} diff --git a/module/deltagreen.js b/module/deltagreen.js index 63f12f7..5f7aad5 100644 --- a/module/deltagreen.js +++ b/module/deltagreen.js @@ -25,18 +25,35 @@ import AgentData from "./data/actor/agent.js"; import UnnaturalData from "./data/actor/unnatural.js"; import NPCData from "./data/actor/npc.js"; import VehicleData from "./data/actor/vehicle.js"; +import WeaponItemData from "./data/item/weapon.js"; +import ArmorItemData from "./data/item/armor.js"; +import MotivationItemData from "./data/item/motivation.js"; +import BondItemData from "./data/item/bond.js"; +import GearItemData from "./data/item/gear.js"; +import TomeItemData from "./data/item/tome.js"; +import RitualItemData from "./data/item/ritual.js"; const { Actors, Items } = foundry.documents.collections; Hooks.once("init", async () => { Object.assign(CONFIG.Actor.dataModels, { - // The keys are the types defined in our template.json + // The keys are the types defined in system.json documentTypes.Actor agent: AgentData, unnatural: UnnaturalData, npc: NPCData, vehicle: VehicleData, }); + Object.assign(CONFIG.Item.dataModels, { + weapon: WeaponItemData, + armor: ArmorItemData, + motivation: MotivationItemData, + bond: BondItemData, + gear: GearItemData, + tome: TomeItemData, + ritual: RitualItemData, + }); + game.deltagreen = { DeltaGreenActor, DeltaGreenItem, diff --git a/module/roll/roll.js b/module/roll/roll.js index 80f7fbc..db002e4 100644 --- a/module/roll/roll.js +++ b/module/roll/roll.js @@ -594,10 +594,11 @@ export class DGLethalityRoll extends DGPercentileRoll { } let html = ""; - html += `
`; + html += `
`; html += `
`; html += `
${resultString}
`; html += `
`; + html += `
`; html += `
`; html += `
`; html += `
`; @@ -626,10 +627,12 @@ export class DGLethalityRoll extends DGPercentileRoll { html += ` `; html += `
`; html += `
`; + html += `
`; html += `
`; html += `

${this.total} (${ nonLethalDamage.total } ${game.i18n.localize("DG.Roll.Damage")})

`; + html += `
`; html += `
`; return this.toMessage({ content: html, flavor: label }); @@ -788,10 +791,11 @@ export class DGSanityDamageRoll extends DGRoll { )} For ${lowDie.formula} / ${highDie.formula}`; let html = ""; - html += `
`; + html += `
`; html += `
`; html += `
${lowDie.formula} / ${highDie.formula}
`; html += `
`; + html += `
`; html += `
`; html += `
`; html += `
`; @@ -819,8 +823,10 @@ export class DGSanityDamageRoll extends DGRoll { html += ` `; html += `
`; html += `
`; + html += `
`; html += `
`; html += `

${lowResult} / ${highResult}

`; + html += `
`; html += `
`; return this.toMessage({ content: html, flavor }); } diff --git a/system.json b/system.json index c27a854..fec8891 100644 --- a/system.json +++ b/system.json @@ -18,8 +18,8 @@ "version": "dev", "compatibility": { "minimum": "13", - "verified": "13", - "maximum": "13" + "verified": "14", + "maximum": "14" }, "flags": { "hotReload": { @@ -203,10 +203,41 @@ "secondaryTokenAttribute": "wp", "documentTypes": { "Actor": { - "agent": {}, - "unnatural": {}, - "npc": {}, - "vehicle": {} + "agent": { + "htmlFields": ["physical.description"] + }, + "unnatural": { + "htmlFields": ["notes"] + }, + "npc": { + "htmlFields": ["notes"] + }, + "vehicle": { + "htmlFields": ["description"] + } + }, + "Item": { + "weapon": { + "htmlFields": ["description"] + }, + "armor": { + "htmlFields": ["description"] + }, + "motivation": { + "htmlFields": ["description"] + }, + "bond": { + "htmlFields": ["description"] + }, + "gear": { + "htmlFields": ["description"] + }, + "tome": { + "htmlFields": ["description", "handlerNotes"] + }, + "ritual": { + "htmlFields": ["description", "handlerNotes"] + } } } } diff --git a/template.json b/template.json deleted file mode 100644 index 68dc905..0000000 --- a/template.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "Item": { - "types": [ - "weapon", - "armor", - "motivation", - "bond", - "gear", - "tome", - "ritual" - ], - "templates": { - "base": { - "name": "", - "description": "" - } - }, - "weapon": { - "templates": ["base"], - "skill": "", - "skillModifier": 0, - "customSkillTarget": 50, - "range": "10M", - "damage": "1D8", - "armorPiercing": 0, - "lethality": 0, - "isLethal": false, - "killRadius": "N/A", - "ammo": "", - "expense": "Standard", - "equipped": true - }, - "armor": { - "templates": ["base"], - "protection": 3, - "equipped": true, - "expense": "Standard" - }, - "motivation": { - "templates": ["base"], - "disorder": "", - "crossedOut": false, - "disorderCured": false - }, - "bond": { - "templates": ["base"], - "score": 10, - "relationship": "?", - "hasBeenDamagedSinceLastHomeScene": false - }, - "gear": { - "templates": ["base"], - "equipped": true, - "expense": "Standard" - }, - "tome": { - "templates": ["base"], - "language": "", - "studyTime": "", - "unnaturalSkillIncrease": 5, - "occultSkillIncrease": 3, - "sanity": { - "notes": "", - "failedLoss": "1D6", - "successLoss": "1D4" - }, - "handlerNotes": "", - "revealed": false - }, - "ritual": { - "templates": ["base"], - "studyTime": "", - "sanity": { - "notes": "", - "failedLoss": "1D10", - "successLoss": "0" - }, - "learnedSanity": { - "notes": "", - "failedLoss": "1D10", - "successLoss": "0" - }, - "unnaturalSkillIncrease": 1, - "activationCosts": "", - "activationTime": "", - "complexity": "Simple", - "handlerNotes": "", - "revealed": false - } - } -} diff --git a/templates/actor/parts/about-tab.html b/templates/actor/parts/about-tab.html index c2f07b5..607354c 100644 --- a/templates/actor/parts/about-tab.html +++ b/templates/actor/parts/about-tab.html @@ -3,31 +3,32 @@ data-tab="about">
-
-
- - {{localize 'DG.About.OnlineHelp'}} - -
-
- - {{localize 'DG.About.OnlineBugTracker'}} - -
-
- - {{localize 'DG.About.Changelog'}} - -
-
-

{{localize 'DG.About.Copyright'}}

-

{{{localize 'DG.About.License'}}}

-
+ + +
diff --git a/templates/roll/percentile-roll.hbs b/templates/roll/percentile-roll.hbs index 1c83e39..cef8a41 100644 --- a/templates/roll/percentile-roll.hbs +++ b/templates/roll/percentile-roll.hbs @@ -1,18 +1,20 @@ -
+
{{resultString}}
-
-
-
- {{formula}} - {{total}} -
-
    -
  1. {{total}}
  2. -
-
-
+
+
+
+
+ {{formula}} + {{total}} +
+
    +
  1. {{total}}
  2. +
+
+
+

{{total}}

@@ -27,4 +29,4 @@
{{/if}} -
\ No newline at end of file +