feature: generate pdf from actor
This commit is contained in:
@@ -19,7 +19,7 @@ build:
|
|||||||
- cp styles/* dist/styles/
|
- cp styles/* dist/styles/
|
||||||
- cp module.json dist
|
- cp module.json dist
|
||||||
- cd dist
|
- cd dist
|
||||||
- zip wfrp4e-actor-sheet-print.zip -r *.* src lang styles -x ".*"
|
- zip wfrp4e-actor-sheet-print.zip -r *.* elements lang styles -x ".*"
|
||||||
artifacts:
|
artifacts:
|
||||||
name: wfrp4e-actor-sheet-print
|
name: wfrp4e-actor-sheet-print
|
||||||
when: on_success
|
when: on_success
|
||||||
@@ -40,7 +40,7 @@ build_beta:
|
|||||||
- cp styles/* dist/styles/
|
- cp styles/* dist/styles/
|
||||||
- cp module-beta.json dist/module.json
|
- cp module-beta.json dist/module.json
|
||||||
- cd dist
|
- cd dist
|
||||||
- zip wfrp4e-actor-sheet-print.zip -r *.* src lang styles -x ".*"
|
- zip wfrp4e-actor-sheet-print.zip -r *.* elements lang styles -x ".*"
|
||||||
artifacts:
|
artifacts:
|
||||||
name: wfrp4e-actor-sheet-print
|
name: wfrp4e-actor-sheet-print
|
||||||
when: on_success
|
when: on_success
|
||||||
|
|||||||
@@ -28,14 +28,16 @@ export class Column extends AbstractElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getHeight(doc): number {
|
public getHeight(doc): number {
|
||||||
return this.elements
|
return this.elements.length > 0
|
||||||
|
? this.elements
|
||||||
.map((e) => e.getHeight(doc))
|
.map((e) => e.getHeight(doc))
|
||||||
.reduce((p, c, i) => {
|
.reduce((p, c, i) => {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
return p + c + 2;
|
return p + c + 2;
|
||||||
});
|
})
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCheckNewPageHeight(doc?: jsPDF): number {
|
public getCheckNewPageHeight(doc?: jsPDF): number {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class LabelledValues extends Row {
|
|||||||
const labelPercent = 100 - valuePercent;
|
const labelPercent = 100 - valuePercent;
|
||||||
const widthPercent = [labelPercent, valuePercent];
|
const widthPercent = [labelPercent, valuePercent];
|
||||||
let currentIndex = 0;
|
let currentIndex = 0;
|
||||||
if (labelledValues.length >= this.nbrOfCol) {
|
if (this.nbrOfCol > 1) {
|
||||||
const nbrPerCol = Math.floor(labelledValues.length / this.nbrOfCol);
|
const nbrPerCol = Math.floor(labelledValues.length / this.nbrOfCol);
|
||||||
const rest = labelledValues.length - nbrPerCol * this.nbrOfCol;
|
const rest = labelledValues.length - nbrPerCol * this.nbrOfCol;
|
||||||
const nbrPerCols = [
|
const nbrPerCols = [
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class Texts extends Row {
|
|||||||
this.nbrOfCol = 4;
|
this.nbrOfCol = 4;
|
||||||
}
|
}
|
||||||
let currentIndex = 0;
|
let currentIndex = 0;
|
||||||
if (texts.length >= this.nbrOfCol) {
|
if (this.nbrOfCol > 1) {
|
||||||
const nbrPerCol = Math.floor(texts.length / this.nbrOfCol);
|
const nbrPerCol = Math.floor(texts.length / this.nbrOfCol);
|
||||||
const rest = texts.length - nbrPerCol * this.nbrOfCol;
|
const rest = texts.length - nbrPerCol * this.nbrOfCol;
|
||||||
const nbrPerCols = [
|
const nbrPerCols = [
|
||||||
|
|||||||
233
src/main.ts
233
src/main.ts
@@ -88,7 +88,7 @@ Hooks.on(
|
|||||||
const weaponsMelee = new Texts(
|
const weaponsMelee = new Texts(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
actor.itemCategories.weapon
|
Util.getActorItems(actor, 'weapon')
|
||||||
.filter((w) => w.isMelee)
|
.filter((w) => w.isMelee)
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return `${item.name} : ${item.WeaponGroup}, ${item.Reach}, ${
|
return `${item.name} : ${item.WeaponGroup}, ${item.Reach}, ${
|
||||||
@@ -105,7 +105,7 @@ Hooks.on(
|
|||||||
const weaponsRanged = new Texts(
|
const weaponsRanged = new Texts(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
actor.itemCategories.weapon
|
Util.getActorItems(actor, 'weapon')
|
||||||
.filter((w) => w.isRanged)
|
.filter((w) => w.isRanged)
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return `${item.name} : ${item.WeaponGroup}, ${
|
return `${item.name} : ${item.WeaponGroup}, ${
|
||||||
@@ -124,7 +124,7 @@ Hooks.on(
|
|||||||
const ammunitions = new Texts(
|
const ammunitions = new Texts(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
actor.itemCategories.ammunition
|
Util.getActorItems(actor, 'ammunition')
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return `${item.data.data.quantity.value} ${item.name} : ${
|
return `${item.data.data.quantity.value} ${item.name} : ${
|
||||||
item.data.data.range.value.length > 0
|
item.data.data.range.value.length > 0
|
||||||
@@ -143,7 +143,7 @@ Hooks.on(
|
|||||||
|
|
||||||
const armourLocation: string[] = [];
|
const armourLocation: string[] = [];
|
||||||
const armourLabels: { [key: string]: string[] } = {};
|
const armourLabels: { [key: string]: string[] } = {};
|
||||||
for (const armour of actor.itemCategories.armour) {
|
for (const armour of Util.getActorItems(actor, 'armour')) {
|
||||||
const maxAp = armour.data.data.maxAP;
|
const maxAp = armour.data.data.maxAP;
|
||||||
for (const key of Object.keys(maxAp)) {
|
for (const key of Object.keys(maxAp)) {
|
||||||
if (maxAp[key] > 0) {
|
if (maxAp[key] > 0) {
|
||||||
@@ -174,6 +174,160 @@ Hooks.on(
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const petty = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.spell
|
||||||
|
.filter((s) => s.lore.value === 'petty')
|
||||||
|
.map((s) => {
|
||||||
|
return `${s.name} : ${s.cn.value}, ${s.Range}, ${s.Target}, ${s.Duration}`;
|
||||||
|
}),
|
||||||
|
2,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const spell = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.spell
|
||||||
|
.filter((s) => s.lore.value !== 'petty')
|
||||||
|
.map((s) => {
|
||||||
|
return `${s.name} : ${s.cn.value}, ${s.Range}, ${s.Target}, ${s.Duration}, ${s.ingredientList.length}`;
|
||||||
|
}),
|
||||||
|
2,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const blessing = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.prayer
|
||||||
|
.filter((s) => s.prayerType.value === 'blessing')
|
||||||
|
.map((s) => {
|
||||||
|
return `${s.name} : ${s.Range}, ${s.Target}, ${s.Duration}`;
|
||||||
|
}),
|
||||||
|
2,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const miracle = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.prayer
|
||||||
|
.filter((s) => s.prayerType.value !== 'blessing')
|
||||||
|
.map((s) => {
|
||||||
|
return `${s.name} : ${s.Range}, ${s.Target}, ${s.Duration}`;
|
||||||
|
}),
|
||||||
|
2,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const allMoney = Util.getActorItems(actor, 'money');
|
||||||
|
const moneyNames: string[] = [];
|
||||||
|
const moneyByName: { [name: string]: number } = {};
|
||||||
|
for (const money of allMoney) {
|
||||||
|
if (!moneyNames.includes(money.name)) {
|
||||||
|
moneyNames.push(money.name);
|
||||||
|
}
|
||||||
|
if (moneyByName[money.name] == null) {
|
||||||
|
moneyByName[money.name] = 0;
|
||||||
|
}
|
||||||
|
moneyByName[money.name] =
|
||||||
|
moneyByName[money.name] + money.quantity.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trappingsHeader = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
[
|
||||||
|
`${i18nLocalize('Trappings')} : ${i18nLocalize(
|
||||||
|
'Money'
|
||||||
|
)} : ${moneyNames
|
||||||
|
.map((m) => {
|
||||||
|
return `${m} : ${moneyByName[m]}`;
|
||||||
|
})
|
||||||
|
.join(', ')}`,
|
||||||
|
],
|
||||||
|
1,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const trappings = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
Util.getAllActorItems(actor, ['container', 'trapping'])
|
||||||
|
.map((t) => {
|
||||||
|
const location = t.location.value;
|
||||||
|
let prefix = '';
|
||||||
|
if (location != null && location !== 0) {
|
||||||
|
prefix = `${actor.getEmbeddedDocument('Item', location).name} : `;
|
||||||
|
}
|
||||||
|
const qteLabel = t.quantity.value > 1 ? `${t.quantity.value} ` : '';
|
||||||
|
return `${prefix}${qteLabel}${t.name}`;
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.localeCompare(b)),
|
||||||
|
4,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
const critical = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.critical.map((i) => {
|
||||||
|
return i.name;
|
||||||
|
}),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
const disease = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.disease.map((i) => {
|
||||||
|
return i.name;
|
||||||
|
}),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
const injury = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.injury.map((i) => {
|
||||||
|
return i.name;
|
||||||
|
}),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
const mutationP = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.mutation
|
||||||
|
.filter((i) => i.mutationType.value === 'physical')
|
||||||
|
.map((i) => {
|
||||||
|
return i.name;
|
||||||
|
}),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
const mutationM = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.mutation
|
||||||
|
.filter((i) => i.mutationType.value === 'mental')
|
||||||
|
.map((i) => {
|
||||||
|
return i.name;
|
||||||
|
}),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
const psychology = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.psychology.map((i) => {
|
||||||
|
return i.name;
|
||||||
|
}),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
const imageWidth = 25;
|
const imageWidth = 25;
|
||||||
const imageY = labelledRowHeight + MARGINS.top + 2;
|
const imageY = labelledRowHeight + MARGINS.top + 2;
|
||||||
const actorImageElement =
|
const actorImageElement =
|
||||||
@@ -353,6 +507,77 @@ Hooks.on(
|
|||||||
new Separator(0, 0),
|
new Separator(0, 0),
|
||||||
new Text(0, 0, 'Armour'),
|
new Text(0, 0, 'Armour'),
|
||||||
armours,
|
armours,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
`${i18nLocalize('SHEET.PettySpell')} : ${i18nLocalize(
|
||||||
|
'Casting Number'
|
||||||
|
)}, ${i18nLocalize('Range')}, ${i18nLocalize(
|
||||||
|
'Target'
|
||||||
|
)}, ${i18nLocalize('Duration')}`
|
||||||
|
),
|
||||||
|
petty,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
`${i18nLocalize('SHEET.LoreSpell')} : ${i18nLocalize(
|
||||||
|
'Casting Number'
|
||||||
|
)}, ${i18nLocalize('Range')}, ${i18nLocalize(
|
||||||
|
'Target'
|
||||||
|
)}, ${i18nLocalize('Duration')}, ${i18nLocalize(
|
||||||
|
'WFRP4E.TrappingType.Ingredients'
|
||||||
|
)}`
|
||||||
|
),
|
||||||
|
spell,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
`${i18nLocalize('Blessing')} : ${i18nLocalize(
|
||||||
|
'Range'
|
||||||
|
)}, ${i18nLocalize('Target')}, ${i18nLocalize('Duration')}`
|
||||||
|
),
|
||||||
|
blessing,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
`${i18nLocalize('Miracle')} : ${i18nLocalize(
|
||||||
|
'Range'
|
||||||
|
)}, ${i18nLocalize('Target')}, ${i18nLocalize('Duration')}`
|
||||||
|
),
|
||||||
|
miracle,
|
||||||
|
new Separator(0, 0),
|
||||||
|
trappingsHeader,
|
||||||
|
trappings,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Psychology'),
|
||||||
|
psychology,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Criticals'),
|
||||||
|
critical,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Diseases'),
|
||||||
|
disease,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Injuries'),
|
||||||
|
injury,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
`${i18nLocalize('Mutations')} (${i18nLocalize('Physical')})`
|
||||||
|
),
|
||||||
|
mutationP,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
`${i18nLocalize('Mutations')} (${i18nLocalize('Mental')})`
|
||||||
|
),
|
||||||
|
mutationM,
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
docBuilder.doc.save(`${app.actor.name}.pdf`);
|
docBuilder.doc.save(`${app.actor.name}.pdf`);
|
||||||
|
|||||||
24
src/util.ts
24
src/util.ts
@@ -4,4 +4,28 @@ export class Util {
|
|||||||
public static getHeightFromPx(doc: jsPDF, size: number) {
|
public static getHeightFromPx(doc: jsPDF, size: number) {
|
||||||
return size / doc.internal.scaleFactor;
|
return size / doc.internal.scaleFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static getAllActorItems(
|
||||||
|
actor: Actor & any,
|
||||||
|
keys: string[]
|
||||||
|
): (Item & any)[] {
|
||||||
|
const result: (Item & any)[] = [];
|
||||||
|
for (const key of keys) {
|
||||||
|
result.push(...this.getActorItems(actor, key));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getActorItems(actor: Actor & any, key: string): (Item & any)[] {
|
||||||
|
if (actor.itemCategories[key] == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return actor.itemCategories[key].filter((it) => {
|
||||||
|
const location = it.location.value;
|
||||||
|
if (location != null && location !== 0) {
|
||||||
|
return actor.getEmbeddedDocument('Item', location) != null;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user