intelligent-system-design-language 0.3.21 → 0.3.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/langium-language-designer.md +38 -38
- package/.claude/agents/typescript-vscode-expert.md +29 -29
- package/.claude/agents/ui-ux-designer.md +36 -36
- package/.claude/settings.local.json +33 -33
- package/.idea/inspectionProfiles/Project_Default.xml +6 -6
- package/.idea/isdl.iml +13 -13
- package/.idea/modules.xml +8 -8
- package/.idea/vcs.xml +6 -6
- package/.idea/watcherTasks.xml +3 -3
- package/.vscodeignore +18 -18
- package/LICENSE +673 -673
- package/README.md +86 -86
- package/bin/cli.js +4 -4
- package/bin/lsp.js +8 -8
- package/out/_backgrounds.scss +91 -91
- package/out/_handlebars.scss +497 -497
- package/out/_isdlStyles.scss +1444 -1381
- package/out/_vuetifyOverrides.scss +425 -425
- package/out/_vuetifyStyles.scss +31957 -31957
- package/out/cli/components/_backgrounds.scss +91 -91
- package/out/cli/components/_handlebars.scss +497 -497
- package/out/cli/components/_isdlStyles.scss +1444 -1381
- package/out/cli/components/_vuetifyOverrides.scss +425 -425
- package/out/cli/components/_vuetifyStyles.scss +31957 -31957
- package/out/cli/components/active-effect-sheet-generator.js +453 -453
- package/out/cli/components/chat-card-generator.js +654 -651
- package/out/cli/components/chat-card-generator.js.map +1 -1
- package/out/cli/components/css-generator.js +4 -4
- package/out/cli/components/damage-roll-generator.js +160 -160
- package/out/cli/components/datamodel-generator.js +264 -257
- package/out/cli/components/datamodel-generator.js.map +1 -1
- package/out/cli/components/derived-data-generator.js +923 -923
- package/out/cli/components/hotbar-drop-hook-generator.js +82 -82
- package/out/cli/components/init-hook-generator.js +495 -495
- package/out/cli/components/language-generator.js +1 -1
- package/out/cli/components/language-generator.js.map +1 -1
- package/out/cli/components/measured-template-preview.js +221 -221
- package/out/cli/components/method-generator.js +979 -887
- package/out/cli/components/method-generator.js.map +1 -1
- package/out/cli/components/ready-hook-generator.js +404 -404
- package/out/cli/components/token-generator.js +116 -116
- package/out/cli/components/vue/base-components/vue-attribute.js +138 -138
- package/out/cli/components/vue/base-components/vue-boolean.js +64 -64
- package/out/cli/components/vue/base-components/vue-calculator.js +93 -93
- package/out/cli/components/vue/base-components/vue-damage-application.js +356 -356
- package/out/cli/components/vue/base-components/vue-damage-bonuses.js +165 -165
- package/out/cli/components/vue/base-components/vue-damage-resistances.js +196 -196
- package/out/cli/components/vue/base-components/vue-damage-track.js +121 -121
- package/out/cli/components/vue/base-components/vue-date-time.js +42 -42
- package/out/cli/components/vue/base-components/vue-dice.js +98 -98
- package/out/cli/components/vue/base-components/vue-die.js +73 -73
- package/out/cli/components/vue/base-components/vue-document-choice.js +149 -149
- package/out/cli/components/vue/base-components/vue-document-choices.js +179 -179
- package/out/cli/components/vue/base-components/vue-document-link.js +60 -60
- package/out/cli/components/vue/base-components/vue-extended-choice.js +88 -88
- package/out/cli/components/vue/base-components/vue-inventory.js +519 -519
- package/out/cli/components/vue/base-components/vue-macro-choice.js +138 -138
- package/out/cli/components/vue/base-components/vue-measured-template.js +530 -530
- package/out/cli/components/vue/base-components/vue-money.js +483 -483
- package/out/cli/components/vue/base-components/vue-number.js +174 -174
- package/out/cli/components/vue/base-components/vue-paperdoll.js +43 -43
- package/out/cli/components/vue/base-components/vue-parent-property-reference.js +76 -76
- package/out/cli/components/vue/base-components/vue-prosemirror.js +18 -18
- package/out/cli/components/vue/base-components/vue-resource.js +136 -136
- package/out/cli/components/vue/base-components/vue-roll-visualizer.js +286 -109
- package/out/cli/components/vue/base-components/vue-roll-visualizer.js.map +1 -1
- package/out/cli/components/vue/base-components/vue-self-property-reference.js +62 -62
- package/out/cli/components/vue/base-components/vue-string-choice.js +98 -98
- package/out/cli/components/vue/base-components/vue-string-choices.js +203 -203
- package/out/cli/components/vue/base-components/vue-string.js +60 -60
- package/out/cli/components/vue/base-components/vue-text-field.js +53 -53
- package/out/cli/components/vue/base-components/vue-tracker.js +431 -431
- package/out/cli/components/vue/vue-action-component-generator.js +64 -64
- package/out/cli/components/vue/vue-active-effect-sheet-generator.js +856 -856
- package/out/cli/components/vue/vue-datatable-sheet-class-generator.js +292 -292
- package/out/cli/components/vue/vue-datatable2-component-generator.js +824 -824
- package/out/cli/components/vue/vue-document-creation-app.js +121 -121
- package/out/cli/components/vue/vue-document-creation-sheet.js +94 -94
- package/out/cli/components/vue/vue-generator.js +40 -40
- package/out/cli/components/vue/vue-mixin.js +296 -296
- package/out/cli/components/vue/vue-pinned-datatable-component-generator.js +260 -260
- package/out/cli/components/vue/vue-prompt-generator.js +91 -76
- package/out/cli/components/vue/vue-prompt-generator.js.map +1 -1
- package/out/cli/components/vue/vue-prompt-sheet-class-generator.js +317 -317
- package/out/cli/components/vue/vue-sheet-application-generator.js +1177 -1167
- package/out/cli/components/vue/vue-sheet-application-generator.js.map +1 -1
- package/out/cli/components/vue/vue-sheet-class-generator.js +510 -510
- package/out/cli/generator.js +438 -433
- package/out/cli/generator.js.map +1 -1
- package/out/extension/github/githubAuthProvider.js +71 -29
- package/out/extension/github/githubAuthProvider.js.map +1 -1
- package/out/extension/github/githubGistManager.js +4 -3
- package/out/extension/github/githubGistManager.js.map +1 -1
- package/out/extension/github/githubManager.js +40 -38
- package/out/extension/github/githubManager.js.map +1 -1
- package/out/extension/github/githubQuickActions.js +120 -120
- package/out/extension/github/system-workflow.yml +47 -47
- package/out/extension/main.cjs +909 -532
- package/out/extension/main.cjs.map +3 -3
- package/out/extension/package.json +419 -419
- package/out/language/generated/ast.js +51 -2
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.js +14240 -13991
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/intelligent-system-design-language-validator.js +32 -2
- package/out/language/intelligent-system-design-language-validator.js.map +1 -1
- package/out/language/isdl-scope-provider.js +14 -1
- package/out/language/isdl-scope-provider.js.map +1 -1
- package/out/language/main.cjs +913 -569
- package/out/language/main.cjs.map +3 -3
- package/out/package.json +419 -419
- package/out/progressbar.min.js +6 -6
- package/out/styles.scss +762 -747
- package/out/test/validating/diagnostics.test.js +40 -0
- package/out/test/validating/diagnostics.test.js.map +1 -1
- package/package.json +419 -419
|
@@ -13,11 +13,11 @@ export function generateInitHookMjs(entry, id, destination) {
|
|
|
13
13
|
}
|
|
14
14
|
function generateTrackableResourceBars(document) {
|
|
15
15
|
let resourceExps = getAllOfType(document.body, isResourceExp);
|
|
16
|
-
return expandToNode `
|
|
17
|
-
"${document.name.toLowerCase()}": {
|
|
18
|
-
"bar": [${joinToNode(resourceExps, x => `"${x.name.toLowerCase()}"`, { separator: ',' })}],
|
|
19
|
-
"value": []
|
|
20
|
-
}
|
|
16
|
+
return expandToNode `
|
|
17
|
+
"${document.name.toLowerCase()}": {
|
|
18
|
+
"bar": [${joinToNode(resourceExps, x => `"${x.name.toLowerCase()}"`, { separator: ',' })}],
|
|
19
|
+
"value": []
|
|
20
|
+
}
|
|
21
21
|
`;
|
|
22
22
|
}
|
|
23
23
|
function generateStatusEffect(document) {
|
|
@@ -30,15 +30,15 @@ export function generateInitHookMjs(entry, id, destination) {
|
|
|
30
30
|
svg = "icons/svg/upgrade.svg";
|
|
31
31
|
}
|
|
32
32
|
let calculated = document.params.find(p => isStatusParamWhen(p)) ? true : false;
|
|
33
|
-
return expandToNode `
|
|
34
|
-
{
|
|
35
|
-
id: "${document.name.toLowerCase()}",
|
|
36
|
-
name: "${document.name}",
|
|
37
|
-
label: "${document.name}",
|
|
38
|
-
icon: "${svg}",
|
|
39
|
-
img: "${svg}",
|
|
40
|
-
calculated: ${calculated}
|
|
41
|
-
}
|
|
33
|
+
return expandToNode `
|
|
34
|
+
{
|
|
35
|
+
id: "${document.name.toLowerCase()}",
|
|
36
|
+
name: "${document.name}",
|
|
37
|
+
label: "${document.name}",
|
|
38
|
+
icon: "${svg}",
|
|
39
|
+
img: "${svg}",
|
|
40
|
+
calculated: ${calculated}
|
|
41
|
+
}
|
|
42
42
|
`;
|
|
43
43
|
}
|
|
44
44
|
function generateKeywordConfig(entry) {
|
|
@@ -46,13 +46,13 @@ export function generateInitHookMjs(entry, id, destination) {
|
|
|
46
46
|
if (keywords.size === 0) {
|
|
47
47
|
return expandToNode ``;
|
|
48
48
|
}
|
|
49
|
-
return joinToNode(Array.from(keywords.entries()), ([key, data]) => `${key}: {
|
|
50
|
-
name: "${data.name}",
|
|
51
|
-
description: "${data.description.replace(/"/g, '\\"')}",
|
|
52
|
-
color: "${data.color}",
|
|
53
|
-
icon: "${data.icon}",
|
|
54
|
-
type: "${data.type}"${data.label ? `,
|
|
55
|
-
label: "${data.label}"` : ''}
|
|
49
|
+
return joinToNode(Array.from(keywords.entries()), ([key, data]) => `${key}: {
|
|
50
|
+
name: "${data.name}",
|
|
51
|
+
description: "${data.description.replace(/"/g, '\\"')}",
|
|
52
|
+
color: "${data.color}",
|
|
53
|
+
icon: "${data.icon}",
|
|
54
|
+
type: "${data.type}"${data.label ? `,
|
|
55
|
+
label: "${data.label}"` : ''}
|
|
56
56
|
}`, { separator: ',\n ' }) || expandToNode ``;
|
|
57
57
|
}
|
|
58
58
|
function generateMacroActionConfig(entry) {
|
|
@@ -74,24 +74,24 @@ export function generateInitHookMjs(entry, id, destination) {
|
|
|
74
74
|
function generateRegisterStatusEffects() {
|
|
75
75
|
let statusEffects = getAllOfType(entry.documents, isStatusProperty, false);
|
|
76
76
|
if (statusEffects.length === 0)
|
|
77
|
-
return expandToNode `
|
|
78
|
-
function registerStatusEffects() {
|
|
79
|
-
game.system.statusEffects = [];
|
|
80
|
-
}
|
|
77
|
+
return expandToNode `
|
|
78
|
+
function registerStatusEffects() {
|
|
79
|
+
game.system.statusEffects = [];
|
|
80
|
+
}
|
|
81
81
|
`;
|
|
82
82
|
let hasDead = statusEffects.find(x => x.name.toLowerCase() === "dead");
|
|
83
|
-
return expandToNode `
|
|
84
|
-
function registerStatusEffects() {
|
|
85
|
-
CONFIG.statusEffects = [
|
|
86
|
-
${hasDead ? '' : `{"id":"dead","name":"EFFECT.StatusDead","img":"icons/svg/skull.svg"},`}
|
|
87
|
-
{"id":"unconscious","name":"EFFECT.StatusUnconscious","img":"icons/svg/unconscious.svg"},
|
|
88
|
-
{"id":"invisible","name":"EFFECT.StatusInvisible","img":"icons/svg/invisible.svg"},
|
|
89
|
-
${joinToNode(statusEffects, generateStatusEffect, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
90
|
-
];
|
|
91
|
-
|
|
92
|
-
// Also store for journal generation
|
|
93
|
-
game.system.statusEffects = CONFIG.statusEffects;
|
|
94
|
-
}
|
|
83
|
+
return expandToNode `
|
|
84
|
+
function registerStatusEffects() {
|
|
85
|
+
CONFIG.statusEffects = [
|
|
86
|
+
${hasDead ? '' : `{"id":"dead","name":"EFFECT.StatusDead","img":"icons/svg/skull.svg"},`}
|
|
87
|
+
{"id":"unconscious","name":"EFFECT.StatusUnconscious","img":"icons/svg/unconscious.svg"},
|
|
88
|
+
{"id":"invisible","name":"EFFECT.StatusInvisible","img":"icons/svg/invisible.svg"},
|
|
89
|
+
${joinToNode(statusEffects, generateStatusEffect, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// Also store for journal generation
|
|
93
|
+
game.system.statusEffects = CONFIG.statusEffects;
|
|
94
|
+
}
|
|
95
95
|
`.appendNewLine();
|
|
96
96
|
}
|
|
97
97
|
let actorDocs = entry.documents.filter(d => isActor(d)).map(d => d);
|
|
@@ -127,474 +127,474 @@ export function generateInitHookMjs(entry, id, destination) {
|
|
|
127
127
|
return `${document.name.toLowerCase()}${identity}: ${document.name}${identity}PromptApp`;
|
|
128
128
|
}), { appendNewLineIfNotEmpty: true, separator: ',' });
|
|
129
129
|
}
|
|
130
|
-
const fileNode = expandToNode `
|
|
131
|
-
${joinToNode(entry.documents, document => `import ${document.name}TypeDataModel from "../datamodels/${isActor(document) ? "actor" : "item"}/${document.name.toLowerCase()}.mjs"`, { appendNewLineIfNotEmpty: true })}
|
|
132
|
-
${joinToNode(entry.documents, document => `import ${document.name}VueSheet from "../sheets/vue/${isActor(document) ? "actor" : "item"}/${document.name.toLowerCase()}-sheet.mjs"`, { appendNewLineIfNotEmpty: true })}
|
|
133
|
-
import DataTableApp from "../sheets/vue/datatable-app.mjs";
|
|
134
|
-
${joinToNode(entry.documents, generateDocumentPromptImports, { appendNewLineIfNotEmpty: true })}
|
|
135
|
-
import ${entry.config.name}EffectVueSheet from "../sheets/vue/active-effect-sheet.mjs";
|
|
136
|
-
import ${entry.config.name}Actor from "../documents/actor.mjs";
|
|
137
|
-
import ${entry.config.name}Item from "../documents/item.mjs";
|
|
138
|
-
import ${entry.config.name}Combatant from "../documents/combatant.mjs";
|
|
139
|
-
import ${entry.config.name}TokenDocument from "../documents/token.mjs";
|
|
140
|
-
import ${entry.config.name}Token from "../canvas/token.mjs";
|
|
141
|
-
import ${entry.config.name}Roll from "../rolls/roll.mjs";
|
|
142
|
-
import ${entry.config.name}DamageRoll from "../rolls/damage-roll.mjs";
|
|
143
|
-
import DocumentCreationVueDialog from "../sheets/vue/document-creation-dialog.mjs";
|
|
144
|
-
import MeasuredTemplatePreview from "../placeables/measured-template-preview.mjs";
|
|
145
|
-
|
|
146
|
-
export function init() {
|
|
147
|
-
console.log('${id} | Initializing System');
|
|
148
|
-
|
|
149
|
-
CONFIG.ActiveEffect.legacyTransferral = false;
|
|
150
|
-
|
|
151
|
-
registerSettings();
|
|
152
|
-
registerDataModels();
|
|
153
|
-
registerDocumentSheets();
|
|
154
|
-
registerDocumentClasses();
|
|
155
|
-
registerPromptClasses();
|
|
156
|
-
registerCanvasClasses();
|
|
157
|
-
registerTypeInfo();
|
|
158
|
-
registerHandlebarsHelpers();
|
|
159
|
-
registerResourceBars();
|
|
160
|
-
registerStatusEffects();
|
|
161
|
-
registerMacroActions();
|
|
162
|
-
registerKeywords();
|
|
163
|
-
setupKeywordEnricher();
|
|
164
|
-
registerUtils();
|
|
165
|
-
//addVueImportMap();
|
|
166
|
-
|
|
167
|
-
game.system.documentHooks = new Map();
|
|
168
|
-
game.system.datatableApp = DataTableApp;
|
|
169
|
-
game.system.rollClass = ${entry.config.name}Roll;
|
|
170
|
-
game.system.damageRollClass = ${entry.config.name}DamageRoll;
|
|
171
|
-
CONFIG.Dice.rolls.push(${entry.config.name}Roll);
|
|
172
|
-
CONFIG.Dice.rolls.push(${entry.config.name}DamageRoll);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/* -------------------------------------------- */
|
|
176
|
-
|
|
177
|
-
function registerSettings() {
|
|
178
|
-
|
|
179
|
-
game.settings.register('${id}', 'createSystemJournal', {
|
|
180
|
-
name: game.i18n.localize("SETTINGS.CreateSystemJournalName"),
|
|
181
|
-
hint: game.i18n.localize("SETTINGS.CreateSystemJournalHint"),
|
|
182
|
-
scope: 'world',
|
|
183
|
-
config: true,
|
|
184
|
-
default: true,
|
|
185
|
-
type: Boolean
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
game.settings.register('${id}', 'roundUpDamageApplication', {
|
|
189
|
-
name: game.i18n.localize("SETTINGS.RoundUpDamageApplicationName"),
|
|
190
|
-
hint: game.i18n.localize("SETTINGS.RoundUpDamageApplicationHint"),
|
|
191
|
-
scope: 'world',
|
|
192
|
-
config: true,
|
|
193
|
-
default: true,
|
|
194
|
-
type: Boolean
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
game.settings.register('${id}', 'allowTargetDamageApplication', {
|
|
198
|
-
name: game.i18n.localize('SETTINGS.AllowTargetDamageApplicationName'),
|
|
199
|
-
hint: game.i18n.localize('SETTINGS.AllowTargetDamageApplicationHint'),
|
|
200
|
-
scope: 'world',
|
|
201
|
-
config: true,
|
|
202
|
-
default: false,
|
|
203
|
-
type: Boolean,
|
|
204
|
-
requiresReload: true
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
game.settings.register('${id}', 'userTargetDamageApplicationType', {
|
|
208
|
-
scope: 'client',
|
|
209
|
-
config: false,
|
|
210
|
-
default: 'selected',
|
|
211
|
-
type: String
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
game.settings.register('${id}', 'damageApplicationChatCard', {
|
|
215
|
-
name: game.i18n.localize('SETTINGS.DamageApplicationChatCardName'),
|
|
216
|
-
hint: game.i18n.localize('SETTINGS.DamageApplicationChatCardHint'),
|
|
217
|
-
scope: 'world',
|
|
218
|
-
config: true,
|
|
219
|
-
default: 'gm',
|
|
220
|
-
type: String,
|
|
221
|
-
choices: {
|
|
222
|
-
'none': game.i18n.localize('SETTINGS.DamageApplicationChatCard.None'),
|
|
223
|
-
'public': game.i18n.localize('SETTINGS.DamageApplicationChatCard.Public'),
|
|
224
|
-
'gm': game.i18n.localize('SETTINGS.DamageApplicationChatCard.GM')
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
game.settings.register('${id}', 'hotReloadLastState', {
|
|
229
|
-
scope: 'client',
|
|
230
|
-
config: false,
|
|
231
|
-
default: { openWindows: [] },
|
|
232
|
-
type: Object
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
game.settings.register('${id}', 'documentColorThemes', {
|
|
236
|
-
scope: 'client',
|
|
237
|
-
config: false,
|
|
238
|
-
default: {},
|
|
239
|
-
type: Object
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
game.settings.register('${id}', 'documentLastState', {
|
|
243
|
-
scope: 'client',
|
|
244
|
-
config: false,
|
|
245
|
-
default: {},
|
|
246
|
-
type: Object
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
game.settings.register('${id}', 'documentTableColumns', {
|
|
250
|
-
scope: 'client',
|
|
251
|
-
config: false,
|
|
252
|
-
default: {},
|
|
253
|
-
type: Object
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/* -------------------------------------------- */
|
|
258
|
-
|
|
259
|
-
function registerDataModels() {
|
|
260
|
-
CONFIG.Actor.dataModels = {
|
|
261
|
-
${joinToNode(entry.documents.filter(d => isActor(d)), document => `${document.name.toLowerCase()}: ${document.name}TypeDataModel`, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
CONFIG.Item.dataModels = {
|
|
265
|
-
${joinToNode(entry.documents.filter(d => isItem(d)), document => `${document.name.toLowerCase()}: ${document.name}TypeDataModel`, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/* -------------------------------------------- */
|
|
270
|
-
|
|
271
|
-
function registerDocumentSheets() {
|
|
272
|
-
Actors.unregisterSheet("core", ActorSheet);
|
|
273
|
-
Items.unregisterSheet("core", ItemSheet);
|
|
274
|
-
|
|
275
|
-
// Actors
|
|
276
|
-
${joinToNode(entry.documents.filter(d => isActor(d)), document => `Actors.registerSheet("${id}", ${document.name}VueSheet, {types: ["${document.name.toLowerCase()}"], makeDefault: true});`, { appendNewLineIfNotEmpty: true })}
|
|
277
|
-
|
|
278
|
-
// Items
|
|
279
|
-
${joinToNode(entry.documents.filter(d => isItem(d)), document => `Items.registerSheet("${id}", ${document.name}VueSheet, {types: ["${document.name.toLowerCase()}"], makeDefault: true});`, { appendNewLineIfNotEmpty: true })}
|
|
280
|
-
|
|
281
|
-
// Active Effects
|
|
282
|
-
DocumentSheetConfig.registerSheet(ActiveEffect, "${id}", ${entry.config.name}EffectVueSheet, { makeDefault: true });
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/* -------------------------------------------- */
|
|
286
|
-
|
|
287
|
-
function registerDocumentClasses() {
|
|
288
|
-
CONFIG.Actor.documentClass = ${entry.config.name}Actor;
|
|
289
|
-
CONFIG.Item.documentClass = ${entry.config.name}Item;
|
|
290
|
-
CONFIG.Combatant.documentClass = ${entry.config.name}Combatant;
|
|
291
|
-
CONFIG.Token.documentClass = ${entry.config.name}TokenDocument;
|
|
292
|
-
|
|
293
|
-
game.system.measuredTemplatePreviewClass = MeasuredTemplatePreview;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/* -------------------------------------------- */
|
|
297
|
-
|
|
298
|
-
function registerPromptClasses() {
|
|
299
|
-
game.system.prompts = {
|
|
300
|
-
${joinToNode(entry.documents, document => generateDocumentPromptAssignment(document), { separator: ',\n' })}
|
|
301
|
-
};
|
|
302
|
-
game.system.documentCreateDialog = DocumentCreationVueDialog;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/* -------------------------------------------- */
|
|
306
|
-
|
|
307
|
-
function registerCanvasClasses() {
|
|
308
|
-
CONFIG.Token.objectClass = ${entry.config.name}Token;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/* -------------------------------------------- */
|
|
312
|
-
|
|
313
|
-
function registerTypeInfo() {
|
|
314
|
-
CONFIG.Actor.defaultType = "${actorDefaultType}";
|
|
315
|
-
CONFIG.Item.defaultType = "${itemDefaultType}";
|
|
316
|
-
|
|
317
|
-
CONFIG.Actor.typeArtworks = {
|
|
130
|
+
const fileNode = expandToNode `
|
|
131
|
+
${joinToNode(entry.documents, document => `import ${document.name}TypeDataModel from "../datamodels/${isActor(document) ? "actor" : "item"}/${document.name.toLowerCase()}.mjs"`, { appendNewLineIfNotEmpty: true })}
|
|
132
|
+
${joinToNode(entry.documents, document => `import ${document.name}VueSheet from "../sheets/vue/${isActor(document) ? "actor" : "item"}/${document.name.toLowerCase()}-sheet.mjs"`, { appendNewLineIfNotEmpty: true })}
|
|
133
|
+
import DataTableApp from "../sheets/vue/datatable-app.mjs";
|
|
134
|
+
${joinToNode(entry.documents, generateDocumentPromptImports, { appendNewLineIfNotEmpty: true })}
|
|
135
|
+
import ${entry.config.name}EffectVueSheet from "../sheets/vue/active-effect-sheet.mjs";
|
|
136
|
+
import ${entry.config.name}Actor from "../documents/actor.mjs";
|
|
137
|
+
import ${entry.config.name}Item from "../documents/item.mjs";
|
|
138
|
+
import ${entry.config.name}Combatant from "../documents/combatant.mjs";
|
|
139
|
+
import ${entry.config.name}TokenDocument from "../documents/token.mjs";
|
|
140
|
+
import ${entry.config.name}Token from "../canvas/token.mjs";
|
|
141
|
+
import ${entry.config.name}Roll from "../rolls/roll.mjs";
|
|
142
|
+
import ${entry.config.name}DamageRoll from "../rolls/damage-roll.mjs";
|
|
143
|
+
import DocumentCreationVueDialog from "../sheets/vue/document-creation-dialog.mjs";
|
|
144
|
+
import MeasuredTemplatePreview from "../placeables/measured-template-preview.mjs";
|
|
145
|
+
|
|
146
|
+
export function init() {
|
|
147
|
+
console.log('${id} | Initializing System');
|
|
148
|
+
|
|
149
|
+
CONFIG.ActiveEffect.legacyTransferral = false;
|
|
150
|
+
|
|
151
|
+
registerSettings();
|
|
152
|
+
registerDataModels();
|
|
153
|
+
registerDocumentSheets();
|
|
154
|
+
registerDocumentClasses();
|
|
155
|
+
registerPromptClasses();
|
|
156
|
+
registerCanvasClasses();
|
|
157
|
+
registerTypeInfo();
|
|
158
|
+
registerHandlebarsHelpers();
|
|
159
|
+
registerResourceBars();
|
|
160
|
+
registerStatusEffects();
|
|
161
|
+
registerMacroActions();
|
|
162
|
+
registerKeywords();
|
|
163
|
+
setupKeywordEnricher();
|
|
164
|
+
registerUtils();
|
|
165
|
+
//addVueImportMap();
|
|
166
|
+
|
|
167
|
+
game.system.documentHooks = new Map();
|
|
168
|
+
game.system.datatableApp = DataTableApp;
|
|
169
|
+
game.system.rollClass = ${entry.config.name}Roll;
|
|
170
|
+
game.system.damageRollClass = ${entry.config.name}DamageRoll;
|
|
171
|
+
CONFIG.Dice.rolls.push(${entry.config.name}Roll);
|
|
172
|
+
CONFIG.Dice.rolls.push(${entry.config.name}DamageRoll);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* -------------------------------------------- */
|
|
176
|
+
|
|
177
|
+
function registerSettings() {
|
|
178
|
+
|
|
179
|
+
game.settings.register('${id}', 'createSystemJournal', {
|
|
180
|
+
name: game.i18n.localize("SETTINGS.CreateSystemJournalName"),
|
|
181
|
+
hint: game.i18n.localize("SETTINGS.CreateSystemJournalHint"),
|
|
182
|
+
scope: 'world',
|
|
183
|
+
config: true,
|
|
184
|
+
default: true,
|
|
185
|
+
type: Boolean
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
game.settings.register('${id}', 'roundUpDamageApplication', {
|
|
189
|
+
name: game.i18n.localize("SETTINGS.RoundUpDamageApplicationName"),
|
|
190
|
+
hint: game.i18n.localize("SETTINGS.RoundUpDamageApplicationHint"),
|
|
191
|
+
scope: 'world',
|
|
192
|
+
config: true,
|
|
193
|
+
default: true,
|
|
194
|
+
type: Boolean
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
game.settings.register('${id}', 'allowTargetDamageApplication', {
|
|
198
|
+
name: game.i18n.localize('SETTINGS.AllowTargetDamageApplicationName'),
|
|
199
|
+
hint: game.i18n.localize('SETTINGS.AllowTargetDamageApplicationHint'),
|
|
200
|
+
scope: 'world',
|
|
201
|
+
config: true,
|
|
202
|
+
default: false,
|
|
203
|
+
type: Boolean,
|
|
204
|
+
requiresReload: true
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
game.settings.register('${id}', 'userTargetDamageApplicationType', {
|
|
208
|
+
scope: 'client',
|
|
209
|
+
config: false,
|
|
210
|
+
default: 'selected',
|
|
211
|
+
type: String
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
game.settings.register('${id}', 'damageApplicationChatCard', {
|
|
215
|
+
name: game.i18n.localize('SETTINGS.DamageApplicationChatCardName'),
|
|
216
|
+
hint: game.i18n.localize('SETTINGS.DamageApplicationChatCardHint'),
|
|
217
|
+
scope: 'world',
|
|
218
|
+
config: true,
|
|
219
|
+
default: 'gm',
|
|
220
|
+
type: String,
|
|
221
|
+
choices: {
|
|
222
|
+
'none': game.i18n.localize('SETTINGS.DamageApplicationChatCard.None'),
|
|
223
|
+
'public': game.i18n.localize('SETTINGS.DamageApplicationChatCard.Public'),
|
|
224
|
+
'gm': game.i18n.localize('SETTINGS.DamageApplicationChatCard.GM')
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
game.settings.register('${id}', 'hotReloadLastState', {
|
|
229
|
+
scope: 'client',
|
|
230
|
+
config: false,
|
|
231
|
+
default: { openWindows: [] },
|
|
232
|
+
type: Object
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
game.settings.register('${id}', 'documentColorThemes', {
|
|
236
|
+
scope: 'client',
|
|
237
|
+
config: false,
|
|
238
|
+
default: {},
|
|
239
|
+
type: Object
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
game.settings.register('${id}', 'documentLastState', {
|
|
243
|
+
scope: 'client',
|
|
244
|
+
config: false,
|
|
245
|
+
default: {},
|
|
246
|
+
type: Object
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
game.settings.register('${id}', 'documentTableColumns', {
|
|
250
|
+
scope: 'client',
|
|
251
|
+
config: false,
|
|
252
|
+
default: {},
|
|
253
|
+
type: Object
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* -------------------------------------------- */
|
|
258
|
+
|
|
259
|
+
function registerDataModels() {
|
|
260
|
+
CONFIG.Actor.dataModels = {
|
|
261
|
+
${joinToNode(entry.documents.filter(d => isActor(d)), document => `${document.name.toLowerCase()}: ${document.name}TypeDataModel`, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
CONFIG.Item.dataModels = {
|
|
265
|
+
${joinToNode(entry.documents.filter(d => isItem(d)), document => `${document.name.toLowerCase()}: ${document.name}TypeDataModel`, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* -------------------------------------------- */
|
|
270
|
+
|
|
271
|
+
function registerDocumentSheets() {
|
|
272
|
+
Actors.unregisterSheet("core", ActorSheet);
|
|
273
|
+
Items.unregisterSheet("core", ItemSheet);
|
|
274
|
+
|
|
275
|
+
// Actors
|
|
276
|
+
${joinToNode(entry.documents.filter(d => isActor(d)), document => `Actors.registerSheet("${id}", ${document.name}VueSheet, {types: ["${document.name.toLowerCase()}"], makeDefault: true});`, { appendNewLineIfNotEmpty: true })}
|
|
277
|
+
|
|
278
|
+
// Items
|
|
279
|
+
${joinToNode(entry.documents.filter(d => isItem(d)), document => `Items.registerSheet("${id}", ${document.name}VueSheet, {types: ["${document.name.toLowerCase()}"], makeDefault: true});`, { appendNewLineIfNotEmpty: true })}
|
|
280
|
+
|
|
281
|
+
// Active Effects
|
|
282
|
+
DocumentSheetConfig.registerSheet(ActiveEffect, "${id}", ${entry.config.name}EffectVueSheet, { makeDefault: true });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* -------------------------------------------- */
|
|
286
|
+
|
|
287
|
+
function registerDocumentClasses() {
|
|
288
|
+
CONFIG.Actor.documentClass = ${entry.config.name}Actor;
|
|
289
|
+
CONFIG.Item.documentClass = ${entry.config.name}Item;
|
|
290
|
+
CONFIG.Combatant.documentClass = ${entry.config.name}Combatant;
|
|
291
|
+
CONFIG.Token.documentClass = ${entry.config.name}TokenDocument;
|
|
292
|
+
|
|
293
|
+
game.system.measuredTemplatePreviewClass = MeasuredTemplatePreview;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* -------------------------------------------- */
|
|
297
|
+
|
|
298
|
+
function registerPromptClasses() {
|
|
299
|
+
game.system.prompts = {
|
|
300
|
+
${joinToNode(entry.documents, document => generateDocumentPromptAssignment(document), { separator: ',\n' })}
|
|
301
|
+
};
|
|
302
|
+
game.system.documentCreateDialog = DocumentCreationVueDialog;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/* -------------------------------------------- */
|
|
306
|
+
|
|
307
|
+
function registerCanvasClasses() {
|
|
308
|
+
CONFIG.Token.objectClass = ${entry.config.name}Token;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* -------------------------------------------- */
|
|
312
|
+
|
|
313
|
+
function registerTypeInfo() {
|
|
314
|
+
CONFIG.Actor.defaultType = "${actorDefaultType}";
|
|
315
|
+
CONFIG.Item.defaultType = "${itemDefaultType}";
|
|
316
|
+
|
|
317
|
+
CONFIG.Actor.typeArtworks = {
|
|
318
318
|
${joinToNode(actorArtworks, document => {
|
|
319
319
|
var _a, _b;
|
|
320
320
|
const path = (_b = (_a = document.params.find(p => isDocumentSvgParam(p))) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
|
|
321
321
|
const fullPath = path.startsWith('/icons/') ? path : `systems/${id}/${path}`;
|
|
322
322
|
return `"${document.name.toLowerCase()}": "${fullPath}"`;
|
|
323
|
-
}, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
CONFIG.Item.typeArtworks = {
|
|
323
|
+
}, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
CONFIG.Item.typeArtworks = {
|
|
327
327
|
${joinToNode(itemArtworks, document => {
|
|
328
328
|
var _a, _b;
|
|
329
329
|
const path = (_b = (_a = document.params.find(p => isDocumentSvgParam(p))) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '';
|
|
330
330
|
const fullPath = path.startsWith('/icons/') ? path : `systems/${id}/${path}`;
|
|
331
331
|
return `"${document.name.toLowerCase()}": "${fullPath}"`;
|
|
332
|
-
}, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
CONFIG.Actor.typeDescriptions = {
|
|
336
|
-
${joinToNode(actorDescriptions, document => { var _a; return `"${document.name.toLowerCase()}": "${(_a = document.params.find(p => isDocumentDescriptionParam(p))) === null || _a === void 0 ? void 0 : _a.value}"`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
337
|
-
}
|
|
338
|
-
CONFIG.Item.typeDescriptions = {
|
|
339
|
-
${joinToNode(itemDescriptions, document => { var _a; return `"${document.name.toLowerCase()}": "${(_a = document.params.find(p => isDocumentDescriptionParam(p))) === null || _a === void 0 ? void 0 : _a.value}"`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
CONFIG.Actor.typeCreatables = {
|
|
343
|
-
${joinToNode(actorCreatables, document => { var _a; return `"${document.name.toLowerCase()}": ${(_a = document.params.find(p => isDocumentCreatableParam(p))) === null || _a === void 0 ? void 0 : _a.value}`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
344
|
-
}
|
|
345
|
-
CONFIG.Item.typeCreatables = {
|
|
346
|
-
${joinToNode(itemCreatables, document => { var _a; return `"${document.name.toLowerCase()}": ${(_a = document.params.find(p => isDocumentCreatableParam(p))) === null || _a === void 0 ? void 0 : _a.value}`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/* -------------------------------------------- */
|
|
351
|
-
|
|
352
|
-
function registerHandlebarsHelpers() {
|
|
353
|
-
|
|
354
|
-
// Convert a type and value to a localized label
|
|
355
|
-
Handlebars.registerHelper("typeLabel", (type, value) => {
|
|
356
|
-
return game.i18n.localize(CONFIG.SYSTEM[type][value]?.label);
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
// Truncate a string to a certain length with an ellipsis
|
|
360
|
-
Handlebars.registerHelper("truncate", (str, len) => {
|
|
361
|
-
if (str.length > len) {
|
|
362
|
-
return \`\${str.slice(0, len)}...\`;
|
|
363
|
-
}
|
|
364
|
-
return str;
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
// Get a property on an object using a string key
|
|
368
|
-
Handlebars.registerHelper("getProperty", (obj, key) => {
|
|
369
|
-
if (obj == null) return "";
|
|
370
|
-
return foundry.utils.getProperty(obj, key);
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
// Humanize a string
|
|
374
|
-
Handlebars.registerHelper("humanize", (str) => {
|
|
375
|
-
let humanized = str.replace(/_/g, " ");
|
|
376
|
-
humanized = humanized.replace("system.", "").replaceAll(".", " ");
|
|
377
|
-
humanized = humanized.charAt(0).toUpperCase() + humanized.slice(1);
|
|
378
|
-
return humanized;
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/* -------------------------------------------- */
|
|
383
|
-
|
|
384
|
-
function registerResourceBars() {
|
|
385
|
-
CONFIG.Actor.trackableAttributes = {
|
|
386
|
-
${joinToNode(entry.documents.filter(d => isActor(d)), document => generateTrackableResourceBars(document), { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/* -------------------------------------------- */
|
|
391
|
-
|
|
392
|
-
${generateRegisterStatusEffects()}
|
|
393
|
-
|
|
394
|
-
/* -------------------------------------------- */
|
|
395
|
-
|
|
396
|
-
function registerMacroActions() {
|
|
397
|
-
game.system.macroActions = {
|
|
398
|
-
${generateMacroActionConfig(entry)}
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/* -------------------------------------------- */
|
|
403
|
-
|
|
404
|
-
function registerKeywords() {
|
|
405
|
-
game.system.keywords = {
|
|
406
|
-
${generateKeywordConfig(entry)}
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/* -------------------------------------------- */
|
|
411
|
-
|
|
412
|
-
function setupKeywordEnricher() {
|
|
413
|
-
// Register keyword text enricher
|
|
414
|
-
CONFIG.TextEditor.enrichers.push({
|
|
415
|
-
pattern: /@([a-zA-Z][a-zA-Z0-9]*)/gi,
|
|
416
|
-
replaceParent: true,
|
|
417
|
-
enricher: async (match, options) => {
|
|
418
|
-
const keywordName = match[1].toLowerCase();
|
|
419
|
-
const keyword = game.system.keywords[keywordName];
|
|
420
|
-
|
|
421
|
-
if (!keyword) return null;
|
|
422
|
-
|
|
423
|
-
// Find the system documentation journal and determine which page the keyword is on
|
|
424
|
-
const keywordsJournal = game.journal.find(j => j.getFlag('${id}', 'systemJournal') === true || j.getFlag('core', 'keywordsJournal') === true);
|
|
425
|
-
const isDamageType = keyword.type === 'damage-type';
|
|
426
|
-
const pageType = isDamageType ? 'damage-types' : 'keywords';
|
|
427
|
-
const targetPage = keywordsJournal?.pages.find(p => p.getFlag('core', 'pageType') === pageType);
|
|
428
|
-
|
|
429
|
-
const element = document.createElement('span');
|
|
430
|
-
element.className = 'keyword-reference';
|
|
431
|
-
element.setAttribute('data-keyword', keywordName);
|
|
432
|
-
element.setAttribute('data-journal-uuid', keywordsJournal?.uuid || '');
|
|
433
|
-
element.setAttribute('data-page-uuid', targetPage?.uuid || '');
|
|
434
|
-
element.setAttribute('data-anchor', keywordName);
|
|
435
|
-
element.title = keyword.description;
|
|
436
|
-
|
|
437
|
-
if (keyword.icon) {
|
|
438
|
-
const icon = document.createElement('i');
|
|
439
|
-
icon.className = keyword.icon;
|
|
440
|
-
icon.style.color = keyword.color;
|
|
441
|
-
element.appendChild(icon);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
element.appendChild(document.createTextNode(keyword.name));
|
|
445
|
-
|
|
446
|
-
return element;
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
// Register click handler for keyword references
|
|
451
|
-
$(document).on('click', '.keyword-reference', async function() {
|
|
452
|
-
const journalUuid = $(this).data('journal-uuid');
|
|
453
|
-
const pageUuid = $(this).data('page-uuid');
|
|
454
|
-
const anchor = $(this).data('anchor');
|
|
455
|
-
|
|
456
|
-
if (journalUuid && pageUuid) {
|
|
457
|
-
const journal = await fromUuid(journalUuid);
|
|
458
|
-
const page = await fromUuid(pageUuid);
|
|
459
|
-
if (journal && page) {
|
|
460
|
-
journal.sheet.render(true, {pageId: page.id, anchor: anchor});
|
|
461
|
-
}
|
|
462
|
-
} else if (journalUuid) {
|
|
463
|
-
const journal = await fromUuid(journalUuid);
|
|
464
|
-
journal?.sheet.render(true);
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/** -------------------------------------------- */
|
|
470
|
-
|
|
471
|
-
function addVueImportMap() {
|
|
472
|
-
let script = document.createElement('script');
|
|
473
|
-
script.type = 'importmap';
|
|
474
|
-
script.text = \`{
|
|
475
|
-
"imports": {
|
|
476
|
-
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
|
|
477
|
-
}
|
|
478
|
-
}\`;
|
|
479
|
-
document.head.appendChild(script);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
/* -------------------------------------------- */
|
|
483
|
-
|
|
484
|
-
function registerUtils() {
|
|
485
|
-
game.system.utils = {};
|
|
486
|
-
|
|
487
|
-
function flattenObject(obj, _d=0) {
|
|
488
|
-
const flat = {};
|
|
489
|
-
if ( _d > 100 ) {
|
|
490
|
-
throw new Error("Maximum depth exceeded");
|
|
491
|
-
}
|
|
492
|
-
for ( let [k, v] of Object.entries(obj) ) {
|
|
493
|
-
let t = foundry.utils.getType(v);
|
|
494
|
-
if ( t === "Object" ) {
|
|
495
|
-
if ( k == "parent" ) continue;
|
|
496
|
-
if ( foundry.utils.isEmpty(v) ) flat[k] = v;
|
|
497
|
-
let inner = flattenObject(v, _d+1);
|
|
498
|
-
for ( let [ik, iv] of Object.entries(inner) ) {
|
|
499
|
-
flat[\`\${k}.\${ik}\`] = iv;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
else flat[k] = v;
|
|
503
|
-
}
|
|
504
|
-
return flat;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
game.system.utils.flattenObject = flattenObject;
|
|
508
|
-
|
|
509
|
-
function toNearest(interval=1, method="round") {
|
|
510
|
-
if (!Number.isNumeric(this)) {
|
|
511
|
-
throw new Error("toNearest() must be called on a numeric looking value");
|
|
512
|
-
}
|
|
513
|
-
const number = Number.fromString(this);
|
|
514
|
-
return number.toNearest(interval, method);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
Object.defineProperties(String.prototype, {
|
|
518
|
-
toNearest: {value: toNearest}
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
async function callAllAsync(hook, ...args) {
|
|
522
|
-
if ( CONFIG.debug.hooks ) {
|
|
523
|
-
console.log(\`DEBUG | Calling async \${hook} hook with args:\`);
|
|
524
|
-
console.log(args);
|
|
525
|
-
}
|
|
526
|
-
const events = Hooks.events;
|
|
527
|
-
if ( !(hook in events) ) return true;
|
|
528
|
-
for ( const entry of Array.from(events[hook]) ) {
|
|
529
|
-
await entry.fn(...args);
|
|
530
|
-
}
|
|
531
|
-
return true;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
Hooks.callAllAsync = callAllAsync;
|
|
535
|
-
|
|
536
|
-
let audioSources = new Map();
|
|
537
|
-
let gainNodes = new Map();
|
|
538
|
-
|
|
539
|
-
async function playAudio(id, url, onEndCallback, volume=0.5) {
|
|
540
|
-
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
541
|
-
let source = audioCtx.createBufferSource();
|
|
542
|
-
let gainNode = audioCtx.createGain();
|
|
543
|
-
audioSources.set(id, source);
|
|
544
|
-
gainNodes.set(id, gainNode);
|
|
545
|
-
source.connect(gainNode).connect(audioCtx.destination);
|
|
546
|
-
|
|
547
|
-
let request = new XMLHttpRequest();
|
|
548
|
-
request.open('GET', url, true);
|
|
549
|
-
request.responseType = 'arraybuffer';
|
|
550
|
-
|
|
551
|
-
request.onload = () => {
|
|
552
|
-
let audioData = request.response;
|
|
553
|
-
audioCtx.decodeAudioData(audioData,
|
|
554
|
-
(buffer) => {
|
|
555
|
-
source.buffer = buffer;
|
|
556
|
-
gainNode.gain.value = volume;
|
|
557
|
-
source.start(0);
|
|
558
|
-
source.onended = () => {
|
|
559
|
-
audioSources.delete(id);
|
|
560
|
-
gainNodes.delete(id);
|
|
561
|
-
onEndCallback();
|
|
562
|
-
};
|
|
563
|
-
},
|
|
564
|
-
(e) => {
|
|
565
|
-
ui.notifications.error("An error occurred while decoding audio data");
|
|
566
|
-
console.log(url);
|
|
567
|
-
console.log(audioData);
|
|
568
|
-
console.log(e);
|
|
569
|
-
onEndCallback();
|
|
570
|
-
});
|
|
571
|
-
};
|
|
572
|
-
try {
|
|
573
|
-
request.send();
|
|
574
|
-
}
|
|
575
|
-
catch (e) {
|
|
576
|
-
console.error("Error playing sound effect:", e);
|
|
577
|
-
onEndCallback();
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
async function playSfx(url, volume=0.5) {
|
|
582
|
-
// Invoke the playAudio function with the provided parameters and wait for it to complete vis the onEndCallback
|
|
583
|
-
let finishedPromise = new Promise(async (resolve) => {
|
|
584
|
-
let onEndCallback = () => {
|
|
585
|
-
resolve();
|
|
586
|
-
};
|
|
587
|
-
// Attach base url
|
|
588
|
-
if (!url.startsWith("http")) {
|
|
589
|
-
url = \`\${window.location.origin}/systems/${id}/\${url}\`;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
await playAudio(foundry.utils.randomID(), url, onEndCallback, volume);
|
|
593
|
-
});
|
|
594
|
-
return finishedPromise;
|
|
595
|
-
}
|
|
596
|
-
game.system.utils.playSfx = playSfx;
|
|
597
|
-
}
|
|
332
|
+
}, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
CONFIG.Actor.typeDescriptions = {
|
|
336
|
+
${joinToNode(actorDescriptions, document => { var _a; return `"${document.name.toLowerCase()}": "${(_a = document.params.find(p => isDocumentDescriptionParam(p))) === null || _a === void 0 ? void 0 : _a.value}"`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
337
|
+
}
|
|
338
|
+
CONFIG.Item.typeDescriptions = {
|
|
339
|
+
${joinToNode(itemDescriptions, document => { var _a; return `"${document.name.toLowerCase()}": "${(_a = document.params.find(p => isDocumentDescriptionParam(p))) === null || _a === void 0 ? void 0 : _a.value}"`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
CONFIG.Actor.typeCreatables = {
|
|
343
|
+
${joinToNode(actorCreatables, document => { var _a; return `"${document.name.toLowerCase()}": ${(_a = document.params.find(p => isDocumentCreatableParam(p))) === null || _a === void 0 ? void 0 : _a.value}`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
344
|
+
}
|
|
345
|
+
CONFIG.Item.typeCreatables = {
|
|
346
|
+
${joinToNode(itemCreatables, document => { var _a; return `"${document.name.toLowerCase()}": ${(_a = document.params.find(p => isDocumentCreatableParam(p))) === null || _a === void 0 ? void 0 : _a.value}`; }, { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* -------------------------------------------- */
|
|
351
|
+
|
|
352
|
+
function registerHandlebarsHelpers() {
|
|
353
|
+
|
|
354
|
+
// Convert a type and value to a localized label
|
|
355
|
+
Handlebars.registerHelper("typeLabel", (type, value) => {
|
|
356
|
+
return game.i18n.localize(CONFIG.SYSTEM[type][value]?.label);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Truncate a string to a certain length with an ellipsis
|
|
360
|
+
Handlebars.registerHelper("truncate", (str, len) => {
|
|
361
|
+
if (str.length > len) {
|
|
362
|
+
return \`\${str.slice(0, len)}...\`;
|
|
363
|
+
}
|
|
364
|
+
return str;
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// Get a property on an object using a string key
|
|
368
|
+
Handlebars.registerHelper("getProperty", (obj, key) => {
|
|
369
|
+
if (obj == null) return "";
|
|
370
|
+
return foundry.utils.getProperty(obj, key);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Humanize a string
|
|
374
|
+
Handlebars.registerHelper("humanize", (str) => {
|
|
375
|
+
let humanized = str.replace(/_/g, " ");
|
|
376
|
+
humanized = humanized.replace("system.", "").replaceAll(".", " ");
|
|
377
|
+
humanized = humanized.charAt(0).toUpperCase() + humanized.slice(1);
|
|
378
|
+
return humanized;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* -------------------------------------------- */
|
|
383
|
+
|
|
384
|
+
function registerResourceBars() {
|
|
385
|
+
CONFIG.Actor.trackableAttributes = {
|
|
386
|
+
${joinToNode(entry.documents.filter(d => isActor(d)), document => generateTrackableResourceBars(document), { appendNewLineIfNotEmpty: true, separator: ',' })}
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/* -------------------------------------------- */
|
|
391
|
+
|
|
392
|
+
${generateRegisterStatusEffects()}
|
|
393
|
+
|
|
394
|
+
/* -------------------------------------------- */
|
|
395
|
+
|
|
396
|
+
function registerMacroActions() {
|
|
397
|
+
game.system.macroActions = {
|
|
398
|
+
${generateMacroActionConfig(entry)}
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/* -------------------------------------------- */
|
|
403
|
+
|
|
404
|
+
function registerKeywords() {
|
|
405
|
+
game.system.keywords = {
|
|
406
|
+
${generateKeywordConfig(entry)}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/* -------------------------------------------- */
|
|
411
|
+
|
|
412
|
+
function setupKeywordEnricher() {
|
|
413
|
+
// Register keyword text enricher
|
|
414
|
+
CONFIG.TextEditor.enrichers.push({
|
|
415
|
+
pattern: /@([a-zA-Z][a-zA-Z0-9]*)/gi,
|
|
416
|
+
replaceParent: true,
|
|
417
|
+
enricher: async (match, options) => {
|
|
418
|
+
const keywordName = match[1].toLowerCase();
|
|
419
|
+
const keyword = game.system.keywords[keywordName];
|
|
420
|
+
|
|
421
|
+
if (!keyword) return null;
|
|
422
|
+
|
|
423
|
+
// Find the system documentation journal and determine which page the keyword is on
|
|
424
|
+
const keywordsJournal = game.journal.find(j => j.getFlag('${id}', 'systemJournal') === true || j.getFlag('core', 'keywordsJournal') === true);
|
|
425
|
+
const isDamageType = keyword.type === 'damage-type';
|
|
426
|
+
const pageType = isDamageType ? 'damage-types' : 'keywords';
|
|
427
|
+
const targetPage = keywordsJournal?.pages.find(p => p.getFlag('core', 'pageType') === pageType);
|
|
428
|
+
|
|
429
|
+
const element = document.createElement('span');
|
|
430
|
+
element.className = 'keyword-reference';
|
|
431
|
+
element.setAttribute('data-keyword', keywordName);
|
|
432
|
+
element.setAttribute('data-journal-uuid', keywordsJournal?.uuid || '');
|
|
433
|
+
element.setAttribute('data-page-uuid', targetPage?.uuid || '');
|
|
434
|
+
element.setAttribute('data-anchor', keywordName);
|
|
435
|
+
element.title = keyword.description;
|
|
436
|
+
|
|
437
|
+
if (keyword.icon) {
|
|
438
|
+
const icon = document.createElement('i');
|
|
439
|
+
icon.className = keyword.icon;
|
|
440
|
+
icon.style.color = keyword.color;
|
|
441
|
+
element.appendChild(icon);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
element.appendChild(document.createTextNode(keyword.name));
|
|
445
|
+
|
|
446
|
+
return element;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Register click handler for keyword references
|
|
451
|
+
$(document).on('click', '.keyword-reference', async function() {
|
|
452
|
+
const journalUuid = $(this).data('journal-uuid');
|
|
453
|
+
const pageUuid = $(this).data('page-uuid');
|
|
454
|
+
const anchor = $(this).data('anchor');
|
|
455
|
+
|
|
456
|
+
if (journalUuid && pageUuid) {
|
|
457
|
+
const journal = await fromUuid(journalUuid);
|
|
458
|
+
const page = await fromUuid(pageUuid);
|
|
459
|
+
if (journal && page) {
|
|
460
|
+
journal.sheet.render(true, {pageId: page.id, anchor: anchor});
|
|
461
|
+
}
|
|
462
|
+
} else if (journalUuid) {
|
|
463
|
+
const journal = await fromUuid(journalUuid);
|
|
464
|
+
journal?.sheet.render(true);
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** -------------------------------------------- */
|
|
470
|
+
|
|
471
|
+
function addVueImportMap() {
|
|
472
|
+
let script = document.createElement('script');
|
|
473
|
+
script.type = 'importmap';
|
|
474
|
+
script.text = \`{
|
|
475
|
+
"imports": {
|
|
476
|
+
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
|
|
477
|
+
}
|
|
478
|
+
}\`;
|
|
479
|
+
document.head.appendChild(script);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* -------------------------------------------- */
|
|
483
|
+
|
|
484
|
+
function registerUtils() {
|
|
485
|
+
game.system.utils = {};
|
|
486
|
+
|
|
487
|
+
function flattenObject(obj, _d=0) {
|
|
488
|
+
const flat = {};
|
|
489
|
+
if ( _d > 100 ) {
|
|
490
|
+
throw new Error("Maximum depth exceeded");
|
|
491
|
+
}
|
|
492
|
+
for ( let [k, v] of Object.entries(obj) ) {
|
|
493
|
+
let t = foundry.utils.getType(v);
|
|
494
|
+
if ( t === "Object" ) {
|
|
495
|
+
if ( k == "parent" ) continue;
|
|
496
|
+
if ( foundry.utils.isEmpty(v) ) flat[k] = v;
|
|
497
|
+
let inner = flattenObject(v, _d+1);
|
|
498
|
+
for ( let [ik, iv] of Object.entries(inner) ) {
|
|
499
|
+
flat[\`\${k}.\${ik}\`] = iv;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
else flat[k] = v;
|
|
503
|
+
}
|
|
504
|
+
return flat;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
game.system.utils.flattenObject = flattenObject;
|
|
508
|
+
|
|
509
|
+
function toNearest(interval=1, method="round") {
|
|
510
|
+
if (!Number.isNumeric(this)) {
|
|
511
|
+
throw new Error("toNearest() must be called on a numeric looking value");
|
|
512
|
+
}
|
|
513
|
+
const number = Number.fromString(this);
|
|
514
|
+
return number.toNearest(interval, method);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
Object.defineProperties(String.prototype, {
|
|
518
|
+
toNearest: {value: toNearest}
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
async function callAllAsync(hook, ...args) {
|
|
522
|
+
if ( CONFIG.debug.hooks ) {
|
|
523
|
+
console.log(\`DEBUG | Calling async \${hook} hook with args:\`);
|
|
524
|
+
console.log(args);
|
|
525
|
+
}
|
|
526
|
+
const events = Hooks.events;
|
|
527
|
+
if ( !(hook in events) ) return true;
|
|
528
|
+
for ( const entry of Array.from(events[hook]) ) {
|
|
529
|
+
await entry.fn(...args);
|
|
530
|
+
}
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
Hooks.callAllAsync = callAllAsync;
|
|
535
|
+
|
|
536
|
+
let audioSources = new Map();
|
|
537
|
+
let gainNodes = new Map();
|
|
538
|
+
|
|
539
|
+
async function playAudio(id, url, onEndCallback, volume=0.5) {
|
|
540
|
+
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
541
|
+
let source = audioCtx.createBufferSource();
|
|
542
|
+
let gainNode = audioCtx.createGain();
|
|
543
|
+
audioSources.set(id, source);
|
|
544
|
+
gainNodes.set(id, gainNode);
|
|
545
|
+
source.connect(gainNode).connect(audioCtx.destination);
|
|
546
|
+
|
|
547
|
+
let request = new XMLHttpRequest();
|
|
548
|
+
request.open('GET', url, true);
|
|
549
|
+
request.responseType = 'arraybuffer';
|
|
550
|
+
|
|
551
|
+
request.onload = () => {
|
|
552
|
+
let audioData = request.response;
|
|
553
|
+
audioCtx.decodeAudioData(audioData,
|
|
554
|
+
(buffer) => {
|
|
555
|
+
source.buffer = buffer;
|
|
556
|
+
gainNode.gain.value = volume;
|
|
557
|
+
source.start(0);
|
|
558
|
+
source.onended = () => {
|
|
559
|
+
audioSources.delete(id);
|
|
560
|
+
gainNodes.delete(id);
|
|
561
|
+
onEndCallback();
|
|
562
|
+
};
|
|
563
|
+
},
|
|
564
|
+
(e) => {
|
|
565
|
+
ui.notifications.error("An error occurred while decoding audio data");
|
|
566
|
+
console.log(url);
|
|
567
|
+
console.log(audioData);
|
|
568
|
+
console.log(e);
|
|
569
|
+
onEndCallback();
|
|
570
|
+
});
|
|
571
|
+
};
|
|
572
|
+
try {
|
|
573
|
+
request.send();
|
|
574
|
+
}
|
|
575
|
+
catch (e) {
|
|
576
|
+
console.error("Error playing sound effect:", e);
|
|
577
|
+
onEndCallback();
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async function playSfx(url, volume=0.5) {
|
|
582
|
+
// Invoke the playAudio function with the provided parameters and wait for it to complete vis the onEndCallback
|
|
583
|
+
let finishedPromise = new Promise(async (resolve) => {
|
|
584
|
+
let onEndCallback = () => {
|
|
585
|
+
resolve();
|
|
586
|
+
};
|
|
587
|
+
// Attach base url
|
|
588
|
+
if (!url.startsWith("http")) {
|
|
589
|
+
url = \`\${window.location.origin}/systems/${id}/\${url}\`;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
await playAudio(foundry.utils.randomID(), url, onEndCallback, volume);
|
|
593
|
+
});
|
|
594
|
+
return finishedPromise;
|
|
595
|
+
}
|
|
596
|
+
game.system.utils.playSfx = playSfx;
|
|
597
|
+
}
|
|
598
598
|
`.appendNewLineIfNotEmpty();
|
|
599
599
|
fs.writeFileSync(generatedFilePath, toString(fileNode));
|
|
600
600
|
}
|