Skip to content

Commit

Permalink
Rudimentarily working Token Image Manager
Browse files Browse the repository at this point in the history
  • Loading branch information
MrVauxs committed Jul 30, 2024
1 parent 226208b commit c33e9f2
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 19 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- "Develeoper mode" setting. Puts into console what is being played with what roll options. Automatically on in `npm run dev`.
- Tabs to the Actor Animations Menu (#3) and "PF2e Graphics" bonus feat creation for Token Image Mapper.
- Tabs to the Actor Animations Menu (#3) and with it a rudimentary Token Image Manager.

#### Animations
- Melee Ignition
Expand Down
2 changes: 2 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
"openSheet": "Open Sheet"
},
"actorAnimation": {
"openFeat": "Open",
"displayFeat": "Display Feat on Character Sheet",
"tabs": {
"all-animations": "All Animations",
"actor-animations": "Actor Animations",
Expand Down
6 changes: 6 additions & 0 deletions src/app.postcss
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@
position: absolute;
margin: 0.42rem 0 0 -0.74rem;
}

.bg-button {
background: rgba(0, 0, 0, 0.1);
border: 2px groove var(--color-border-light-highlight);
border-radius: 3px;
}
20 changes: 20 additions & 0 deletions src/extensions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,23 @@ declare module 'svelte' {
export type TokenOrDoc = TokenDocument | Token

type Entries<T, K extends keyof T = keyof T> = (K extends unknown ? [K, T[K]] : never)[]

declare global {
type TokenImageRuleSource = RuleElementSource & {
/** An image or video path */
value: string
/** An optional scale adjustment */
scale: number
/** An optional tint adjustment */
tint: string
/** An optional alpha adjustment */
alpha: number
/** Animation options for when the image is applied */
animation: {
duration: number
transition: string
easing: string
name: string
}
}
}
4 changes: 2 additions & 2 deletions src/view/ActorAnimations/ActorAnimationsShell.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@
</div>
</div>
<div class='flex flex-row overflow-hidden flex-1 pb-2'>
<div class='overflow-y-scroll w-full'>
<div class='overflow-y-auto w-full'>
{#if activeTab === 'all-animations'}
<AllAnimations {doc} />
{/if}{#if activeTab === 'actor-animations'}
<ActorAnimations {doc} />
{/if}{#if activeTab === 'tokenimage-manager'}
<TokenimageManager {doc} />
<TokenimageManager actor={doc} />
{/if}
</div>
</div>
Expand Down
121 changes: 105 additions & 16 deletions src/view/ActorAnimations/submenus/tokenimage-manager.svelte
Original file line number Diff line number Diff line change
@@ -1,47 +1,136 @@
<script lang='ts'>
import type { TJSDocument } from '@typhonjs-fvtt/runtime/svelte/store/fvtt/document'
import { devMessage } from 'src/utils'
import { TJSDocument } from '@typhonjs-fvtt/runtime/svelte/store/fvtt/document'
import { dev, devMessage, i18n } from 'src/utils'
import { derived } from 'svelte/store'
import featData from './tokenimage-feat.json'
export let doc: TJSDocument<ActorPF2e>
export let actor: TJSDocument<ActorPF2e>
const tokenImageID = derived(doc, $doc => $doc.flags['pf2e-graphics']?.tokenImageID)
const feat = derived(doc, $doc => $doc.items.find(x => x.id === $doc.flags['pf2e-graphics']?.tokenImageID))
const tokenImageID = derived(actor, $actor => $actor.flags['pf2e-graphics']?.tokenImageID)
const derivedFeat = derived(actor, $actor => $actor.items.find(x => x.id === $actor.flags['pf2e-graphics']?.tokenImageID))
let feat = new TJSDocument($derivedFeat)
derivedFeat.subscribe(value => (feat = new TJSDocument(value)))
if ($tokenImageID && !$feat) {
ui.notifications.error('PF2e Graphics | PF2e Graphics bonus feat got deleted! Removing flags.')
$doc.unsetFlag('pf2e-graphics', 'tokenImageID')
$actor.unsetFlag('pf2e-graphics', 'tokenImageID')
}
devMessage($doc, $tokenImageID, $feat)
devMessage($actor, $tokenImageID, $feat)
const FeatPF2e = CONFIG.PF2E.Item.documentClasses.feat
async function giveth() {
const feat = (await $doc.createEmbeddedDocuments('Item', [new FeatPF2e(featData)]))[0]
$doc.setFlag('pf2e-graphics', 'tokenImageID', feat.id)
const feat = (await $actor.createEmbeddedDocuments('Item', [new FeatPF2e(featData)]))[0]
$actor.setFlag('pf2e-graphics', 'tokenImageID', feat.id)
}
async function takethAway() {
($doc.items.find(x => x.id === $doc.flags['pf2e-graphics']?.tokenImageID))?.delete()
$doc.unsetFlag('pf2e-graphics', 'tokenImageID')
($actor.items.find(x => x.id === $actor.flags['pf2e-graphics']?.tokenImageID))?.delete()
$actor.unsetFlag('pf2e-graphics', 'tokenImageID')
}
let display = $doc.getFlag('pf2e-graphics', 'displayFeat') as boolean
let display = $actor.getFlag('pf2e-graphics', 'displayFeat') as boolean
async function invisibility() {
$doc.setFlag('pf2e-graphics', 'displayFeat', display)
$actor.setFlag('pf2e-graphics', 'displayFeat', display)
}
const ruleTemplate = {
id: foundry.utils.randomID(),
key: 'TokenImage',
value: $feat?.actor.prototypeToken.texture.src,
predicate: [],
}
async function createRule() {
await $feat?.update({ 'system.rules': $feat.system.rules.concat(ruleTemplate) })
}
async function removeRule(rule: RuleElementSource) {
await $feat?.update({ 'system.rules': $feat.system.rules.filter(x => x !== rule) })
}
async function updateRules() {
await $feat?.update({ 'system.rules': $feat.system.rules })
}
async function PickAFile(current: string) {
// @ts-ignore Good grief, why cant all these be FilePicker options be OPTIONAL?
return new Promise(resolve => new FilePicker({ current, callback: result => resolve(result) }).browse())
}
</script>

<div class='p-2'>
<div class='p-2 pb-0 flex flex-col h-full'>
{#if $tokenImageID}
<div class='grid grid-flow-col columns-2'>
<div class='flex-grow flex-shrink overflow-y-scroll mb-2 text-center'>
{#each $feat?.system.rules.filter(x => x.key === 'TokenImage') || [] as rule}
<div class='border border-solid rounded-md p-1 m-1 gap-2 flex flex-col relative'>

<div class='flex items-center gap-1'>
<h3 class='border-b-0 -mt-1'><i class='fa-regular fa-circle mr-1.5 size-4 py-1' />Token Image</h3>
<div class='ml-auto'>
Priority Goes Here
<button on:click={() => removeRule(rule)} class='fas fa-trash-can size-8 m-1' />
</div>
</div>

<div class='flex items-center gap-1'>
Drag-and-Drop Predicates Go Here
</div>
<div class='flex items-center gap-1'>
Transition Options Go Here
</div>
<div class='flex items-center gap-1'>
Scale / Tint / Opacity Options Go Here
</div>
<div class='flex items-center gap-1 '>
<img
src={rule.value}
alt={rule.value}
class='size-8 border-0'
style:transform='scale({rule.scale ?? $feat.actor.prototypeToken.texture.scaleX})'
/>
<input
class='image h-6'
type='text'
placeholder='path/to/file.ext'
bind:value={rule.value}
on:change={updateRules}
/>
<button
class='fas fa-file-import w-10 bg-button h-6'
type='button'
data-tooltip={i18n('FILES.BrowseTooltip')}
aria-label={i18n('FILES.BrowseTooltip')}
tabindex='-1'
on:click={() => PickAFile(rule.value).then((x) => {
rule.value = x
updateRules()
})}
/>
</div>
{#if dev}
<div class='border border-solid bg-gray-400 p-1 mt-2 opacity-75'>
{JSON.stringify(rule)}
</div>
{/if}
</div>
{/each}
<button class='w-1/2' on:click={createRule}>
<i class='fas fa-plus' />
Create Token Image
</button>
</div>
<div class='grid grid-flow-col columns-2 gap-1'>
<div class='flex items-center'>
<label for='displayFeat'>Display Feat on Character Sheet</label>
<input type='checkbox' id='displayFeat' bind:checked={display} on:change={invisibility} />
</div>
<button class='' on:click={takethAway}>
Delet
{i18n('Delete')}
</button>
<button class='' on:click={() => $feat.sheet.render(true)}>
{i18n('actorAnimation.openFeat')}
</button>
</div>
{:else}
Expand Down

0 comments on commit c33e9f2

Please sign in to comment.