Skip to content

Commit

Permalink
Merge pull request #1023 from ben/ben/moves-from-index
Browse files Browse the repository at this point in the history
Indexed moves
  • Loading branch information
ben authored Aug 29, 2024
2 parents b5268a2 + fbb2a18 commit f63aec5
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 70 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Next Release

- Brought back support for the "Custom Moves" folder ([#1023](https://github.com/ben/foundry-ironsworn/pull/1023))

## 1.24.0

This is a major update that includes Sundered Isles content, but also brings along a host of changes:
Expand Down
7 changes: 5 additions & 2 deletions src/module/datasworn2/finding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,13 @@ interface PackAndIndex {

export async function getPackAndIndexForCompendiumKey(
ruleset: DataswornRulesetKey,
type: keyof typeof COMPENDIUM_KEY_MAP
type: keyof typeof COMPENDIUM_KEY_MAP,
additionalFields?: string[]
): Promise<PackAndIndex> {
const pack = game.packs.get(COMPENDIUM_KEY_MAP[type][ruleset])
const index = await pack?.getIndex({ fields: ['flags'] })
const index = await pack?.getIndex({
fields: ['flags', ...((additionalFields ?? []) as any[])]
})
return { pack, index }
}

Expand Down
57 changes: 53 additions & 4 deletions src/module/features/custommoves.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import {
} from '../datasworn2'
import { DataswornRulesetKey, IronswornSettings } from '../helpers/settings'
import type { Move, MoveCategory } from '@datasworn/core/dist/Datasworn'
import { moveTriggerIsRollable } from '../rolls/preroll-dialog'
import { compact } from 'lodash-es'
import { IronswornItem } from '../item/item'
import { SFMoveModel } from '../item/subtypes/sfmove'

interface DisplayMoveRuleset {
displayName: string
Expand All @@ -22,14 +26,20 @@ export interface DisplayMove {
color: string | null
displayName: string
uuid: string
triggerText?: string
isRollable: boolean
oracles: string[]
ds?: Move
}

const INDEXES: Record<string, any> = {}
async function ensureIndex(rsKey: DataswornRulesetKey) {
const compendiumKey = COMPENDIUM_KEY_MAP.move[rsKey]
if (INDEXES[compendiumKey] == null) {
const { index } = await getPackAndIndexForCompendiumKey(rsKey, 'move')
const { index } = await getPackAndIndexForCompendiumKey(rsKey, 'move', [
'system.Trigger',
'system.dsOracleIds'
])
INDEXES[compendiumKey] = index
}
}
Expand All @@ -55,19 +65,58 @@ export async function createMoveTreeForRuleset(
color: move.color ?? null,
displayName: move.name,
uuid: indexEntry.uuid, // TODO: move.uuid
triggerText: indexEntry.system?.Trigger?.Text,
isRollable: moveTriggerIsRollable(indexEntry?.system?.Trigger),
oracles: indexEntry.system?.dsOracleIds ?? [],
ds: move
}
})
}))
}
}

function customFolderMoveCategory(): DisplayMoveRuleset | undefined {
const name = game.i18n.localize('IRONSWORN.MOVES.Custom Moves')
const rootFolder = game.items?.directory?.folders.find((x) => x.name === name)
if (!rootFolder) return undefined

const category: DisplayMoveCategory = {
displayName: name,
color: (rootFolder as any).color?.css ?? null,
moves: []
}

for (const item of rootFolder.contents) {
if (!(item instanceof IronswornItem)) continue
if (item.type !== 'sfmove') continue
const system = item.system as SFMoveModel

category.moves.push({
displayName: item.name ?? '(unnamed)',
uuid: item.uuid,
color: null,
isRollable: moveTriggerIsRollable(system.Trigger),
oracles: system.dsOracleIds ?? [],
triggerText: system.Trigger?.Text
})
}
if (category.moves.length === 0) return undefined

return {
displayName: name,
categories: [category]
}
}

export async function createMergedMoveTree(): Promise<DisplayMoveRuleset[]> {
// Pre-load compendium indexes
await Promise.all(IronswornSettings.enabledRulesets.map(ensureIndex))
return await Promise.all(
IronswornSettings.enabledRulesets.map(createMoveTreeForRuleset)
)
return compact([
...(await Promise.all(
IronswornSettings.enabledRulesets.map(createMoveTreeForRuleset)
)),
customFolderMoveCategory()
])
}

// TODO dataforged has a key for move colours...., but they appear to have changed significantly since the last time i updated them! they'll be fixed for 2.0, but until then, here's a workaround.
Expand Down
6 changes: 2 additions & 4 deletions src/module/rolls/preroll-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ function rollableOptions(trigger: SFMoveTrigger) {
)
}

export function moveHasRollableOptions(move: IronswornItem<'sfmove'>) {
if (!move.assert('sfmove')) return false
const options = rollableOptions(move.system.Trigger)
return options.length > 0
export function moveTriggerIsRollable(trigger?: SFMoveTrigger) : boolean {
return !!trigger && rollableOptions(trigger).length > 0
}

export function getStatData(
Expand Down
14 changes: 7 additions & 7 deletions src/module/vue/components/buttons/btn-sendmovetochat.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@
</template>

<script setup lang="ts">
import { inject } from 'vue'
import { createSfMoveChatMessage } from '../../../chat/sf-move-chat-message'
import type { DisplayMove } from '../../../features/custommoves'
import { $ItemKey } from '../../provisions.js'
import IronBtn from './iron-btn.vue'
import { IronswornItem } from '../../../item/item'
interface Props
extends /* @vue-ignore */ Omit<PropsOf<typeof IronBtn>, 'tooltip'> {
move: DisplayMove
}
defineProps<Props>()
const props = defineProps<Props>()
const $item = inject($ItemKey)
function sendToChat(e) {
if ($item) createSfMoveChatMessage($item)
async function sendToChat(e) {
const foundryMove = (await fromUuid(
props.move.uuid
)) as IronswornItem<'sfmove'>
if (foundryMove) createSfMoveChatMessage(foundryMove)
}
</script>
71 changes: 71 additions & 0 deletions src/module/vue/components/move/move-content.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<template>
<RulesTextMove
:data="moveObj"
:is-progress-move="foundryMove.system.isProgressMove"
:class="$style.summary"
>
<template #after-footer>
<OracleTreeNode
v-for="node of oracleNodes"
:key="node.displayName"
:class="$style.oracle"
:node="node"
/>
</template>
</RulesTextMove>
</template>

<script setup lang="ts">
import { ref, provide } from 'vue'
import { uniq, compact } from 'lodash-es'
import { IronswornItem } from '../../../item/item'
import { OracleTable } from '../../../roll-table/oracle-table'
import { ItemKey, $ItemKey } from '../../provisions.js'
import type { DisplayMove } from '../../../features/custommoves'
import type { IOracleTreeNode } from '../../../features/customoracles'
import RulesTextMove from '../rules-text/rules-text-move.vue'
import OracleTreeNode from '../oracle-tree-node.vue'
const props = defineProps<{
move: DisplayMove
}>()
const foundryMove = (await fromUuid(props.move.uuid)) as IronswornItem<'sfmove'>
const moveObj = ref(foundryMove.toObject())
provide(ItemKey, moveObj as any)
provide($ItemKey, foundryMove)
const oracleDsIds = uniq([
...(foundryMove?.system?.dsOracleIds ?? []),
...Object.values(props.move.ds?.oracles ?? {}).map((x) => x._id)
])
const oracleNodes: IOracleTreeNode[] = await Promise.all(
oracleDsIds.map(async (oid) => {
const t = await OracleTable.getByDsId(oid)
return {
displayName: t?.name ?? '(missing)',
tables: compact([t?.uuid]),
children: []
}
})
)
</script>

<style lang="scss" module>
.oracle {
border-width: var(--ironsworn-border-width-md);
border-style: solid;
border-radius: var(--ironsworn-border-radius-sm);
border-color: var(--ironsworn-color-border);
padding: 0;
h4 {
font-size: var(--font-size-16);
button.icon-button {
height: inherit;
}
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class="movesheet-row"
:class="$style.wrapper"
data-tooltip-direction="LEFT"
:base-id="`move_row_${item._id}`"
:base-id="`move_row_${move.uuid}`"
:content-wrapper-class="$style.contentWrapper"
:toggle-wrapper-is="`h${headingLevel}`"
:toggle-section-class="[$style.toggleSection, toggleSectionClass]"
Expand All @@ -15,8 +15,7 @@
:toggle-wrapper-class="$style.toggleWrapper"
:toggle-label="move?.displayName"
:data-highlighted="dataHighlight"
:data-move-id="item._id"
:data-move-uuid="$item.uuid"
:data-move-uuid="move.uuid"
>
<template #after-toggle>
<section
Expand All @@ -28,10 +27,10 @@
<slot name="controls">
<slot
name="btn-roll-move"
v-bind="{ disabled: !canRoll, move, class: $style.btn }"
v-bind="{ disabled: !move.isRollable, move, class: $style.btn }"
>
<BtnRollmove
:disabled="!canRoll"
:disabled="!move.isRollable"
:move="move"
:class="$style.btn"
/>
Expand All @@ -57,40 +56,23 @@
</section>
</template>
<template #default>
<RulesTextMove
:data="item"
:is-progress-move="$item.system.isProgressMove"
:class="$style.summary"
>
<template #after-footer>
<OracleTreeNode
v-for="node of oracleNodes"
:key="node.displayName"
:class="$style.oracle"
:node="node"
/>
</template>
</RulesTextMove>
<MoveContent :move="move" />
</template>
</Collapsible>
</template>

<script setup lang="ts">
import { computed, onMounted, provide, ref, watch } from 'vue'
import type { DisplayMove } from '../../features/custommoves'
import type { IOracleTreeNode } from '../../features/customoracles'
import type { IronswornItem } from '../../item/item'
import { moveHasRollableOptions } from '../../rolls/preroll-dialog'
import BtnRollmove from './buttons/btn-rollmove.vue'
import BtnSendmovetochat from './buttons/btn-sendmovetochat.vue'
import OracleTreeNode from './oracle-tree-node.vue'
import RulesTextMove from './rules-text/rules-text-move.vue'
import Collapsible from './collapsible/collapsible.vue'
import BtnOracle from './buttons/btn-oracle.vue'
import { ItemKey, $ItemKey } from '../provisions.js'
import { enrichMarkdown } from '../vue-plugin.js'
import { compact, uniq } from 'lodash-es'
import { OracleTable } from '../../roll-table/oracle-table'
import { computed, onMounted, ref, watch } from 'vue'
import type { DisplayMove } from '../../../features/custommoves'
import type { IOracleTreeNode } from '../../../features/customoracles'
import { compact } from 'lodash-es'
import { OracleTable } from '../../../roll-table/oracle-table'
import BtnRollmove from '../buttons/btn-rollmove.vue'
import BtnSendmovetochat from '../buttons/btn-sendmovetochat.vue'
import Collapsible from '../collapsible/collapsible.vue'
import BtnOracle from '../buttons/btn-oracle.vue'
import MoveContent from './move-content.vue'
const props = withDefaults(
defineProps<{
Expand Down Expand Up @@ -125,20 +107,10 @@ const props = withDefaults(
}
)
const $item = (await fromUuid(props.move.uuid)) as IronswornItem<'sfmove'>
const item = ref($item.toObject())
provide(ItemKey, item as any)
provide($ItemKey, $item)
const $collapsible = ref<typeof Collapsible>()
const oracleDsIds = uniq([
...($item?.system?.dsOracleIds ?? []),
...Object.values(props.move.ds?.oracles ?? {}).map((x) => x._id)
])
const oracleNodes: IOracleTreeNode[] = await Promise.all(
oracleDsIds.map(async (oid) => {
props.move.oracles.map(async (oid) => {
const t = await OracleTable.getByDsId(oid)
return {
displayName: t?.name ?? '(missing)',
Expand All @@ -148,15 +120,11 @@ const oracleNodes: IOracleTreeNode[] = await Promise.all(
})
)
const canRoll = computed(() => {
return moveHasRollableOptions($item)
})
const preventOracle = computed(() => {
return oracleNodes.length !== 1
})
const toggleTooltip = ref($item.system.Trigger?.Text)
enrichMarkdown(toggleTooltip.value).then((x) => (toggleTooltip.value = x))
const toggleTooltip = props.move.triggerText
const dataHighlight = ref(false)
async function flashHighlight() {
Expand Down
2 changes: 1 addition & 1 deletion src/module/vue/components/sf-move-category-rows.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { DisplayMoveCategory } from '../../features/custommoves.js'
import SfMoverow from './sf-moverow.vue'
import SfMoverow from './move/sf-moverow.vue'
import Collapsible from './collapsible/collapsible.vue'
import { snakeCase } from 'lodash-es'
import { enrichMarkdown } from '../vue-plugin'
Expand Down
2 changes: 1 addition & 1 deletion src/module/vue/components/sf-movesheetmoves.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import { computed, nextTick, provide, reactive, ref } from 'vue'
import type { DisplayMoveCategory } from '../../features/custommoves'
import { createMergedMoveTree } from '../../features/custommoves'
import SfMoveCategoryRows from './sf-move-category-rows.vue'
import SfMoverow from './sf-moverow.vue'
import SfMoverow from './move/sf-moverow.vue'
import IronBtn from './buttons/iron-btn.vue'
const state = reactive({
Expand Down
2 changes: 1 addition & 1 deletion src/module/vue/components/site/site-moves.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ import { $ActorKey, ActorKey } from '../../provisions'
import BtnOracle from '../buttons/btn-oracle.vue'
import BtnRollmove from '../buttons/btn-rollmove.vue'
import SfMoverow from '../sf-moverow.vue'
import SfMoverow from '../move/sf-moverow.vue'
const site = inject(ActorKey) as Ref<ActorSource<'site'>>
const $site = inject($ActorKey) as IronswornActor<'site'>
Expand Down

0 comments on commit f63aec5

Please sign in to comment.