diff --git a/CHANGELOG.md b/CHANGELOG.md index ab3fc78ca..3ee5aa8b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Next Release +This is a major update that includes Sundered Isles content, but also brings along a host of changes: + +- Selection of content happens in the first-start dialog, which will show the first time you open your world after this update. +- For module/macro authors: registration of custom oracle content has a name change: `'ironsworn'` has changed to `'classic'`, and there's a new `'sundered_isles'` tree. + ## 1.23.7 - Fix Cinder and Wraith dice with dice-so-nice 5 ([#1009](https://github.com/ben/foundry-ironsworn/pull/1009)) diff --git a/src/module/applications/firstStartDialog.ts b/src/module/applications/firstStartDialog.ts index d0094d874..039fd0328 100644 --- a/src/module/applications/firstStartDialog.ts +++ b/src/module/applications/firstStartDialog.ts @@ -1,4 +1,4 @@ -import { IronswornSettings } from '../helpers/settings' +import { IronswornSettings, RULESETS } from '../helpers/settings' import { SFSettingTruthsDialogVue } from './vueSfSettingTruthsDialog' import { WorldTruthsDialog } from './worldTruthsDialog' @@ -8,6 +8,7 @@ export class FirstStartDialog extends FormApplication { } static get defaultOptions(): FormApplicationOptions { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions return foundry.utils.mergeObject(super.defaultOptions, { title: game.i18n.localize('IRONSWORN.First Start.Welcome'), template: 'systems/foundry-ironsworn/templates/first-start.hbs', @@ -15,7 +16,7 @@ export class FirstStartDialog extends FormApplication { resizable: false, classes: ['ironsworn', 'sheet', 'first-start'], width: 650, - height: 360 + height: 560 } as FormApplicationOptions) } @@ -25,75 +26,63 @@ export class FirstStartDialog extends FormApplication { activateListeners(html: JQuery) { super.activateListeners(html) - html.find('#select-ironsworn').on('click', async (ev) => { - await this._selectIronsworn.call(this, ev) - }) - html.find('#select-starforged').on('click', async (ev) => { - await this._selectStarforged.call(this, ev) - }) - html.find('#select-sunderedisles').on('click', async (ev) => { - await this._selectSunderedIsles.call(this, ev) + // eslint-disable-next-line @typescript-eslint/no-misused-promises + html.find('button.ironsworn__save').on('click', async (ev) => { + console.log(html) + + // Update default character sheet + const defaultSheet = html.find('input[name=sheet]:checked').val() + const setting = game.settings.get('core', 'sheetClasses') + foundry.utils.mergeObject(setting, { + 'Actor.character': `ironsworn.${defaultSheet}` + }) + await game.settings.set('core', 'sheetClasses', setting) + + // Update rulesets + const checkedRulesets: any[] = $.map( + html.find('input.ruleset:checked'), + (x: any) => x.value ?? '' + ) + await IronswornSettings.enableOnlyRulesets(...checkedRulesets) + + if (IronswornSettings.get('show-first-start-dialog')) { + if (defaultSheet === 'StarforgedCharacterSheet') { + void new SFSettingTruthsDialogVue().render(true) + } else { + void new WorldTruthsDialog().render(true) + } + } + await IronswornSettings.set('show-first-start-dialog', false) }) } async getData(_options?: unknown) { + const rulesets = {} + for (const r of RULESETS) { + rulesets[r] = { + id: r, + name: game.i18n.localize(`IRONSWORN.RULESETS.${r}`), + enabled: IronswornSettings.get(`ruleset-${r}`) + } + } return { ...(await super.getData()), - sunderedislesBeta: IronswornSettings.get('sundered-isles-beta') + rulesets: rulesets, + sheetIsIronsworn: this.currentDefaultSheet === 'ironsworn', + sheetIsStarforged: this.currentDefaultSheet === 'starforged' } } - async _selectIronsworn(ev) { - ev.preventDefault() - - // Character sheet - const setting = game.settings.get('core', 'sheetClasses') - foundry.utils.mergeObject(setting, { - 'Actor.character': 'ironsworn.IronswornCharacterSheetV2' - }) - await game.settings.set('core', 'sheetClasses', setting) - - // Truths - new WorldTruthsDialog().render(true) - game.settings.set('foundry-ironsworn', 'prompt-world-truths', false) - this.close() - } - - async _selectStarforged(ev) { - ev.preventDefault() - - // Character sheet - const setting = game.settings.get('core', 'sheetClasses') - foundry.utils.mergeObject(setting, { - 'Actor.character': 'ironsworn.StarforgedCharacterSheet' - }) - await game.settings.set('core', 'sheetClasses', setting) - - // Truths - new SFSettingTruthsDialogVue().render(true) - game.settings.set('foundry-ironsworn', 'prompt-world-truths', false) - this.close() - } - - async _selectSunderedIsles(ev) { - ev.preventDefault() - - // Use the Starforged character sheet + get currentDefaultSheet(): 'ironsworn' | 'starforged' { const setting = game.settings.get('core', 'sheetClasses') - foundry.utils.mergeObject(setting, { - 'Actor.character': 'ironsworn.StarforgedCharacterSheet' - }) - await game.settings.set('core', 'sheetClasses', setting) - - // TODO: Sundered Isles Truths - // new SFSettingTruthsDialogVue().render(true) - // game.settings.set('foundry-ironsworn', 'prompt-world-truths', false) - - this.close() + if (setting.Actor?.character === 'ironsworn.StarforgedCharacterSheet') { + return 'starforged' + } + return 'ironsworn' } static async maybeShow() { - if (!IronswornSettings.get('prompt-world-truths')) { + if (!IronswornSettings.get('show-first-start-dialog')) { return } diff --git a/src/module/features/customoracles.ts b/src/module/features/customoracles.ts index ac204cdef..4080c4b0c 100644 --- a/src/module/features/customoracles.ts +++ b/src/module/features/customoracles.ts @@ -1,16 +1,21 @@ import type { - IOracle, - IOracleCategory, - Starforged, - Ironsworn -} from 'dataforged' -import { starforged, ironsworn } from 'dataforged' + OracleCollection, + OracleRollableTable, + OracleTablesCollection, + RulesetId +} from '@datasworn/core/dist/Datasworn' +import type { IOracle, IOracleCategory } from 'dataforged' import { cloneDeep, compact } from 'lodash-es' -import { OracleTable } from '../roll-table/oracle-table' -import { cachedDocumentsForPack } from './pack-cache' +import { DataswornTree } from '../datasworn2' +import { IronswornSettings } from '../helpers/settings' +import { + DS_ORACLE_COMPENDIUM_KEYS, + OracleTable +} from '../roll-table/oracle-table' export interface IOracleTreeNode { dataforgedNode?: IOracle | IOracleCategory + dataswornNode?: OracleCollection | OracleRollableTable tables: string[] // UUIDs displayName: string children: IOracleTreeNode[] @@ -18,78 +23,13 @@ export interface IOracleTreeNode { forceHidden?: boolean } -// For some reason, rollupJs mangles this -const SFOracleCategories = ((starforged as any).default as Starforged)[ - 'Oracle Categories' -] -const ISOracleCategories = ((ironsworn as any).default as Ironsworn)[ - 'Oracle Categories' -] - const emptyNode: () => IOracleTreeNode = () => ({ displayName: '', tables: [], children: [] }) -async function createOracleTree( - compendium: string, - categories: IOracleCategory[] -): Promise { - const rootNode = emptyNode() - - // Make sure the compendium is loaded - await cachedDocumentsForPack(compendium) - - // Build the default tree - for (const category of categories) { - rootNode.children.push(await walkOracleCategory(category)) - } - - return rootNode -} - -async function createIronswornOracleTree(): Promise { - return await createOracleTree( - 'foundry-ironsworn.ironswornoracles', - ISOracleCategories - ) -} - -async function createStarforgedOracleTree(): Promise { - return await createOracleTree( - 'foundry-ironsworn.starforgedoracles', - SFOracleCategories - ) -} - -async function walkOracleCategory( - cat: IOracleCategory -): Promise { - const node: IOracleTreeNode = { - ...emptyNode(), - dataforgedNode: cat, - displayName: game.i18n.localize(`IRONSWORN.OracleCategories.${cat.Name}`) - } - - for (const childCat of cat.Categories ?? []) { - node.children.push(await walkOracleCategory(childCat)) - } - for (const oracle of cat.Oracles ?? []) { - node.children.push(await walkOracle(oracle)) - } - - // Promote children of nodes that have a table - for (const child of node.children) { - if (child.tables.length > 0) { - node.children = [...node.children, ...child.children] - child.children = [] - } - } - - return node -} - +// TODO: only used for sf-moverow now, clean that up export async function walkOracle( oracle?: IOracle | IOracleCategory ): Promise { @@ -206,13 +146,9 @@ export function findPathToNodeByDfId(rootNode: IOracleTreeNode, dfid: string) { return ret } -type OracleCategory = 'ironsworn' | 'starforged' | 'sunderedisles' +type OracleCategory = 'classic' | 'delve' | 'starforged' | 'sundered_isles' -const ORACLES: Record = { - ironsworn: emptyNode(), - starforged: emptyNode(), - sunderedisles: emptyNode() -} +const ORACLES: Record = {} export function registerOracleTreeInternal( category: OracleCategory, @@ -223,14 +159,67 @@ export function registerOracleTreeInternal( let defaultTreesInitialized = false -export async function registerDefaultOracleTrees() { - const ironswornOracles = await createIronswornOracleTree() - registerOracleTreeInternal('ironsworn', ironswornOracles) +function walkOracleTable( + node: OracleRollableTable, + index: any +): IOracleTreeNode { + const tableIndexEntry = index.contents.find( + (x) => x.flags?.['foundry-ironsworn']?.['dsid'] === node._id + ) + return { + dataswornNode: node, + displayName: tableIndexEntry?.name ?? node.name, + tables: compact([tableIndexEntry?.uuid]), + children: [] + } +} - const starforgedOracles = await createStarforgedOracleTree() - registerOracleTreeInternal('starforged', starforgedOracles) +function walkDsOracleCollection( + node: OracleTablesCollection, + index: any +): IOracleTreeNode { + const children = [ + ...Object.values(node?.collections ?? {}).map((x) => + walkDsOracleCollection(x as OracleTablesCollection, index) + ), + ...Object.values(node?.contents ?? {}).map((x) => walkOracleTable(x, index)) + ] + if ( + game.i18n + .localize(`IRONSWORN.OracleCategories.${node.name}`) + .startsWith('IRONSWORN') + ) { + console.log('!!!', node.name) + } + return { + dataswornNode: node, + displayName: game.i18n.localize(`IRONSWORN.OracleCategories.${node.name}`), + tables: [], + children + } +} - // TODO: Sundered Isles oracles +async function generateTreeFromDsData( + ruleset: RulesetId +): Promise { + const pack = game.packs.get(DS_ORACLE_COMPENDIUM_KEYS[ruleset]) + const index = await pack.getIndex({ fields: ['flags'] }) + + const rp = DataswornTree.get(ruleset) + return { + displayName: game.i18n.localize(`IRONSWORN.RULESETS.${ruleset}`), + tables: [], + children: Object.values(rp?.oracles ?? {}).map((o) => + walkDsOracleCollection(o, index) + ) + } +} + +export async function registerDefaultOracleTrees() { + for (const ruleset of IronswornSettings.enabledRulesets) { + const tree = await generateTreeFromDsData(ruleset) + registerOracleTreeInternal(ruleset, tree) + } defaultTreesInitialized = true Hooks.call('ironswornOracleTreesReady') @@ -270,3 +259,19 @@ export async function getOracleTreeWithCustomOracles( return rootNode } + +export async function getCustomizedOracleTrees(): Promise { + return await Promise.all( + Object.keys(ORACLES).map(async (ruleset) => { + const tree = ORACLES[ruleset] + + // Add in custom oracles from a well-known directory + await augmentWithFolderContents(tree) + + // Fire the hook and allow extensions to modify the tree + Hooks.call('ironswornOracles', tree) + + return tree + }) + ) +} diff --git a/src/module/helpers/settings.ts b/src/module/helpers/settings.ts index fd01583d6..be328adb4 100644 --- a/src/module/helpers/settings.ts +++ b/src/module/helpers/settings.ts @@ -7,12 +7,7 @@ import { WorldTruthsDialog } from '../applications/worldTruthsDialog.js' import * as IronColor from '../features/ironcolor' import * as IronTheme from '../features/irontheme' -async function closeAllMoveSheets() { - for (const actor of game.actors?.contents ?? []) { - await actor.moveSheet?.close() - actor.moveSheet = undefined - } -} +export const RULESETS = ['classic', 'delve', 'starforged', 'sundered_isles'] declare global { // eslint-disable-next-line @typescript-eslint/no-namespace @@ -24,13 +19,19 @@ declare global { | 'starforged' | 'sunderedisles' | 'sheet' + | 'migrated' + + 'foundry-ironsworn.ruleset-classic': boolean + 'foundry-ironsworn.ruleset-delve': boolean + 'foundry-ironsworn.ruleset-starforged': boolean + 'foundry-ironsworn.ruleset-sundered_isles': boolean 'foundry-ironsworn.theme': keyof typeof IronTheme.THEMES 'foundry-ironsworn.color-scheme': 'zinc' | 'phosphor' | 'oceanic' 'foundry-ironsworn.progress-mark-animation': boolean 'foundry-ironsworn.log-changes': boolean - 'foundry-ironsworn.prompt-world-truths': boolean + 'foundry-ironsworn.show-first-start-dialog': boolean 'foundry-ironsworn.shared-supply': boolean @@ -99,23 +100,31 @@ export class IronswornSettings { }) // Toolbox/ruleset. this goes at the top because it's a "showstopper" if folks need it but can't find it. + // Legacy toolbox selection. This has been converted to individual rulesets below game.settings.register('foundry-ironsworn', 'toolbox', { - name: 'IRONSWORN.Settings.Tools.Name', - hint: 'IRONSWORN.Settings.Tools.Hint', scope: 'world', - config: true, + config: false, type: String, choices: { sheet: 'IRONSWORN.Settings.Tools.Sheet', ironsworn: 'IRONSWORN.Ironsworn', starforged: 'IRONSWORN.Starforged', - sunderedisles: 'IRONSWORN.SunderedIsles' + sunderedisles: 'IRONSWORN.SunderedIsles', + migrated: 'MIGRATED' }, - default: 'sheet', - // eslint-disable-next-line @typescript-eslint/no-misused-promises - onChange: closeAllMoveSheets + default: 'migrated' }) + // Ruleset selection, one for each supported ruleset + for (const key of RULESETS) { + game.settings.register('foundry-ironsworn', `ruleset-${key}`, { + scope: 'world', + config: false, + type: Boolean, + default: key === 'classic' + }) + } + // Appearance settings. They're impactful and not especially esoteric/technical, so they come next. game.settings.register('foundry-ironsworn', 'theme', { name: 'IRONSWORN.Settings.Theme.Name', @@ -161,7 +170,7 @@ export class IronswornSettings { type: Boolean, default: true }) - game.settings.register('foundry-ironsworn', 'prompt-world-truths', { + game.settings.register('foundry-ironsworn', 'show-first-start-dialog', { name: 'IRONSWORN.Settings.PromptTruths.Name', hint: 'IRONSWORN.Settings.PromptTruths.Hint', scope: 'world', @@ -248,6 +257,13 @@ export class IronswornSettings { return game.settings.get('foundry-ironsworn', key) } + static async set( + key: K, + value: ClientSettings.Values[`foundry-ironsworn.${K}`] + ) { + return await game.settings.set('foundry-ironsworn', key, value) + } + static get defaultToolbox(): 'ironsworn' | 'starforged' | 'sunderedisles' { const setting = this.get('toolbox') if (setting === 'sheet') { @@ -266,7 +282,7 @@ export class IronswornSettings { } /** - * Upddate all actors of the provided types with a single data object. + * Update all actors of the provided types with a single data object. * @param data The data to pass to each actor's `update()` method. * @param actorTypes The subtypes of actor to apply the change to. */ @@ -283,4 +299,59 @@ export class IronswornSettings { } as any) } } + + static get enabledRulesets(): Array< + 'classic' | 'delve' | 'starforged' | 'sundered_isles' + > { + const ret: string[] = [] + for (const ruleset of RULESETS) { + if (IronswornSettings.get(`ruleset-${ruleset}`)) { + ret.push(ruleset) + } + } + return ret + } + + static async enableOnlyRulesets( + ...enabled: Array<'classic' | 'delve' | 'starforged' | 'sundered_isles'> + ) { + for (const ruleset of RULESETS) { + await game.settings.set( + 'foundry-ironsworn', + `ruleset-${ruleset}`, + enabled.includes(ruleset) + ) + } + } +} + +Hooks.once('ready', async () => { + await maybeMigrateToolbox() +}) + +async function maybeMigrateToolbox() { + let toolboxSetting = IronswornSettings.get('toolbox') + if (toolboxSetting === 'migrated') return + + if (toolboxSetting === 'sheet') { + // Process this as the sheet setting + toolboxSetting = IronswornSettings.defaultToolbox + } + + switch (toolboxSetting) { + case 'ironsworn': + await IronswornSettings.enableOnlyRulesets('classic', 'delve') + break + + case 'starforged': + await IronswornSettings.enableOnlyRulesets('starforged') + break + + case 'sunderedisles': + await IronswornSettings.enableOnlyRulesets('starforged', 'sundered_isles') + break + } + + // Only do this once + await game.settings.set('foundry-ironsworn', 'toolbox', 'migrated') } diff --git a/src/module/roll-table/oracle-table.ts b/src/module/roll-table/oracle-table.ts index 1c310cdaa..8e3f6dc6d 100644 --- a/src/module/roll-table/oracle-table.ts +++ b/src/module/roll-table/oracle-table.ts @@ -17,6 +17,13 @@ import type { IronswornJournalPage } from '../journal/journal-entry-page' import { OracleTableResult } from './oracle-table-result' import type { ComputedTableType } from './roll-table-types' +export const DS_ORACLE_COMPENDIUM_KEYS: Record = { + classic: 'foundry-ironsworn.ironswornoracles', + delve: 'foundry-ironsworn.ironsworndelveoracles', + starforged: 'foundry-ironsworn.starforgedoracles', + sundered_isles: 'foundry-ironsworn.sunderedislesoracles' +} + /** Extends FVTT's default RollTable with functionality specific to this system. */ export class OracleTable extends RollTable { // missing from the LoFD types package @@ -91,11 +98,29 @@ export class OracleTable extends RollTable { delved?.find(matcher)) as StoredDocument | undefined } - static async getByDsId( - dsid: string - ): Promise | undefined> { + static async getIndexEntryByDsId(dsid: string) { + const parsed = IdParser.parse(dsid) + const packId = DS_ORACLE_COMPENDIUM_KEYS[parsed.rulesPackageId] + const pack = game.packs.get(packId) + const index = await pack?.getIndex({ fields: ['flags'] }) + return index?.find((entry) => { + return entry.flags?.['foundry-ironsworn']?.dsid === dsid + }) + } + + static async getByDsId(dsid: string) { + const parsed = IdParser.parse(dsid) + const packId = DS_ORACLE_COMPENDIUM_KEYS[parsed.rulesPackageId] + const pack = game.packs.get(packId) + if (!pack) return + const id = IdParser.get(dsid) - console.log(id) + const index = await pack?.getIndex({ fields: ['flags'] }) + for (const entry of index.contents) { + if (entry.flags?.['foundry-ironsworn']?.dsid === dsid) { + return pack.getDocument(entry._id) + } + } } /** @@ -112,6 +137,10 @@ export class OracleTable extends RollTable { for await (const id of ids) { let tbl: OracleTable | undefined switch (true) { + case /^oracle_rollable:/i.test(id): + // A Datasworn 2 ID + tbl = await OracleTable.getByDsId(id) + break case /^(ironsworn|starforged)\/oracles/i.test(id): // A Dataforged ID tbl = await OracleTable.getByDfId(id) diff --git a/src/module/vue/components/sf-moverow.vue b/src/module/vue/components/sf-moverow.vue index e68dda6ad..1136483f2 100644 --- a/src/module/vue/components/sf-moverow.vue +++ b/src/module/vue/components/sf-moverow.vue @@ -149,6 +149,7 @@ const toggleTooltip = ref($item.value.system.Trigger?.Text) const moveId = computed(() => props.move.moveItem().id) +// TODO: switch this to use datasworn data const oracleIds = uniq([ ...($item?.value.system.Oracles ?? []), ...(props.move.dataforgedMove?.Oracles ?? []) diff --git a/src/module/vue/components/sf-movesheetoracles.vue b/src/module/vue/components/sf-movesheetoracles.vue index 822ea324e..4b3472b53 100644 --- a/src/module/vue/components/sf-movesheetoracles.vue +++ b/src/module/vue/components/sf-movesheetoracles.vue @@ -26,33 +26,34 @@
- +
+

+ {{ section.displayName }} +

+ +
diff --git a/src/module/vue/sf-charactermovesheet.vue b/src/module/vue/sf-charactermovesheet.vue index 9a4ae1f5b..9200aa208 100644 --- a/src/module/vue/sf-charactermovesheet.vue +++ b/src/module/vue/sf-charactermovesheet.vue @@ -30,11 +30,7 @@ - + diff --git a/system/assets/welcome/ironsworn-sheet.jpg b/system/assets/welcome/ironsworn-sheet.jpg index 1dd672de0..3da3dda1f 100644 Binary files a/system/assets/welcome/ironsworn-sheet.jpg and b/system/assets/welcome/ironsworn-sheet.jpg differ diff --git a/system/assets/welcome/starforged-sheet.jpg b/system/assets/welcome/starforged-sheet.jpg index 26e4ba369..5826e279f 100644 Binary files a/system/assets/welcome/starforged-sheet.jpg and b/system/assets/welcome/starforged-sheet.jpg differ diff --git a/system/lang/en.json b/system/lang/en.json index cc042785c..69b4305a1 100644 --- a/system/lang/en.json +++ b/system/lang/en.json @@ -1,8 +1,16 @@ { "IRONSWORN": { "Ironsworn": "Ironsworn", + "IronswornClassic": "Ironsworn Classic", "Starforged": "Starforged", "SunderedIsles": "Sundered Isles", + "RULESETS": { + "Rulesets": "Rulesets", + "classic": "Ironsworn Classic", + "delve": "Ironsworn: Delve", + "starforged": "Starforged", + "sundered_isles": "Sundered Isles" + }, "YourWorldTruths": "Your World: Truths", "TruthsAreOptional": "Creating truths is an optional step. You can always come back to this later in the settings.", "TruthQuestStarter": "Quest Starter:", @@ -325,7 +333,7 @@ }, "PromptTruths": { "Name": "Configuration Dialog on Start", - "Hint": "Open the above dialog on the next reload." + "Hint": "Open the configuration dialog on the next reload." }, "ConfigurationDialog": { "Label": "Configuration Dialog", @@ -362,6 +370,10 @@ "First Start": { "Welcome": "Welcome", "Intro": "Please choose which system you'll be primarily using. This sets sheet and move/oracle defaults; more detailed options are available in the settings.", + "SheetTitle": "Character Sheet", + "SheetHint": "Choose the default sheet to use for characters.", + "RulesetsTitle": "Rulesets", + "RulesetsHint": "Choose which books' content should be active in this world.", "SettingTruths": "Setting Truths", "SettingTruth": "Setting Truth" }, @@ -562,6 +574,48 @@ } }, "OracleCategories": { + "Action and Theme Oracles": "Action and Theme Oracles", + "Other Names": "Other Names", + "Place Oracles": "Place Oracles", + "Settlement Name": "Settlement Name", + "Quick Settlement Name Generator": "Quick Settlement Name Generator", + "Turning Point Oracles": "Turning Point Oracles", + "Character Oracles": "Character Oracles", + "Core Oracles": "Core Oracles", + "Creature Basic Form": "Creature Basic Form", + "Creature Oracles": "Creature Oracles", + "Derelict Type (by location)": "Derelict Type (by location)", + "Derelict Zones": "Derelict Zones", + "Derelict Oracles": "Derelict Oracles", + "Faction Name": "Faction Name", + "Faction Oracles": "Faction Oracles", + "Step 5: Board Your Starship": "Step 5: Board Your Starship", + "Create Your Character": "Create Your Character", + "Build Your Starting Sector": "Build Your Starting Sector", + "Begin Your Adventure": "Begin Your Adventure", + "Launching Your Campaign": "Launching Your Campaign", + "Location Theme Oracles": "Location Theme Oracles", + "Miscellaneous Oracles": "Miscellaneous Oracles", + "Desert World": "Desert World", + "Furnace World": "Furnace World", + "Grave World": "Grave World", + "Ice World": "Ice World", + "Jovian World": "Jovian World", + "Jungle World": "Jungle World", + "Ocean World": "Ocean World", + "Rocky World": "Rocky World", + "Shattered World": "Shattered World", + "Tainted World": "Tainted World", + "Vital World": "Vital World", + "Planetside Peril": "Planetside Peril", + "Planetside Opportunity": "Planetside Opportunity", + "Planet Oracles": "Planet Oracles", + "Precursor Vault Oracles": "Precursor Vault Oracles", + "Settlement Oracles": "Settlement Oracles", + "Space Sighting": "Space Sighting", + "Space Encounter Oracles": "Space Encounter Oracles", + "Starship Mission": "Starship Mission", + "Starship Oracles": "Starship Oracles", "Access": "Access", "Action and Theme": "Action and Theme", "Ask the Oracle": "Ask the Oracle", @@ -634,6 +688,63 @@ "Vaults": "Vaults", "Vital": "Vital", "Zones": "Zones", + "Factions of the Isles": "Factions of the Isles", + "Beasts of the Isles": "Beasts of the Isles", + "Adventures Among the Isles": "Adventures Among the Isles", + "Cave Scale": "Cave Scale", + "Sea Cave Details": "Sea Cave Details", + "Inland Cave Details": "Inland Cave Details", + "Cave Oracles": "Cave Oracles", + "Character Role Details": "Character Role Details", + "Cursed Moniker": "Cursed Moniker", + "Society": "Society", + "Organization": "Organization", + "Empire": "Empire", + "The Cursed": "The Cursed", + "Affluence": "Affluence", + "Craft": "Craft", + "Discovery": "Discovery", + "Faith": "Faith", + "Loyalty": "Loyalty", + "Mysticism": "Mysticism", + "Rebellion": "Rebellion", + "Secrecy": "Secrecy", + "War": "War", + "Curses": "Curses", + "Faction Name: Themes": "Faction Name: Themes", + "Take Command": "Take Command", + "Chart Your Course": "Chart Your Course", + "Getting Underway": "Getting Underway", + "Vitality": "Vitality", + "Island Landscape": "Island Landscape", + "Visible Habitation": "Visible Habitation", + "Nearby Islands": "Nearby Islands", + "Island Oracles": "Island Oracles", + "Magnitude": "Magnitude", + "Local Seas": "Local Seas", + "Overland Waypoints": "Overland Waypoints", + "Region Landmarks": "Region Landmarks", + "Overland Oracles": "Overland Oracles", + "Ruin Oracles": "Ruin Oracles", + "Known Waters": "Known Waters", + "Unknown Waters": "Unknown Waters", + "Seafaring Waypoints": "Seafaring Waypoints", + "Seafaring Oracles": "Seafaring Oracles", + "Settlement Size": "Settlement Size", + "Settlement Controlling Faction": "Settlement Controlling Faction", + "Settlement Identity": "Settlement Identity", + "Settlement Focus": "Settlement Focus", + "Ship Position": "Ship Position", + "Ship Controlling Faction": "Ship Controlling Faction", + "Ship Mission": "Ship Mission", + "Ship Oracles": "Ship Oracles", + "Shipwreck Position": "Shipwreck Position", + "Shipwreck Orientation": "Shipwreck Orientation", + "Shipwreck Oracles": "Shipwreck Oracles", + "Treasure Value": "Treasure Value", + "Treasure Oracles": "Treasure Oracles", + "Weather Conditions": "Weather Conditions", + "Weather Oracles": "Weather Oracles", "Custom": "Custom Oracles" }, "Asset Categories": { diff --git a/system/templates/first-start.hbs b/system/templates/first-start.hbs index b05b72670..a331049b7 100644 --- a/system/templates/first-start.hbs +++ b/system/templates/first-start.hbs @@ -1,61 +1,100 @@
-

{{localize 'IRONSWORN.First Start.Welcome'}}

-

{{localize 'IRONSWORN.First Start.Intro'}}

+
+

{{localize 'IRONSWORN.First Start.SheetTitle'}}

+

{{localize 'IRONSWORN.First Start.SheetHint'}}

+
-
- Ironsworn sheet -

- {{localize 'IRONSWORN.Ironsworn'}} -

-
-
- Starforged sheet -

- {{localize 'IRONSWORN.Starforged'}} -

+
+
- - {{#if sunderedislesBeta}} -
- Sundered Isles sheet +
+
- {{/if}} + +
+
+

{{localize 'IRONSWORN.First Start.RulesetsTitle'}}

+

{{localize 'IRONSWORN.First Start.RulesetsHint'}}

+
+ + {{#*inline "rulesetCheckbox"}} + + {{/inline}} + +
+
+
+

{{localize 'IRONSWORN.Ironsworn'}}

+ {{> rulesetCheckbox rulesets.classic}} + {{> rulesetCheckbox rulesets.delve}} +
+
+

{{localize 'IRONSWORN.Starforged'}}

+ {{> rulesetCheckbox rulesets.starforged}} + {{> rulesetCheckbox rulesets.sundered_isles}} +
+
+
+ +
+ +
+