Skip to content

Commit

Permalink
Merge pull request #648 from ben/sf-character-sheet-tour
Browse files Browse the repository at this point in the history
SF character sheet tour
  • Loading branch information
ben authored Feb 18, 2023
2 parents 7cf3c8a + 436c5f1 commit 3339eab
Show file tree
Hide file tree
Showing 14 changed files with 337 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Next Release

- Fix some bugs around move-link navigation throughout the UI ([#647](https://github.com/ben/foundry-ironsworn/pull/647))
- Add a tour for the Starforged character sheet ([#648](https://github.com/ben/foundry-ironsworn/pull/648))

## 1.20.21

Expand Down
54 changes: 54 additions & 0 deletions script/tour-i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const fs = require('fs').promises
const YAML = require('yaml')
const _ = require('lodash')
const { marked } = require('marked')

async function doit() {
// List the yaml files in the tours directory
const files = await fs.readdir('./src/module/features/tours')
const yamls = files.filter(
(x) => x.toLowerCase().endsWith('.yml') || x.toLowerCase().endsWith('.yaml')
)

for (const yamlFilename of yamls) {
console.log(yamlFilename)
// Parse the yaml
const contents = await (
await fs.readFile(`./src/module/features/tours/${yamlFilename}`)
).toString()
const { rootKey, languages } = YAML.parse(contents)

for (const { lang, entries } of languages ?? []) {
console.log(` - ${lang}`)

// Load the i18n json file
const i18njson = JSON.parse(
await fs.readFile(`./system/lang/${lang}.json`)
)

// Update the entries
for (const entry of entries) {
const description = marked
.parse(entry.content)
.replace(/<\/p>\n<p>/g, '</p><p>') // remove extra newlines
.trim()
_.set(i18njson, `${rootKey}.${entry.key}Title`, entry.title)
_.set(i18njson, `${rootKey}.${entry.key}Content`, description)
}

// Write the i18n json file
await fs.writeFile(
`./system/lang/${lang}.json`,
JSON.stringify(i18njson, null, 2)
)
}
}
}

doit().then(
() => process.exit(),
(err) => {
console.error(err)
process.exit(1)
}
)
18 changes: 17 additions & 1 deletion src/module/actor/sheets/sf-charactersheet.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SFCharacterTour } from '../../features/tours/sf-character-tour'
import { IronswornSettings } from '../../helpers/settings'
import SfCharacterSheet from '../../vue/sf-charactersheet.vue'
import { VueActorSheet } from '../../vue/vueactorsheet'
Expand All @@ -13,21 +14,36 @@ export class StarforgedCharacterSheet extends VueActorSheet {
}) as any
}

activateTab(tabKey: string) {
this.localEmitter.emit('activateTab', tabKey)
}

render(...renderArgs: any[]) {
super.render(...renderArgs)
if (this._state <= Application.RENDER_STATES.NONE) this._openMoveSheet()
return Promise.resolve(this) as any
}

_getHeaderButtons() {
const [editButton, sheetButton, tokenButton, ...otherButtons] =
super._getHeaderButtons()
return [
{
class: 'ironsworn-open-move-sheet',
label: game.i18n.localize('IRONSWORN.ITEMS.TypeMove'),
icon: 'fas fa-directions',
onclick: (e) => this._openMoveSheet(e),
},
...super._getHeaderButtons(),
editButton,
sheetButton,
tokenButton,
{
class: 'ironsworn-help',
icon: 'fa fa-circle-question',
label: '',
onclick: (e) => new SFCharacterTour(this.actor).start(),
},
...otherButtons,
]
}
_openMoveSheet(_e?: JQuery.ClickEvent) {
Expand Down
2 changes: 1 addition & 1 deletion src/module/features/tours/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IronswornSettings } from '../../helpers/settings'
import { WelcomeTour } from './welcome_tour'
import { WelcomeTour } from './welcome-tour'

export async function registerTours() {
// Register our tours
Expand Down
2 changes: 1 addition & 1 deletion src/module/features/tours/ironsworn_tour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ declare global {
sidebarTab?: string
layer?: string
tool?: string
hook?: () => Promise<unknown>
hook?: () => Promise<unknown> | unknown
}
}

Expand Down
95 changes: 95 additions & 0 deletions src/module/features/tours/sf-character-tour.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { IronswornActor } from '../../actor/actor'
import { StarforgedCharacterSheet } from '../../actor/sheets/sf-charactersheet'
import { IronswornTour } from './ironsworn_tour'

export class SFCharacterTour extends IronswornTour {
constructor(actor: IronswornActor) {
const sheet = actor.sheet as StarforgedCharacterSheet
const sheetSel = `.app[data-appid="${sheet?.appId}"]`

super({
title: 'IRONSWORN.Tours.SFCharacter.Title',
description: 'IRONSWORN.Tours.SFCharacter.Description',
canBeResumed: false,
steps: [
{
id: 'sheet',
title: 'IRONSWORN.Tours.SFCharacter.SheetTitle',
content: 'IRONSWORN.Tours.SFCharacter.SheetContent',
selector: `${sheetSel} [data-tourid="sheet"]`,
},
{
id: 'edit-button',
title: 'IRONSWORN.Tours.SFCharacter.EditButtonTitle',
content: 'IRONSWORN.Tours.SFCharacter.EditButtonContent',
selector: `${sheetSel} .ironsworn-toggle-edit-mode`,
},
{
id: 'stats',
title: 'IRONSWORN.Tours.SFCharacter.StatsTitle',
content: 'IRONSWORN.Tours.SFCharacter.StatsContent',
selector: `${sheetSel} [data-tourid="stats"]`,
},
{
id: 'resources',
title: 'IRONSWORN.Tours.SFCharacter.ResourcesTitle',
content: 'IRONSWORN.Tours.SFCharacter.ResourcesContent',
selector: `${sheetSel} [data-tourid="resources"]`,
},
{
id: 'momentum',
title: 'IRONSWORN.Tours.SFCharacter.MomentumTitle',
content: 'IRONSWORN.Tours.SFCharacter.MomentumContent',
selector: `${sheetSel} [data-tourid="momentum"]`,
},
{
id: 'impacts',
title: 'IRONSWORN.Tours.SFCharacter.ImpactsTitle',
content: 'IRONSWORN.Tours.SFCharacter.ImpactsContent',
selector: `${sheetSel} [data-tourid="impacts"]`,
},
{
id: 'legacies',
title: 'IRONSWORN.Tours.SFCharacter.LegaciesTabTitle',
content: 'IRONSWORN.Tours.SFCharacter.LegaciesTabContent',
hook: () => sheet.activateTab('legacies'),
selector: `${sheetSel} [data-tourid="tabs"]`,
},
{
id: 'assets',
title: 'IRONSWORN.Tours.SFCharacter.AssetsTabTitle',
content: 'IRONSWORN.Tours.SFCharacter.AssetsTabContent',
hook: () => sheet.activateTab('assets'),
selector: `${sheetSel} [data-tourid="tabs"]`,
},
{
id: 'progress',
title: 'IRONSWORN.Tours.SFCharacter.ProgressTabTitle',
content: 'IRONSWORN.Tours.SFCharacter.ProgressTabContent',
hook: () => sheet.activateTab('progress'),
selector: `${sheetSel} [data-tourid="tabs"]`,
},
{
id: 'connections',
title: 'IRONSWORN.Tours.SFCharacter.ConnectionsTabTitle',
content: 'IRONSWORN.Tours.SFCharacter.ConnectionsTabContent',
hook: () => sheet.activateTab('connections'),
selector: `${sheetSel} [data-tourid="tabs"]`,
},
{
id: 'notes',
title: 'IRONSWORN.Tours.SFCharacter.NotesTabTitle',
content: 'IRONSWORN.Tours.SFCharacter.NotesTabContent',
hook: () => sheet.activateTab('notes'),
selector: `${sheetSel} [data-tourid="tabs"]`,
},
{
id: 'fin',
title: 'IRONSWORN.Tours.SFCharacter.EndTitle',
content: 'IRONSWORN.Tours.SFCharacter.EndContent',
selector: sheetSel,
},
],
})
}
}
81 changes: 81 additions & 0 deletions src/module/features/tours/sf-character-tour.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
rootKey: IRONSWORN.Tours.SFCharacter
languages:
- lang: en
entries:
- key: Sheet
title: Character Sheet
content: This is the player character sheet. It can help you manage your character's attributes, resources, assets, and vows.

- key: EditButton
title: Edit Button
content: The "<i class="fa-solid fa-edit"></i> Edit" button in the title bar is used to switch between interaction and edit modes for this character.

- key: Stats
title: Character Stats
content: |
These are your character's basic attributes, which tell you something about their personality, but also tell you that when they're trying certain kinds of actions, the story will tend to go better for them.
To roll against these stats, click on one of them. A dialog will open, allowing you to add bonuses and confirm the roll.
**EDIT MODE** allows you to adjust these numbers.
- key: Resources
title: Resources
content: |
On the side here we have the three basic resources: Health, Spirit, and Supply. You can adjust the levels of these resources by clicking on the new value.
You can also make rolls by clicking on the resource's name.
- key: Momentum
title: Momentum
content: |
On the other side is the momentum tracker. You can set your character's momentum by clicking on one of the numbers, and if you have debilities marked, one or more of the highest values will be disabled.
Hover over the "<i class="fa-solid fa-fire"></i> MOMENTUM" title for a preview of what burning your momentum will do, and click it to perform the burn.
- key: Impacts
title: Impacts
content: |
Down at the bottom of the sheet are your character's impacts. Checking these will affect your maximum momentum. There are also two boxes for you to enter custom impacts.
If there is a vehicle in the game with Battered or Cursed marked, that impact will be highlighted here to remind you that it should apply while you're on that vehicle.
- key: LegaciesTab
title: Legacies Tab
content: |
In the center area are a series of tabs. The first one is the "Legacies" tab, where you track your three primary Starforged legacies. Also appearing here will be any "starred" items from the Progress or Connections tabs.
To advance a legacy, click the "<i class="fa-solid fa-caret-right"></i>" button on the right. When enough legacy boxes are filled, XP boxes will appear; simply click them to expend XP. **EDIT MODE** also displays buttons for removing legacy ticks if you accidentally marked too many.
- key: AssetsTab
title: Assets Tab
content: |
The Assets tab is where your character's assets are displayed and managed. You can click on any asset here to expand its display and show its marked abilities. Click the "<i class="fa-solid fa-edit"></i>" icon to open a detail sheet for any asset.
**EDIT MODE** displays buttons for deleting and reordering assets.
The "<i class="fa-solid fa-book-atlas"></i> Assets" button at the bottom opens the asset browser.
- key: ProgressTab
title: Progress Tab
content: |
The Progress tab displays your character's current vows and other progress items. You can add a new blank item by clicking the "+Vow" or "+Progress" buttons at the bottom, or you can open the "<i class="fa-solid fa-book-atlas"></i> Foes" compendium and drag an enemy into the list.
Each item shows current progress, and has controls for marking ticks and making a progress roll. Use the "<i class="fa-solid fa-star"></i>" button to also display an item in the Legacies tab.
**EDIT MODE** adds buttons for reordering items, adjusting progress ticks, and marking an item as complete, which hides it in the section at the bottom of the tab.
- key: ConnectionsTab
title: Connections Tab
content: |
Connections are tracked separately from other progress items, and can be found in this tab. Otherwise this behaves the same as the Progress tab.
- key: NotesTab
title: Notes Tab
content: |
The Notes tab is just for you. Keep track of your narrative here (or use journal entries), note down what kind of gear you're carrying, jot down the scars you've earned on your way.
- key: End
title: Character Sheet
content: |
That's all for now. Look for the <i class="fa-solid fa-circle-question"></i> button in other sheet title bars for more information on how they work.
File renamed without changes.
37 changes: 37 additions & 0 deletions src/module/features/tours/welcome-tour.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
rootKey: IRONSWORN.Tours.Welcome
languages:
- lang: en
entries:
- key: Welcome
title: Welcome
content: |
Welcome to Ironsworn & Starforged! This tour will help you find where all the things are that will help you set up and play your game.
At this point you will have seen the game-selection dialog, which configures the default character sheet, moves, and oracles. Let's look at where the other system features can be found.
- key: ActorTab
title: Creating a Character
content: |
At some point, you'll want to create a character. To do that, navigate to the "<i class="fas fa-user"></i> Actors" tab and click this button.
- key: CharacterCreate
title: Creating a Character
content: |
This button will create a primary character, which is all you need to get started. As your game progresses, you may need the other types here to organize things.
- key: Compendium
title: Maps
content: |
You'll probably want a map of the Ironlands or a sector of the Forge. You can create your own scene for this, or you can use one of ours. Open one of these compendiums and drag a map to your "<i class="fas fa-map"></i> Scenes" area.
- key: OracleTool
title: Oracles
content: |
No game of Ironsworn or Starforged would be complete without oracles. This button will pop up a window with all the oracles in your chosen game. The oracles are also available from the character sheet.
- key: Tours
title: Next Steps
content: |
That's it for now! For more information on other topics, check out the Tour Management area in the settings tabs. And if you want to get in contact, check out the `#foundry-vtt` channel in the [Ironsworn Discord](https://discord.gg/8bRuZwK).
Enjoy!
6 changes: 5 additions & 1 deletion src/module/vue/components/tabs/tab-set.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

<script lang="ts" setup>
import { forEach } from 'lodash'
import { onMounted, provide, reactive } from 'vue'
import { inject, onMounted, provide, reactive } from 'vue'
import { $LocalEmitterKey } from '../../provisions'
import {
FocusActivePanelKey,
getTabId,
Expand Down Expand Up @@ -79,6 +80,9 @@ function setActiveTab(tabKey: TabKey) {
}
}
const $localEmitter = inject($LocalEmitterKey)
$localEmitter?.on('activateTab', setActiveTab)
provide(TabStateKey, tabState)
provide(SetActiveTabKey, setActiveTab)
provide(SetActivePanelRefKey, setActivePanelRef)
Expand Down
7 changes: 0 additions & 7 deletions src/module/vue/components/tabs/tab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,6 @@ let $el = ref<typeof IronBtn>()
const isActive = computed(() => tabState.activeTab === props.tabKey)
watch(tabState, async () => {
if (tabState.focusedTab === props.tabKey) {
await nextTick()
$el.value?.element.focus()
}
})
const tabSetId = computed(() => tabState.tabSetId)
defineExpose({
tabSetId: tabSetId.value,
Expand Down
1 change: 1 addition & 0 deletions src/module/vue/provisions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const $EnrichMarkdownKey = Symbol('$enrichMarkdown') as InjectionKey<
// Provided by the render helper
export type LocalEmitterEvents = {
closeApp: void
activateTab: string
}
export type LocalEmitter = Emitter<LocalEmitterEvents>
export const $LocalEmitterKey = Symbol(
Expand Down
Loading

0 comments on commit 3339eab

Please sign in to comment.