diff --git a/public/lang/cs.json b/public/lang/cs.json index c22b7d62e..574566abc 100644 --- a/public/lang/cs.json +++ b/public/lang/cs.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "Důkladný odpočinek", "T5EK.HitDiceRollAverage": "Right Click: Average", - "T5EK.Journal": "Deník", + "T5EK.JournalTabName": "Deník", "T5EK.RestoreOnRest": "Obnovit při odpočinku", diff --git a/public/lang/de.json b/public/lang/de.json index 6ea66220f..60646dd40 100644 --- a/public/lang/de.json +++ b/public/lang/de.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "Lange Rast", "T5EK.HitDiceRollAverage": "Rechtsklick: Durchschnitt", - "T5EK.Journal": "Tagebuch", + "T5EK.JournalTabName": "Tagebuch", "T5EK.RestoreOnRest": "Bei Rast regenerieren", diff --git a/public/lang/en.json b/public/lang/en.json index 6372a22af..0f4b95e35 100644 --- a/public/lang/en.json +++ b/public/lang/en.json @@ -33,7 +33,18 @@ "T5EK.LongRest": "Long Rest", "T5EK.HitDiceRollAverage": "right click: apply average", - "T5EK.Journal": "Journal", + "T5EK.JournalTabName": "Journal", + + "T5EK.Actions": { + "TabName": "Actions", + "OverriddenSetOverrideFalse": "Remove from Actions List (Shift+Click to clear override)", + "OverriddenSetOverrideTrue": "Add to Actions List (Shift+Click to clear override)", + "SetOverrideFalse": "Remove from Actions List", + "SetOverrideTrue": "Add to Actions List", + "ClearOverride": "Clear Action Override" + }, + + "T5EK.HitDC": "Hit / DC", "T5EK.RestoreOnRest": "Restore on rest", @@ -177,6 +188,9 @@ "labelInventoryLocks": "Inventory Locks", "labelFeaturesLocks": "Features Locks" }, + "T5EK.Settings.TabFeatures": { + "tabLabel": "Features" + }, "T5EK.Settings.TabInfo": { "tabLabel": "Info", "Header": "Info", @@ -440,6 +454,23 @@ "name": "Lock Item Quantity", "hint": "Prevents non-GMs from making changes to item quantity." }, + "T5EK.Settings.ActionsList.Header": "Actions List", + "T5EK.Settings.ActionsListLimitActionsToCantrips": { + "name": "Limit Actions to Cantrips", + "hint": "Instead of showing all spells that deal damage in the Actions tab/panel by default, limits to only cantrips. This is the default D&DBeyond behavior." + }, + "T5EK.Settings.ActionsListIncludeMinuteLongSpellsAsActions": { + "name": "Include Minute-long Spells as Actions", + "hint": "Includes spells with a duration of one minute or less (e.g. 1 round) and an activation time of 1 Action or 1 Bonus Action (e.g. Bless, Bane, Command) in the Actions tab/panel by default." + }, + "T5EK.Settings.ActionsListIncludeSpellsWithActiveEffects": { + "name": "Include Spells with Active Effects as Actions", + "hint": "Includes spells with active effects attached (e.g. Barkskin) in the Actions tab/panel by default." + }, + "T5EK.Settings.ActionsListIncludeConsumables": { + "name": "Include Consumables as Actions", + "hint": "Includes consumables which have an activation cost (Action, Bonus Action, etc) in the Actions list by default." + }, "T5EK.Settings.ColorPickerEnabled": { "name": "Use Custom Theme Colors", "hint": "Shows custom theme colors" diff --git a/public/lang/es.json b/public/lang/es.json index fae27ca23..bc82e8ffc 100644 --- a/public/lang/es.json +++ b/public/lang/es.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "Descanso largo", "T5EK.HitDiceRollAverage": "Right Click: Average", - "T5EK.Journal": "Diario", + "T5EK.JournalTabName": "Diario", "T5EK.RestoreOnRest": "Recuperar tras descanso", diff --git a/public/lang/fr.json b/public/lang/fr.json index 0793a35f4..c2301e849 100644 --- a/public/lang/fr.json +++ b/public/lang/fr.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "Repos Long", "T5EK.HitDiceRollAverage": "Right Click: Average", - "T5EK.Journal": "Journal", + "T5EK.JournalTabName": "Journal", "T5EK.RestoreOnRest": "Restaurer lors d'un repos", diff --git a/public/lang/hu.json b/public/lang/hu.json index 98909a3c0..308131097 100644 --- a/public/lang/hu.json +++ b/public/lang/hu.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "Hosszú Pihenő", "T5EK.HitDiceRollAverage": "Jobb Klikk: Átlag", - "T5EK.Journal": "Napló", + "T5EK.JournalTabName": "Napló", "T5EK.RestoreOnRest": "Pihenéskor visszaáll", diff --git a/public/lang/it.json b/public/lang/it.json index 967ecad3e..df3252e2e 100644 --- a/public/lang/it.json +++ b/public/lang/it.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "Riposo Lungo", "T5EK.HitDiceRollAverage": "Right Click: Average", - "T5EK.Journal": "Diario", + "T5EK.JournalTabName": "Diario", "T5EK.RestoreOnRest": "Ripristina dopo un riposo", diff --git a/public/lang/ja.json b/public/lang/ja.json index 1393cc869..5de83d35c 100644 --- a/public/lang/ja.json +++ b/public/lang/ja.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "大休憩", "T5EK.HitDiceRollAverage": "右クリック:平均", - "T5EK.Journal": "記録", + "T5EK.JournalTabName": "記録", "T5EK.RestoreOnRest": "休憩時に回復", diff --git a/public/lang/ko.json b/public/lang/ko.json index 2df1fdd86..47d5a17e9 100644 --- a/public/lang/ko.json +++ b/public/lang/ko.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "긴 휴식", "T5EK.HitDiceRollAverage": "우클릭: 평균", - "T5EK.Journal": "저널", + "T5EK.JournalTabName": "저널", "T5EK.RestoreOnRest": "휴식시 복원", diff --git a/public/lang/pt-BR.json b/public/lang/pt-BR.json index 8d1ea1e78..42eb44b3e 100644 --- a/public/lang/pt-BR.json +++ b/public/lang/pt-BR.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "D. Longo", "T5EK.HitDiceRollAverage": "Right Click: Average", - "T5EK.Journal": "Diário", + "T5EK.JournalTabName": "Diário", "T5EK.RestoreOnRest": "Restaurar no Descanso", diff --git a/public/lang/zh-tw.json b/public/lang/zh-tw.json index 17d38ab30..736cb309d 100644 --- a/public/lang/zh-tw.json +++ b/public/lang/zh-tw.json @@ -33,7 +33,7 @@ "T5EK.LongRest": "長休", "T5EK.HitDiceRollAverage": "Right Click: Average", - "T5EK.Journal": "日誌", + "T5EK.JournalTabName": "日誌", "T5EK.RestoreOnRest": "休息時恢復", diff --git a/src/actions/actions.ts b/src/actions/actions.ts new file mode 100644 index 000000000..0bf67e6bf --- /dev/null +++ b/src/actions/actions.ts @@ -0,0 +1,235 @@ +import { CONSTANTS } from 'src/constants'; +import { FoundryAdapter } from 'src/foundry/foundry-adapter'; +import { SettingsProvider } from 'src/settings/settings'; +import type { Item5e } from 'src/types/item'; +import type { Actor5e, ActorActions } from 'src/types/types'; +import { debug, error } from 'src/utils/logging'; + +export type ActionSets = { + action: Set; + bonus: Set; + crew: Set; + lair: Set; + legendary: Set; + mythic: Set; + special: Set; + reaction: Set; + other: Set; +}; + +const itemTypeSortValues: Record = { + weapon: 1, + equipment: 2, + feat: 3, + spell: 4, + consumable: 5, + tool: 6, + backpack: 7, + class: 8, + loot: 9, +}; + +export function getActorActions(actor: Actor5e): ActorActions { + const filteredItems: any[] = actor.items + .filter(isItemInActionList) + .sort((a: Item5e, b: Item5e) => { + if (a.type !== b.type) { + return itemTypeSortValues[a.type] - itemTypeSortValues[b.type]; + } + if (a.type === 'spell' && b.type === 'spell') { + return a.system.level - b.system.level; + } + return (a.sort || 0) - (b.sort || 0); + }) + .map((item: Item5e) => { + if (item.labels) { + item.labels.type = FoundryAdapter.localize( + `ITEM.Type${item.type.titleCase()}` + ); + } + + // removes any in-formula flavor text from the formula in the label + if (item.labels?.derivedDamage?.length) { + item.labels.derivedDamage = item.labels.derivedDamage.map( + ({ formula, ...rest }: any) => ({ + formula: formula?.replace(/\[.+?\]/, '') || '0', + ...rest, + }) + ); + } + return item; + }); + + const initial: ActionSets = { + action: new Set(), + bonus: new Set(), + crew: new Set(), + lair: new Set(), + legendary: new Set(), + reaction: new Set(), + other: new Set(), + mythic: new Set(), + special: new Set(), + }; + const actionsData = filteredItems.reduce((acc, item) => { + try { + if (['backpack', 'tool'].includes(item.type)) { + return acc; + } + + const activationType = getActivationType(item.system.activation?.type); + acc[activationType].add(item); + return acc; + } catch (e) { + error('error trying to digest item', true, { name: item.name, e }); + return acc; + } + }, initial); + return actionsData; +} + +export function isItemInActionList(item: Item5e): boolean { + // check our override + + const override = FoundryAdapter.tryGetFlag( + item, + 'action-filter-override' + ); + + if (override !== undefined && override !== null) { + return override; + } + + // perform normal filtering logic + switch (item.type) { + case 'weapon': { + return item.system.equipped; + } + case 'equipment': { + return item.system.equipped && isActiveItem(item.system.activation?.type); + } + case 'consumable': { + return ( + SettingsProvider.settings.actionListIncludeConsumables.get() && + isActiveItem(item.system.activation?.type) + ); + } + case 'spell': { + const limitToCantrips = + SettingsProvider.settings.actionListLimitActionsToCantrips.get(); + + // only exclude spells which need to be prepared but aren't + const notPrepared = + item.system.preparation?.mode === 'prepared' && + !item.system.preparation?.prepared; + const isCantrip = item.system.level === 0; + if (!isCantrip && (limitToCantrips || notPrepared)) { + return false; + } + const isReaction = item.system.activation?.type === 'reaction'; + const isBonusAction = item.system.activation?.type === 'bonus'; + + //ASSUMPTION: If the spell causes damage, it will have damageParts + const isDamageDealer = item.system.damage?.parts?.length > 0; + let shouldInclude = isReaction || isBonusAction || isDamageDealer; + if ( + SettingsProvider.settings.actionListIncludeMinuteLongSpellsAsActions.get() + ) { + const isOneMinuter = + item.system?.duration?.units === 'minute' && + item.system?.duration?.value === 1; + const isOneRounder = + item.system?.duration?.units === 'round' && + item.system?.duration?.value === 1; + shouldInclude = shouldInclude || isOneMinuter || isOneRounder; + } + if ( + SettingsProvider.settings.actionListIncludeSpellsWithActiveEffects.get() + ) { + const hasEffects = !!item.effects.size; + shouldInclude = shouldInclude || hasEffects; + } + return shouldInclude; + } + case 'feat': { + return !!item.system.activation?.type; + } + default: { + return false; + } + } +} + +function getActivationType(activationType: string) { + switch (activationType) { + case 'action': + case 'bonus': + case 'crew': + case 'lair': + case 'legendary': + case 'mythic': + case 'special': + case 'reaction': + return activationType; + default: + return 'other'; + } +} + +function isActiveItem(activationType: string) { + if (!activationType) { + return false; + } + if (['minute', 'hour', 'day', 'none'].includes(activationType)) { + return false; + } + return true; +} + +export const damageTypeIconMap: Record = { + acid: '', + bludgeoning: '', + cold: '', + fire: '', + force: '', + lightning: '', + necrotic: '', + piercing: '', + poison: '', + psychic: '', + radiant: '', + slashing: '', + thunder: '', + healing: '', + temphp: '', +}; + +export function actorUsesActionFeature(actor: Actor5e) { + const selectedTabIds = FoundryAdapter.tryGetFlag( + actor, + 'selected-tabs' + ); + + if (selectedTabIds) { + return selectedTabIds.includes(CONSTANTS.TAB_ACTOR_ACTIONS); + } + + const defaultTabIds = + actor.type === CONSTANTS.SHEET_TYPE_CHARACTER + ? SettingsProvider.settings.defaultCharacterSheetTabs.get() + : actor.type === CONSTANTS.SHEET_TYPE_NPC + ? SettingsProvider.settings.defaultNpcSheetTabs.get() + : actor.type === CONSTANTS.SHEET_TYPE_VEHICLE + ? SettingsProvider.settings.defaultVehicleSheetTabs.get() + : []; + + return defaultTabIds.includes(CONSTANTS.TAB_ACTOR_ACTIONS); +} + +export function toggleActionFilterOverride(item: Item5e) { + FoundryAdapter.setFlag( + item, + 'action-filter-override', + !isItemInActionList(item) + ); +} diff --git a/src/applications/sheet-settings/SheetSettings.svelte b/src/applications/sheet-settings/SheetSettings.svelte index 020441657..2768cae29 100644 --- a/src/applications/sheet-settings/SheetSettings.svelte +++ b/src/applications/sheet-settings/SheetSettings.svelte @@ -7,6 +7,7 @@ import VehicleSettingsTab from './tabs/VehicleSettingsTab.svelte'; import GmOptionsSettingsTab from './tabs/GmOptionsSettingsTab.svelte'; import LockSettingsTab from './tabs/LockSettingsTab.svelte'; + import FeaturesSettingsTab from './tabs/FeaturesSettingsTab.svelte'; import InfoTab from './tabs/InfoTab.svelte'; import { FoundryAdapter } from 'src/foundry/foundry-adapter'; import { getContext } from 'svelte'; @@ -65,6 +66,14 @@ ); } + tabs.push({ + id: CONSTANTS.TAB_SETTINGS_FEATURES, + displayName: 'T5EK.Settings.TabFeatures.tabLabel', + content: { + component: FeaturesSettingsTab, + }, + }); + tabs.push({ id: CONSTANTS.TAB_SETTINGS_INFO, displayName: 'T5EK.Settings.TabInfo.tabLabel', diff --git a/src/applications/sheet-settings/tabs/FeaturesSettingsTab.svelte b/src/applications/sheet-settings/tabs/FeaturesSettingsTab.svelte new file mode 100644 index 000000000..62aa4b38b --- /dev/null +++ b/src/applications/sheet-settings/tabs/FeaturesSettingsTab.svelte @@ -0,0 +1,48 @@ + + +

{localize('T5EK.Settings.ActionsList.Header')}

+ + + + + + + + diff --git a/src/components/item-info-card/ItemInfoCard.svelte b/src/components/item-info-card/ItemInfoCard.svelte index 97cb41227..6aeb2cbc0 100644 --- a/src/components/item-info-card/ItemInfoCard.svelte +++ b/src/components/item-info-card/ItemInfoCard.svelte @@ -8,10 +8,10 @@ import type { ItemCardStore } from 'src/types/types'; import { getContext, onDestroy, onMount } from 'svelte'; import type { Writable } from 'svelte/store'; - import DefaultItemCardContentTemplate from './DefaultItemCardContentTemplate.svelte'; import HorizontalLineSeparator from '../layout/HorizontalLineSeparator.svelte'; import { warn } from 'src/utils/logging'; import { settingStore } from 'src/settings/settings'; + import { getItemCardContentTemplate } from './item-info-card'; // Fix Key let frozen: boolean = false; @@ -99,9 +99,7 @@ } let debug = false; let timer: any; - const defaultContentTemplate: ItemCardContentComponent = - DefaultItemCardContentTemplate; - let infoContentTemplate: ItemCardContentComponent | undefined; + let infoContentTemplate: ItemCardContentComponent | null; $: delayMs = $settingStore.itemCardsDelay ?? 0; async function showCard() { @@ -119,8 +117,7 @@ in case the user has moused away. */ if ($card.item) { - infoContentTemplate = - $card.itemCardContentTemplate ?? defaultContentTemplate; + infoContentTemplate = $card.itemCardContentTemplate; item = $card.item; if ($settingStore.itemCardsAreFloating) { @@ -178,7 +175,7 @@ sheet.addEventListener('mousemove', onMouseMove); } else { warn( - 'Item Card parent sheet not found. Unable to support floating item card.' + 'Item Card parent sheet not found. Unable to support floating item card.', ); } }); @@ -204,7 +201,7 @@ props.push( item.labels.derivedDamage[0].label .replace(' + ', '+') - .replace(' - ', '-') + .replace(' - ', '-'), ); } if (item?.labels?.save) { @@ -229,8 +226,12 @@ >
- {#if !!infoContentTemplate && !!item && !!chatData} - + {#if !!item && !!chatData} + {#if specialProps.length || itemProps.length} {#if specialProps.length} diff --git a/src/components/item-info-card/SpellbookItemCardContent.svelte b/src/components/item-info-card/SpellbookItemCardContent.svelte index 1667aebf0..ef2279f8f 100644 --- a/src/components/item-info-card/SpellbookItemCardContent.svelte +++ b/src/components/item-info-card/SpellbookItemCardContent.svelte @@ -14,9 +14,7 @@ export let chatData: ItemChatData; let context = - getContext< - Readable - >('context'); + getContext>('context'); const localize = FoundryAdapter.localize; diff --git a/src/components/item-info-card/item-info-card.ts b/src/components/item-info-card/item-info-card.ts new file mode 100644 index 000000000..634b1c292 --- /dev/null +++ b/src/components/item-info-card/item-info-card.ts @@ -0,0 +1,25 @@ +import type { Item5e } from 'src/types/item'; +import DefaultItemCardContentTemplate from './DefaultItemCardContentTemplate.svelte'; +import SpellbookItemCardContent from './SpellbookItemCardContent.svelte'; +import InventoryItemCardContent from './InventoryItemCardContent.svelte'; + +export function getItemCardContentTemplate(item: Item5e) { + // TODO: Make item type to Card Content Template mod-able via the API. + switch (item?.type) { + case 'spell': + return SpellbookItemCardContent; + case 'backpack': + case 'equipment': + case 'consumable': + case 'tool': + case 'loot': + return InventoryItemCardContent; + case 'race': + case 'background': + case 'class': + case 'subclass': + case 'feat': + default: + return DefaultItemCardContentTemplate; + } +} diff --git a/src/components/item-list/ItemImage.svelte b/src/components/item-list/ItemImage.svelte index 951bcaa0c..f593f1c2b 100644 --- a/src/components/item-list/ItemImage.svelte +++ b/src/components/item-list/ItemImage.svelte @@ -7,8 +7,8 @@ diff --git a/src/components/item-list/ItemName.svelte b/src/components/item-list/ItemName.svelte index a7873c2f1..db0e34e6b 100644 --- a/src/components/item-list/ItemName.svelte +++ b/src/components/item-list/ItemName.svelte @@ -7,12 +7,14 @@ export let cssClass: string = ''; export let hasChildren = true; export let item: Item5e; + export let useActiveEffectsMarker: boolean = true; $: hasActiveEffects = !!item.effects?.size; const dispatcher = createEventDispatcher<{ toggle: Event }>(); + -{#if $settingStore.showActiveEffectsMarker && hasActiveEffects} +{#if useActiveEffectsMarker && $settingStore.showActiveEffectsMarker && hasActiveEffects} {/if} diff --git a/src/components/item-list/ItemTableCell.svelte b/src/components/item-list/ItemTableCell.svelte index 70b7f8745..4701a3765 100644 --- a/src/components/item-list/ItemTableCell.svelte +++ b/src/components/item-list/ItemTableCell.svelte @@ -38,7 +38,7 @@ flex-shrink: 0; font-size: 0.75rem; font-family: var(--t5ek-body-font-family); - height: 1.5rem; + min-height: 1.5rem; color: var(--t5ek-secondary-color); overflow: hidden; display: flex; diff --git a/src/components/item-list/ItemUseButton.svelte b/src/components/item-list/ItemUseButton.svelte index 6327c99ee..8882f9ebc 100644 --- a/src/components/item-list/ItemUseButton.svelte +++ b/src/components/item-list/ItemUseButton.svelte @@ -7,7 +7,7 @@ export let imgUrlOverride: string | undefined = undefined; const showRoll = getContext>( - CONSTANTS.CONTEXT_GRID_CELL_HOVER + CONSTANTS.CONTEXT_GRID_CELL_HOVER, ); let buttonIsFocused = false; @@ -34,8 +34,9 @@ diff --git a/src/sheets/character/tabs/ActorJournalTab.svelte b/src/sheets/actor/tabs/ActorJournalTab.svelte similarity index 97% rename from src/sheets/character/tabs/ActorJournalTab.svelte rename to src/sheets/actor/tabs/ActorJournalTab.svelte index 513da5f1e..492cb06b5 100644 --- a/src/sheets/character/tabs/ActorJournalTab.svelte +++ b/src/sheets/actor/tabs/ActorJournalTab.svelte @@ -25,7 +25,7 @@
@@ -51,7 +51,7 @@
@@ -77,7 +77,7 @@
@@ -103,7 +103,7 @@
@@ -134,7 +134,7 @@
diff --git a/src/sheets/character/parts/FavoriteFeaturesList.svelte b/src/sheets/character/parts/FavoriteFeaturesList.svelte index 4674da2d9..defdded63 100644 --- a/src/sheets/character/parts/FavoriteFeaturesList.svelte +++ b/src/sheets/character/parts/FavoriteFeaturesList.svelte @@ -14,6 +14,7 @@ import ItemUses from '../../../components/item-list/ItemUses.svelte'; import { getContext } from 'svelte'; import type { Readable } from 'svelte/store'; + import RechargeControl from 'src/components/item-list/controls/RechargeControl.svelte'; let context = getContext>('context'); export let items: Item5e[] = []; @@ -58,17 +59,7 @@ {#if ctx?.isOnCooldown} - + {:else if item.system.recharge?.value} {:else if ctx?.hasUses} diff --git a/src/sheets/character/parts/FavoriteSpellsList.svelte b/src/sheets/character/parts/FavoriteSpellsList.svelte index 84964c920..252f2f006 100644 --- a/src/sheets/character/parts/FavoriteSpellsList.svelte +++ b/src/sheets/character/parts/FavoriteSpellsList.svelte @@ -62,7 +62,6 @@ }} let:toggleSummary cssClass={FoundryAdapter.getSpellRowClasses(spell)} - itemCardContentTemplate={SpellbookItemCardContent} > diff --git a/src/sheets/character/parts/InventoryGrid.svelte b/src/sheets/character/parts/InventoryGrid.svelte index 41345f3da..b5a7eb2c9 100644 --- a/src/sheets/character/parts/InventoryGrid.svelte +++ b/src/sheets/character/parts/InventoryGrid.svelte @@ -38,7 +38,6 @@ async function onMouseEnter(item: Item5e) { card.update((card) => { card.item = item; - card.itemCardContentTemplate = InventoryItemCardContent; return card; }); } @@ -46,7 +45,6 @@ async function onMouseLeave() { card.update((card) => { card.item = null; - card.itemCardContentTemplate = null; return card; }); } diff --git a/src/sheets/character/parts/InventoryList.svelte b/src/sheets/character/parts/InventoryList.svelte index 1f91e0512..8e9d30750 100644 --- a/src/sheets/character/parts/InventoryList.svelte +++ b/src/sheets/character/parts/InventoryList.svelte @@ -12,14 +12,14 @@ import { CONSTANTS } from 'src/constants'; import ItemUses from '../../../components/item-list/ItemUses.svelte'; import ItemAddUses from '../../../components/item-list/ItemAddUses.svelte'; - import ItemControls from '../../../components/item-list/ItemControls.svelte'; + import ItemControls from '../../../components/item-list/controls/ItemControls.svelte'; import ItemDuplicateControl from '../../../components/item-list/controls/ItemDuplicateControl.svelte'; import ItemDeleteControl from '../../../components/item-list/controls/ItemDeleteControl.svelte'; - import ItemEditControl from '../../../components/item-list/ItemEditControl.svelte'; + import ItemEditControl from '../../../components/item-list/controls/ItemEditControl.svelte'; import EquipControl from '../../../components/item-list/controls/EquipControl.svelte'; import AttuneControl from '../../../components/item-list/controls/AttuneControl.svelte'; import InlineFavoriteIcon from '../../../components/item-list/InlineFavoriteIcon.svelte'; - import ItemFavoriteControl from '../../../components/item-list/ItemFavoriteControl.svelte'; + import ItemFavoriteControl from '../../../components/item-list/controls/ItemFavoriteControl.svelte'; import { getContext } from 'svelte'; import type { Readable } from 'svelte/store'; import type { CharacterSheetContext } from 'src/types/types'; @@ -27,6 +27,7 @@ import InventoryItemCardContent from '../../../components/item-info-card/InventoryItemCardContent.svelte'; import AmmoSelector from '../../actor/AmmoSelector.svelte'; import { settingStore } from 'src/settings/settings'; + import ActionFilterOverrideControl from 'src/components/item-list/controls/ActionFilterOverrideControl.svelte'; export let primaryColumnName: string; export let items: Item5e[]; @@ -53,7 +54,7 @@ return FoundryAdapter.getInventoryRowClasses( item, $context.itemContext[item.id], - extras + extras, ); } @@ -94,7 +95,6 @@ }} let:toggleSummary cssClass={getInventoryRowClasses(item)} - itemCardContentTemplate={InventoryItemCardContent} > @@ -172,6 +172,9 @@ {/if} + {#if $context.useActionsFeature} + + {/if} {/if} diff --git a/src/sheets/character/tabs/CharacterFeaturesTab.svelte b/src/sheets/character/tabs/CharacterFeaturesTab.svelte index 59a254cbc..22caf3bdc 100644 --- a/src/sheets/character/tabs/CharacterFeaturesTab.svelte +++ b/src/sheets/character/tabs/CharacterFeaturesTab.svelte @@ -2,7 +2,7 @@ import { FoundryAdapter } from 'src/foundry/foundry-adapter'; import { type CharacterSheetContext } from 'src/types/types'; import { formatAsModifier } from 'src/utils/formatting'; - import ItemEditControl from '../../../components/item-list/ItemEditControl.svelte'; + import ItemEditControl from '../../../components/item-list/controls/ItemEditControl.svelte'; import ItemDuplicateControl from '../../../components/item-list/controls/ItemDuplicateControl.svelte'; import ItemDeleteControl from '../../../components/item-list/controls/ItemDeleteControl.svelte'; import ItemTable from '../../../components/item-list/ItemTable.svelte'; @@ -20,12 +20,14 @@ import ItemFilterSearch from '../../../components/item-list/ItemFilterSearch.svelte'; import ItemFilterOption from '../../../components/item-list/ItemFilterOption.svelte'; import InlineFavoriteIcon from '../../../components/item-list/InlineFavoriteIcon.svelte'; - import ItemFavoriteControl from '../../../components/item-list/ItemFavoriteControl.svelte'; + import ItemFavoriteControl from '../../../components/item-list/controls/ItemFavoriteControl.svelte'; import { getContext } from 'svelte'; import type { Readable } from 'svelte/store'; import Notice from '../../../components/notice/Notice.svelte'; import { settingStore } from 'src/settings/settings'; import DtypeInput from '../../../components/inputs/DtypeInput.svelte'; + import RechargeControl from 'src/components/item-list/controls/RechargeControl.svelte'; + import ActionFilterOverrideControl from 'src/components/item-list/controls/ActionFilterOverrideControl.svelte'; let context = getContext>('context'); @@ -63,7 +65,7 @@ {#each $context.features as section (section.label)} {@const filteredItems = FoundryAdapter.getFilteredItems( searchCriteria, - section.items + section.items, )} {#if (searchCriteria.trim() === '' && $context.editable) || filteredItems.length > 0} @@ -139,17 +141,7 @@ {#if section.showUsesColumn} {#if ctx?.isOnCooldown} - + {:else if item.system.recharge.value} {:else if ctx?.hasUses} @@ -181,7 +173,7 @@ FoundryAdapter.onLevelChange( event, item, - $context.actor + $context.actor, )} disabled={!$context.owner || $context.lockLevelSelector} > @@ -240,6 +232,9 @@ {/if} + {#if $context.useActionsFeature} + + {/if} {/if} diff --git a/src/sheets/npc/tabs/NpcAbilitiesTab.svelte b/src/sheets/npc/tabs/NpcAbilitiesTab.svelte index a52aae22b..4b0053c5c 100644 --- a/src/sheets/npc/tabs/NpcAbilitiesTab.svelte +++ b/src/sheets/npc/tabs/NpcAbilitiesTab.svelte @@ -18,9 +18,9 @@ import ItemAddUses from 'src/components/item-list/ItemAddUses.svelte'; import ItemDeleteControl from 'src/components/item-list/controls/ItemDeleteControl.svelte'; import ItemDuplicateControl from 'src/components/item-list/controls/ItemDuplicateControl.svelte'; - import ItemEditControl from 'src/components/item-list/ItemEditControl.svelte'; + import ItemEditControl from 'src/components/item-list/controls/ItemEditControl.svelte'; import ItemUses from 'src/components/item-list/ItemUses.svelte'; - import ItemControls from 'src/components/item-list/ItemControls.svelte'; + import ItemControls from 'src/components/item-list/controls/ItemControls.svelte'; import ItemTableFooter from 'src/components/item-list/ItemTableFooter.svelte'; import NpcLegendaryActions from '../parts/NpcLegendaryActions.svelte'; import SpellbookList from 'src/components/spellbook/SpellbookList.svelte'; @@ -34,6 +34,8 @@ import EncumbranceBar from '../../actor/EncumbranceBar.svelte'; import TabFooter from '../../actor/TabFooter.svelte'; import AmmoSelector from '../../actor/AmmoSelector.svelte'; + import RechargeControl from 'src/components/item-list/controls/RechargeControl.svelte'; + import ActionFilterOverrideControl from 'src/components/item-list/controls/ActionFilterOverrideControl.svelte'; let context = getContext>('context'); @@ -110,7 +112,6 @@ }} {item} cssClass={FoundryAdapter.getInventoryRowClasses(item, ctx)} - itemCardContentTemplate={getInfoCardTemplate(section)} > @@ -131,17 +132,7 @@ {#if section.hasActions} {#if ctx?.isOnCooldown} - + {:else if item.system.recharge?.value} {:else if ctx?.hasUses} @@ -164,6 +155,9 @@ {/if} + {#if $context.useActionsFeature} + + {/if} {/if} diff --git a/src/sheets/vehicle/tabs/VehicleAttributesTab.svelte b/src/sheets/vehicle/tabs/VehicleAttributesTab.svelte index 8f75e99c6..4e831de64 100644 --- a/src/sheets/vehicle/tabs/VehicleAttributesTab.svelte +++ b/src/sheets/vehicle/tabs/VehicleAttributesTab.svelte @@ -18,14 +18,16 @@ import ItemUses from 'src/components/item-list/ItemUses.svelte'; import ItemAddUses from 'src/components/item-list/ItemAddUses.svelte'; import TextInput from 'src/components/inputs/TextInput.svelte'; - import ItemControls from 'src/components/item-list/ItemControls.svelte'; + import ItemControls from 'src/components/item-list/controls/ItemControls.svelte'; import ItemDuplicateControl from 'src/components/item-list/controls/ItemDuplicateControl.svelte'; import ItemDeleteControl from 'src/components/item-list/controls/ItemDeleteControl.svelte'; - import ItemEditControl from 'src/components/item-list/ItemEditControl.svelte'; + import ItemEditControl from 'src/components/item-list/controls/ItemEditControl.svelte'; import ItemControl from 'src/components/item-list/controls/ItemControl.svelte'; import Notice from 'src/components/notice/Notice.svelte'; import HpBar from '../../../components/bar/HpBar.svelte'; import ResourceWithBar from 'src/components/bar/ResourceWithBar.svelte'; + import RechargeControl from 'src/components/item-list/controls/RechargeControl.svelte'; + import ActionFilterOverrideControl from 'src/components/item-list/controls/ActionFilterOverrideControl.svelte'; let context = getContext>('context'); @@ -43,7 +45,7 @@ let alternateColumnHeaderContent: Record = { threshold: ``, }; @@ -55,7 +57,7 @@ : controlsBaseWidthLocked; $: noFeatures = !$context.features.some( - (section: any) => section.items.length + (section: any) => section.items.length, ); @@ -136,18 +138,7 @@ {#if section.hasActions} {#if ctx?.isOnCooldown} - + {:else if item.system.recharge?.value} {/if} + {#if $context.useActionsFeature} + + {/if} {/if} diff --git a/src/sheets/vehicle/tabs/VehicleCargoAndCrewTab.svelte b/src/sheets/vehicle/tabs/VehicleCargoAndCrewTab.svelte index 997423fb6..f07df2769 100644 --- a/src/sheets/vehicle/tabs/VehicleCargoAndCrewTab.svelte +++ b/src/sheets/vehicle/tabs/VehicleCargoAndCrewTab.svelte @@ -20,11 +20,12 @@ import TabFooter from '../../actor/TabFooter.svelte'; import ItemDeleteControl from 'src/components/item-list/controls/ItemDeleteControl.svelte'; import ItemDuplicateControl from 'src/components/item-list/controls/ItemDuplicateControl.svelte'; - import ItemEditControl from 'src/components/item-list/ItemEditControl.svelte'; - import ItemControls from 'src/components/item-list/ItemControls.svelte'; + import ItemEditControl from 'src/components/item-list/controls/ItemEditControl.svelte'; + import ItemControls from 'src/components/item-list/controls/ItemControls.svelte'; import type { ItemCardContentComponent } from 'src/types/item'; import InventoryItemCardContent from 'src/components/item-info-card/InventoryItemCardContent.svelte'; import { settingStore } from 'src/settings/settings'; + import ActionFilterOverrideControl from 'src/components/item-list/controls/ActionFilterOverrideControl.svelte'; let context = getContext>('context'); @@ -58,10 +59,10 @@ section: { dataset: { type: 'crew' | 'passenger' }; items: CargoOrCrewItem[]; - } + }, ) { const cargo = foundry.utils.deepClone( - $context.actor.system.cargo[section.dataset.type] + $context.actor.system.cargo[section.dataset.type], ); const value = ev.currentTarget.value; @@ -146,7 +147,6 @@ }} {item} cssClass={FoundryAdapter.getInventoryRowClasses(item, ctx)} - itemCardContentTemplate={cardTemplate} > {#if section.editableName} @@ -179,11 +179,11 @@ {@const value = FoundryAdapter.getProperty( item, - column.property + column.property, )?.toString() ?? FoundryAdapter.getProperty( ctx, - column.property + column.property, )?.toString() ?? fallback} {/if} + + {#if $context.editable && !section.editableName && $context.useActionsFeature} + + {/if} {/if} diff --git a/src/types/types.ts b/src/types/types.ts index 920c5e654..37461796f 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,6 +1,5 @@ import type { ComponentProps, ComponentType, SvelteComponent } from 'svelte'; import type { Item5e, ItemCardContentComponent, ItemChatData } from './item'; -import type { Writable } from 'svelte/store'; export type Actor5e = any; @@ -93,7 +92,10 @@ export type NpcSheetContext = { export type VehicleSheetContext = {} & ActorSheetContext & Record; +export type ActorActions = Record>; + export type ActorSheetContext = { + actions: ActorActions; actor: Actor5e; allowEffectsManagement: boolean; appId: string; @@ -121,6 +123,7 @@ export type ActorSheetContext = { owner: boolean; showLimitedSheet: boolean; tabs: Tab[]; + useActionsFeature?: boolean; useClassicControls: boolean; useRoundedPortraitStyle: boolean; } & JQueryHooksSheetIntegration &