diff --git a/lang/en.json b/lang/en.json index 9ee6b6a..2452916 100644 --- a/lang/en.json +++ b/lang/en.json @@ -172,6 +172,7 @@ "dblclick-open": "Double-Click to edit", "dice-roller": "Dice Roller", "dice-roller-hint": "Opens the dice roll dialog if a character is attached to the user.", + "drag-apply": "Drag onto Actors or Story Window to apply", "drop-actors": "Drop actors here.", "edit": "Edit", "error-burning-tag": "There was an error trying to burn your tag. Please see the console for more information.", diff --git a/lang/no.json b/lang/no.json index f3f456b..8e9bde1 100644 --- a/lang/no.json +++ b/lang/no.json @@ -172,6 +172,7 @@ "dblclick-open": "Dobbelklikk for å åpne", "dice-roller": "Terningkast", "dice-roller-hint": "Åpner terningkast-vinduet for denne karakteren.", + "drag-apply": "Dra til en aktør eller Merke-vinduet for å legge til.", "drop-actors": "Dra aktører hit", "edit": "Rediger", "error-burning-tag": "Det oppstod en feil under brenning av merket. Se konsollen for mer informasjon.", diff --git a/scripts/actor/character/character-sheet.js b/scripts/actor/character/character-sheet.js index 9c5a491..50e765a 100644 --- a/scripts/actor/character/character-sheet.js +++ b/scripts/actor/character/character-sheet.js @@ -1,5 +1,6 @@ import { SheetMixin } from "../../mixins/sheet-mixin.js"; import { confirmDelete, dispatch } from "../../utils.js"; +import { localize as t } from "../../utils.js"; export class CharacterSheet extends SheetMixin(ActorSheet) { static defaultOptions = foundry.utils.mergeObject(ActorSheet.defaultOptions, { @@ -14,7 +15,8 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { #dragAvatarTimeout = null; #notesEditorOpened = false; - #focusedTags = null; + #tagsFocused = null; + #tagsHovered = false; #themeHovered = null; #contextmenu = null; #roll = game.litm.LitmRollDialog.create({ @@ -134,7 +136,8 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { backpack, note, themes, - tagsFocused: this.#focusedTags, + tagsFocused: this.#tagsFocused, + tagsHovered: this.#tagsHovered, themeHovered: this.#themeHovered, notesEditorOpened: this.#notesEditorOpened, rollTags: this.#roll.characterTags, @@ -160,6 +163,7 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { .on("mousedown", this.#onDragHandleMouseDown.bind(this)); html.on("mouseover", (event) => { html.find(".litm--character-theme").removeClass("hovered"); + html.find(".litm--character-story-tags").removeClass("hovered"); const t = event.target.classList.contains("litm--character-theme") ? event.target @@ -167,6 +171,10 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { if (t) this.#themeHovered = t.dataset.id; else this.#themeHovered = null; + + if (event.target.closest(".litm--character-story-tags")) + this.#tagsHovered = true; + else this.#tagsHovered = false; }); this.#contextmenu = ContextMenu.create( @@ -210,6 +218,33 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { return super._updateObject(event, cleaned); } + async _onDrop(dragEvent) { + const dragData = dragEvent.dataTransfer.getData("text/plain"); + const data = JSON.parse(dragData); + + // Handle dropping tags and statuses + if (!["tag", "status"].includes(data.type)) return; + + await this.actor.createEmbeddedDocuments("ActiveEffect", [ + { + name: data.name, + flags: { + litm: { + type: data.type, + values: data.values, + isBurnt: data.isBurnt, + }, + }, + }, + ]); + + game.litm.storyTags.render(); + dispatch({ + app: "story-tags", + type: "render", + }); + } + // Prevent dropping more than 4 themes on the character sheet async _onDropItem(event, data) { const item = await Item.implementation.fromDropData(data); @@ -267,6 +302,9 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { const id = t.dataset.id; switch (action) { + case "add-tag": + this.#addTag(); + break; case "increase": this.#increase(event); break; @@ -288,9 +326,9 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { switch (action) { case "return": - this.#focusedTags = null; + this.#tagsFocused = null; t.classList.remove("focused"); - t.style.cssText = this.#focusedTags; + t.style.cssText = this.#tagsFocused; break; } } @@ -305,6 +343,11 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { event.stopPropagation(); this.#decrease(event); break; + case "remove-effect": + event.preventDefault(); + event.stopPropagation(); + this.#removeEffect(t.dataset.id); + break; } } @@ -346,6 +389,27 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { $(document).on("mouseup", handleMouseUp); } + async #addTag() { + await this.actor.createEmbeddedDocuments("ActiveEffect", [ + { + name: t("Litm.ui.name-tag"), + flags: { + litm: { + type: "tag", + values: new Array(6).fill(false), + isBurnt: false, + }, + }, + }, + ]); + + game.litm.storyTags.render(); + dispatch({ + app: "story-tags", + type: "render", + }); + } + async #removeItem(id) { const item = this.items.get(id); if (!(await confirmDelete(`TYPES.Item.${item.type}`))) return; @@ -353,6 +417,19 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { return item.delete(); } + async #removeEffect(id) { + const effect = this.actor.effects.get(id); + if (!(await confirmDelete())) return; + + await effect.delete(); + + game.litm.storyTags.render(); + dispatch({ + app: "story-tags", + type: "render", + }); + } + async #increase(event) { const t = event.currentTarget; const attrib = t.dataset.id; @@ -426,10 +503,11 @@ export class CharacterSheet extends SheetMixin(ActorSheet) { const t = event.currentTarget; t.classList.add("focused"); - const listener = t.addEventListener("mouseup", () => { - this.#focusedTags = t.style.cssText; + const listener = () => { + this.#tagsFocused = t.style.cssText; t.removeEventListener("mouseup", listener); - }); + }; + t.addEventListener("mouseup", listener); } async #handleUpdateEmbeddedItems(formData) { diff --git a/scripts/apps/roll-dialog.js b/scripts/apps/roll-dialog.js index 7c86563..bed6567 100644 --- a/scripts/apps/roll-dialog.js +++ b/scripts/apps/roll-dialog.js @@ -1,5 +1,5 @@ import { Sockets } from "../system/sockets.js"; -import { localize as t, sortTags } from "../utils.js"; +import { sortTags, localize as t } from "../utils.js"; export class LitmRollDialog extends FormApplication { static get defaultOptions() { @@ -209,9 +209,11 @@ export class LitmRollDialog extends FormApplication { ...tag, state: this.#tagState.find((t) => t.id === tag.id)?.state || "", states: - tag.type === "tag" ? ",negative,positive,burned" : ",negative,positive", + tag.type === "tag" + ? ",negative,positive,burned" + : ",negative,positive", })) - .filter(tag => game.user.isGM || tag.state !== ""); + .filter((tag) => game.user.isGM || tag.state !== ""); } get totalPower() { @@ -369,8 +371,8 @@ export class LitmRollDialog extends FormApplication { const tags = LitmRollDialog.#filterTags(data.tags); const { totalPower } = LitmRollDialog.#calculateTotalPower(tags); const recipients = Object.entries(this.actor.ownership) - .filter(u => u[1] === 3 && u[0] !== 'default') - .map(u => u[0]) + .filter((u) => u[1] === 3 && u[0] !== "default") + .map((u) => u[0]); ChatMessage.create({ content: await renderTemplate( diff --git a/scripts/mixins/sheet-mixin.js b/scripts/mixins/sheet-mixin.js index f04561a..9f65ffd 100644 --- a/scripts/mixins/sheet-mixin.js +++ b/scripts/mixins/sheet-mixin.js @@ -106,15 +106,21 @@ export const SheetMixin = (Base) => event.originalEvent.type === "pointerdown" ? ["pointermove", "pointerup"] : ["mousemove", "mouseup"]; + const el = this.element; let previousX = event.screenX; let delta = 0; + const clampValue = (current, delta) => { + const value = current + delta / 500; + return Math.max(0.3, Math.min(3, value)); + }; + const mousemove = (event) => { delta = event.screenX - previousX; previousX = event.screenX; - this.#currentScale += delta / 500; + this.#currentScale = clampValue(this.#currentScale, delta); el.css("transform", `scale(${this.#currentScale})`); }; diff --git a/scripts/system/enrichers.js b/scripts/system/enrichers.js index 747280f..09bc60b 100644 --- a/scripts/system/enrichers.js +++ b/scripts/system/enrichers.js @@ -30,6 +30,7 @@ export class Enrichers { } static #enrichTags() { + const tooltip = game.i18n.localize("Litm.ui.drag-apply"); const enrichTags = ([_text, tag, status]) => { if (tag.startsWith("-")) return $( @@ -39,9 +40,11 @@ export class Enrichers { )[0]; if (tag && status) return $( - `${tag}-${status}`, + `${tag}-${status}`, )[0]; - return $(`${tag}`)[0]; + return $( + `${tag}`, + )[0]; }; CONFIG.TextEditor.enrichers.push({ pattern: CONFIG.litm.tagStringRe, diff --git a/scripts/system/handlebars.js b/scripts/system/handlebars.js index b3b23d2..8331a70 100644 --- a/scripts/system/handlebars.js +++ b/scripts/system/handlebars.js @@ -12,7 +12,7 @@ export class HandlebarsHelpers { Handlebars.registerHelper("includes", (array, value, path) => Array.isArray(array) ? (path && array.some((i) => i[path] === value)) || - array.includes(value) + array.includes(value) : false, ); @@ -38,8 +38,8 @@ export class HandlebarsHelpers { tag.isActive ? "Litm.tags.isActive" : readonly - ? "Litm.tags.isInactive" - : "Litm.tags.activate", + ? "Litm.tags.isInactive" + : "Litm.tags.activate", ); } } diff --git a/scripts/system/hooks.js b/scripts/system/hooks.js index 86c2284..c07d310 100644 --- a/scripts/system/hooks.js +++ b/scripts/system/hooks.js @@ -1,5 +1,5 @@ import { error, info } from "../logger.js"; -import { localize as t, sleep } from "../utils.js"; +import { sleep, localize as t } from "../utils.js"; import { Sockets } from "./sockets.js"; export class LitmHooks { @@ -231,7 +231,8 @@ export class LitmHooks { const createEffect = ([key, effect], category) => ({ name: `${t(category)}: ${t(`Litm.effects.${key}.key`)}`, icon: ``, - condition: (li) => li.find("[data-type='tracked']").length, + condition: (li) => + li.find("[data-type='tracked']:not([data-result='failure'])").length, callback: () => { ChatMessage.create({ content: `
@@ -302,7 +303,7 @@ export class LitmHooks { actorLink: true, disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY, texture: { src: tokenImg || img }, - } + } : null; actor.updateSource({ prototypeToken, img }); }); diff --git a/styles/actor/character.css b/styles/actor/character.css index 560c83c..239ed39 100644 --- a/styles/actor/character.css +++ b/styles/actor/character.css @@ -400,6 +400,9 @@ & .litm--character-story-tags { position: absolute; + margin: 0px; + padding: 0px; + list-style: none; top: 0.625rem; right: -21.875rem; rotate: 30deg; @@ -414,7 +417,8 @@ &:hover, &:focus-within, - &.focused { + &.focused, + &.hovered { display: flex; flex-direction: column; pointer-events: all; @@ -486,14 +490,31 @@ } } + & button { + background: none; + border: none; + margin: 0px; + padding: 0px; + position: relative; + font-family: var(--litm-font-accent); + color: var(--litm-color); + + & span { + position: absolute; + top: 2rem; + width: 55%; + left: 2.5rem; + } + } + & .litm--story-tag-values { display: flex; flex-wrap: nowrap; align-items: center; - margin-block-start: 13px; - margin-inline-start: -10px; - gap: 8.5px; - + margin-block-start: 9px; + margin-inline-start: -8px; + gap: 8.2px; + rotate: -1deg; & .litm--story-tag-value { position: relative; @@ -505,7 +526,6 @@ font-family: var(--litm-font-primary); color: color-mix(in hsl, var(--litm-color) 70%, transparent); font-size: var(--font-size-14); - } } diff --git a/styles/apps/story-tags.css b/styles/apps/story-tags.css index d956445..c77b4c5 100644 --- a/styles/apps/story-tags.css +++ b/styles/apps/story-tags.css @@ -48,7 +48,7 @@ & hr { border: none; - height: 18px; + min-height: 16px; background: url(../../assets/media/separator.webp) no-repeat center / contain; width: 95%; } @@ -73,6 +73,8 @@ background-position: left; background-size: cover; color: var(--litm-color-primary-bg); + font-size: var(--font-size-16); + line-height: var(--font-size-16); & img { aspect-ratio: 1/1; @@ -117,21 +119,16 @@ background: transparent; border: none; font-family: var(--litm-font-text); + font-size: var(--font-size-15); color: var(--litm-color-primary); min-width: 10px; - - &.status { - text-indent: 24px; - } + padding: 0px; } & .litm--burn-label { - line-height: 1; - height: var(--font-size-14); - + height: var(--font-size-18); & .litm--burn { height: var(--font-size-18); - margin: 0px; } } @@ -155,8 +152,8 @@ cursor: pointer; margin: 0; padding: 0; - width: 0.8em; - height: 0.8em; + width: 0.9em; + height: 0.9em; border-radius: 4px; border: 1px solid var(--litm-color); diff --git a/styles/chat/message.css b/styles/chat/message.css index 09a6f29..b323aa9 100644 --- a/styles/chat/message.css +++ b/styles/chat/message.css @@ -47,8 +47,11 @@ } &.positive { - color: var(--litm-color-status-bg); + color: color-mix(in hsl, var(--litm-color-status-bg), lightgreen); + } + &.warning { + color: color-mix(in hsl, var(--litm-color-tag-bg), yellow); } &.negative { diff --git a/styles/components.css b/styles/components.css index ee74760..fdc8926 100644 --- a/styles/components.css +++ b/styles/components.css @@ -85,8 +85,9 @@ margin: 0; font: inherit; color: currentColor; + aspect-ratio: 5/6; height: 1.5em; - width: 1.2em; + width: unset; background: url('../assets/media/burn.svg') no-repeat; background-size: contain; background-position: center; @@ -200,8 +201,20 @@ text-align: center; } -/* Custom Elements */ +:where(.litm--red-leaf) { + filter: hue-rotate(-25deg); +} +:where(.litm--green-leaf) { + filter: hue-rotate(45deg); + + /* For some reason filters bug out inputs */ + & +* input { + filter: hue-rotate(0deg); + } +} + +/* Custom Elements */ litm-toggled-input { display: block; flex: 1; diff --git a/styles/root.css b/styles/root.css index 944098f..d5352a9 100644 --- a/styles/root.css +++ b/styles/root.css @@ -1,4 +1,12 @@ -:root { +/* Font smooth only on macOS */ +@media screen and (-webkit-min-device-pixel-ratio: 0) { + html { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} + +body { --litm-color-bg: hsl(40, 85%, 87%); --litm-color: hsl(40, 27%, 24%); --litm-color-alt-bg: hsl(34, 34%, 82%); @@ -40,6 +48,9 @@ --color-border-highlight: var(--litm-color-accent-bg); --color-border-highlight-alt: var(--litm-color-accent-2); --color-text-hyperlink: var(--litm-color-accent-3); + --color-level-success: rgba(26, 107, 34, 0.8); + --color-level-error: rgba(105, 0, 8, 0.8); + --color-level-warning: rgba(214, 150, 0, 0.8); } diff --git a/system.json b/system.json index 8b8f898..204f9ac 100644 --- a/system.json +++ b/system.json @@ -13,12 +13,8 @@ "ko-fi": "amediocredad" } ], - "esmodules": [ - "litm.js" - ], - "styles": [ - "litm.css" - ], + "esmodules": ["litm.js"], + "styles": ["litm.css"], "languages": [ { "lang": "cn", @@ -64,19 +60,8 @@ ], "flags": { "hotReload": { - "extensions": [ - "css", - "html", - "js", - "json" - ], - "paths": [ - "styles", - "templates", - "lang", - "litm.css", - "litm.js" - ] + "extensions": ["css", "html", "js", "json"], + "paths": ["styles", "templates", "lang", "litm.css", "litm.js"] } }, "relationships": { diff --git a/templates/actor/character.html b/templates/actor/character.html index c46cfd5..3026c27 100644 --- a/templates/actor/character.html +++ b/templates/actor/character.html @@ -1,78 +1,104 @@ {{#*inline 'leaf' data}} -
  • - +
    -
  • {{/inline}}
    - {{name}} + {{name}} - +
    {{localize 'Notes'}} -
    {{editor note target="system.note" owner=owner button=true editable=true}}
    {{#if backpack.id}} -
    {{> systems/litm/templates/item/backpack-ro.html backpack=backpack}}
    {{else}}
    - Soft illustration of a rustic backpack
    {{/if}}
    {{#each themes as |item|}} -
    {{> systems/litm/templates/item/theme-ro.html data=item.data}}
    {{/each}}
    - +
    \ No newline at end of file diff --git a/templates/chat/message-tooltip.html b/templates/chat/message-tooltip.html index d9c084e..7980103 100644 --- a/templates/chat/message-tooltip.html +++ b/templates/chat/message-tooltip.html @@ -2,7 +2,8 @@
    {{name}} - {{#if flavor}}{{flavor}}{{/if}} + {{#if flavor}}{{flavor}}{{/if}} {{value}}
    @@ -14,7 +15,8 @@
    {{this.formula}} - {{#if this.flavor}}{{this.flavor}}{{/if}} + {{#if this.flavor}}{{this.flavor}}{{/if}} {{this.total}}
      @@ -29,13 +31,13 @@ {{> section name=tag.name value=3 flavor=(localize 'Litm.tags.isBurnt') flavorClass="burned"}} {{/each}} {{#each data.powerTags as |tag|}} - {{> section name=tag.name value=1}} + {{> section name=tag.name value=1 flavor=(ifThen (eq tag.type 'storyTag') (localize "Litm.other.tag") "") flavorClass=(ifThen (eq tag.type "storyTag") "warning" "")}} {{/each}} {{#if data.mitigate}} {{> section name=(localize 'Litm.effects.mitigate.key') value=1}} {{/if}} {{#each data.weaknessTags as |tag|}} - {{> section name=tag.name value=-1 flavor=(ifThen (eq tag.type 'weaknessTag') (localize 'Litm.tags.weakness') '') flavorClass="negative"}} + {{> section name=tag.name value=-1 flavor=(ifThen (eq tag.type 'weaknessTag') (localize 'Litm.tags.weakness') (localize 'Litm.other.tag')) flavorClass=(ifThen (eq tag.type 'weaknessTag') "negative" "warning")}} {{/each}} {{#each data.positiveStatuses as |tag|}} {{> section name=tag.name value=tag.value flavor=(localize 'Litm.other.status') flavorClass="positive"}} diff --git a/templates/chat/message.html b/templates/chat/message.html index b1f441a..f937aee 100644 --- a/templates/chat/message.html +++ b/templates/chat/message.html @@ -1,10 +1,12 @@ -
      +
      {{flavor}}
      {{#if effect}}

      {{localize effect.description}}

      {{localize effect.action}}

      -

      {{localize 'Litm.other.cost'}}: {{localize effect.cost}}

      +

      {{localize 'Litm.other.cost'}}: + {{localize effect.cost}}

      {{else}}
      @@ -18,16 +20,24 @@ {{{tooltip}}}

      {{#unless (eq type 'mitigate')}}{{localize outcome.label}}{{/unless}} - {{#unless (eq type 'quick')}}{{power}} {{localize 'Litm.tags.power'}}{{/unless}} + {{#unless (eq type 'quick')}}{{power}} + {{localize 'Litm.tags.power'}}{{/unless}}

      {{#if (eq type 'tracked')}} + {{#if (gt total 6)}} +

      + {{{localize "Litm.ui.roll-tracked-hint"}}} +

      + {{/if}} {{#if (gt total 9)}} -

      {{localize 'Litm.ui.roll-tracked-success'}}

      +

      + {{localize 'Litm.ui.roll-tracked-success'}} +

      {{/if}} -

      {{{localize "Litm.ui.roll-tracked-hint"}}}

      {{/if}} {{#if (and isOwner hasBurnedTags)}} - + {{/if}} {{#if (and isOwner hasWeaknessTags)}}