diff --git a/src/elements/abstract-element.ts b/src/elements/abstract-element.ts index bcb756d..a443d04 100644 --- a/src/elements/abstract-element.ts +++ b/src/elements/abstract-element.ts @@ -16,6 +16,10 @@ export abstract class AbstractElement { return size / doc.internal.scaleFactor; } + public getPxFromSize(doc: jsPDF, size: number) { + return size * doc.internal.scaleFactor; + } + protected updateMaxWidth(maxWidth?: number) { this.maxWidth = maxWidth; } diff --git a/src/elements/blank.ts b/src/elements/blank.ts new file mode 100644 index 0000000..f8da391 --- /dev/null +++ b/src/elements/blank.ts @@ -0,0 +1,29 @@ +import { AbstractElement } from './abstract-element'; +import jsPDF from 'jspdf'; +import { Box } from './box'; + +export class Blank extends Box { + constructor(x: number, y: number, w: number, h: number) { + super(x, y, w, h); + } + + public static heightBlank(h: number) { + return new Blank(0, 0, 0, h); + } + + public getCheckNewPageHeight(doc?: jsPDF): number { + return this.getHeight(doc); + } + + public prepareRender(doc: jsPDF, _maxWidth?: number): jsPDF { + return doc; + } + + public render(doc: jsPDF, _maxWidth?: number): jsPDF { + return doc; + } + + public getElements(): AbstractElement[] { + return [this]; + } +} diff --git a/src/elements/labelled-value.ts b/src/elements/labelled-value.ts index c4f9c8a..67bcfe8 100644 --- a/src/elements/labelled-value.ts +++ b/src/elements/labelled-value.ts @@ -1,5 +1,6 @@ import { Row } from './row'; import { Text } from './text'; +import { MultilineText } from './multiline-text'; export class LabelledValue extends Row { public label: string; @@ -9,13 +10,14 @@ export class LabelledValue extends Row { label: string, value: number, widthPercents?: number[], + multiline = false, maxWidth?: number ) { super( 0, 0, [ - new Text(0, 0, label), + multiline ? new MultilineText(0, 0, label) : new Text(0, 0, label), new Text(0, 0, value.toString(), { align: 'right', }), diff --git a/src/elements/labelled-values.ts b/src/elements/labelled-values.ts index 56d5e74..6198203 100644 --- a/src/elements/labelled-values.ts +++ b/src/elements/labelled-values.ts @@ -12,7 +12,8 @@ export class LabelledValues extends Row { x: number, y: number, labelledValues: { label: string; value: number }[], - nbrOfCol?: number + nbrOfCol?: number, + multiline = false ) { super(x, y, []); this.labelledValues = labelledValues; @@ -47,7 +48,8 @@ export class LabelledValues extends Row { new LabelledValue( labelledValues[i].label, labelledValues[i].value, - widthPercent + widthPercent, + multiline ) ); } @@ -61,7 +63,8 @@ export class LabelledValues extends Row { new LabelledValue( libelledValue.label, libelledValue.value, - widthPercent + widthPercent, + multiline ) ) ) diff --git a/src/elements/multiline-text.ts b/src/elements/multiline-text.ts new file mode 100644 index 0000000..e748de2 --- /dev/null +++ b/src/elements/multiline-text.ts @@ -0,0 +1,42 @@ +import { AbstractElement } from './abstract-element'; +import jsPDF, { TextOptionsLight } from 'jspdf'; +import { i18nLocalize, TEXT_SIZE } from '../constants'; +import { Text } from './text'; + +export class MultilineText extends Text { + private nbrLine = 1; + + constructor( + x: number, + y: number, + text: string, + textOptions?: TextOptionsLight + ) { + super(x, y, text, textOptions); + } + + public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF { + doc.setFontSize(TEXT_SIZE); + this.updateMaxWidth(maxWidth); + let finalText: string[] = [i18nLocalize(this.text)]; + if (this.maxWidth != null) { + finalText = doc.splitTextToSize(finalText[0], this.maxWidth); + } + this.nbrLine = finalText.length; + return doc; + } + + public render(doc: jsPDF, _maxWidth?: number): jsPDF { + const yText = this.y + this.getHeightFromPx(doc, TEXT_SIZE); + doc.setFontSize(TEXT_SIZE).text(this.text, this.x, yText, this.textOptions); + return doc; + } + + public getHeight(doc): number { + return this.getHeightFromPx(doc, TEXT_SIZE) * this.nbrLine; + } + + public getElements(): AbstractElement[] { + return [this]; + } +} diff --git a/src/elements/text.ts b/src/elements/text.ts index b4650b7..1267bc7 100644 --- a/src/elements/text.ts +++ b/src/elements/text.ts @@ -23,17 +23,16 @@ export class Text extends AbstractElement { } public render(doc: jsPDF, _maxWidth?: number): jsPDF { + doc.setFontSize(TEXT_SIZE); let finalText: string[] = [i18nLocalize(this.text)]; if (this.maxWidth != null) { - finalText = doc.splitTextToSize(finalText[0], this.maxWidth ?? 0); + finalText = doc.splitTextToSize(finalText[0], this.maxWidth); } if (finalText.length > 1) { finalText[0] = finalText[0].replace(/(.){3}$/, '...'); } const yText = this.y + this.getHeightFromPx(doc, TEXT_SIZE); - doc - .setFontSize(TEXT_SIZE) - .text(finalText[0], this.x, yText, this.textOptions); + doc.text(finalText[0], this.x, yText, this.textOptions); return doc; } diff --git a/src/elements/texts.ts b/src/elements/texts.ts index 367d6b9..5f3c62c 100644 --- a/src/elements/texts.ts +++ b/src/elements/texts.ts @@ -3,12 +3,19 @@ import { Column } from './column'; import jsPDF from 'jspdf'; import { MARGINS } from '../constants'; import { Text } from './text'; +import { MultilineText } from './multiline-text'; export class Texts extends Row { public texts: string[]; public nbrOfCol: number; - constructor(x: number, y: number, texts: string[], nbrOfCol?: number) { + constructor( + x: number, + y: number, + texts: string[], + nbrOfCol?: number, + multiline = false + ) { super(x, y, []); this.texts = texts; this.nbrOfCol = nbrOfCol ?? 4; @@ -39,7 +46,11 @@ export class Texts extends Row { currentIndex = 3; } (this.elements[currentIndex]).elements.push( - new Row(0, 0, [new Text(0, 0, texts[i])]) + new Row(0, 0, [ + multiline + ? new MultilineText(0, 0, texts[i]) + : new Text(0, 0, texts[i]), + ]) ); } } else { @@ -47,7 +58,14 @@ export class Texts extends Row { new Column( 0, 0, - texts.map((text) => new Row(0, 0, [new Text(0, 0, text)])) + texts.map( + (text) => + new Row(0, 0, [ + multiline + ? new MultilineText(0, 0, text) + : new Text(0, 0, text), + ]) + ) ) ); } diff --git a/src/main.ts b/src/main.ts index a0a717f..38f7036 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,13 +4,14 @@ import { Row } from './elements/row'; import { Image } from './elements/image'; import { Box } from './elements/box'; import { Util } from './util'; -import { LABEL_SIZE, MARGINS, TEXT_SIZE } from './constants'; +import { i18nLocalize, LABEL_SIZE, MARGINS, TEXT_SIZE } from './constants'; import { ItemData } from '@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs'; import { LabelledValues } from './elements/labelled-values'; import { Text } from './elements/text'; import { Texts } from './elements/texts'; import { Column } from './elements/column'; import { Separator } from './elements/separator'; +import { Blank } from './elements/blank'; Hooks.on( 'renderActorSheetWfrp4eCharacter', @@ -46,7 +47,9 @@ Hooks.on( actor.itemCategories.skill .map((item) => { return { - label: item.name, + label: `${item.name} (${i18nLocalize( + item.characteristic.abrev + )})`, value: item.data.data.total.value, }; }) @@ -67,7 +70,8 @@ Hooks.on( }; }) .sort((a, b) => a.label.localeCompare(b.label)), - 1 + 1, + true ); const traits = new Texts( @@ -87,14 +91,15 @@ Hooks.on( actor.itemCategories.weapon .filter((w) => w.isMelee) .map((item) => { - return `${item.name} : ${item.data.data.damage.meleeValue} (${ - item.mountDamage - }), ${item.OriginalQualities.concat(item.OriginalFlaws).join( - ', ' - )}`; + return `${item.name} : ${item.WeaponGroup}, ${item.Reach}, ${ + item.data.data.damage.meleeValue + } (${item.mountDamage}), ${item.OriginalQualities.concat( + item.OriginalFlaws + ).join(', ')}`; }) .sort((a, b) => a.localeCompare(b)), - 1 + 1, + true ); const weaponsRanged = new Texts( @@ -103,12 +108,17 @@ Hooks.on( actor.itemCategories.weapon .filter((w) => w.isRanged) .map((item) => { - return `${item.name} : ${item.data.data.damage.rangedValue}, ${ + return `${item.name} : ${item.WeaponGroup}, ${ item.data.data.range.value - }, ${item.OriginalQualities.concat(item.OriginalFlaws).join(', ')}`; + } (${item.Range}), ${item.data.data.damage.rangedValue} (${ + item.Damage + }), ${item.OriginalQualities.concat(item.OriginalFlaws).join( + ', ' + )}`; }) .sort((a, b) => a.localeCompare(b)), - 1 + 1, + true ); const ammunitions = new Texts( @@ -117,15 +127,51 @@ Hooks.on( actor.itemCategories.ammunition .map((item) => { return `${item.data.data.quantity.value} ${item.name} : ${ + item.data.data.range.value.length > 0 + ? item.data.data.range.value + : 'As Weapon' + }, ${ item.data.data.damage.value.length > 0 ? item.data.data.damage.value : '+0' - }, (${item.data.data.range.value}), ${item.OriginalQualities.concat( - item.OriginalFlaws - ).join(', ')}`; + }, ${item.OriginalQualities.concat(item.OriginalFlaws).join(', ')}`; }) .sort((a, b) => a.localeCompare(b)), - 2 + 2, + true + ); + + const armourLocation: string[] = []; + const armourLabels: { [key: string]: string[] } = {}; + for (const armour of actor.itemCategories.armour) { + const maxAp = armour.data.data.maxAP; + for (const key of Object.keys(maxAp)) { + if (maxAp[key] > 0) { + if (!armourLocation.includes(key)) { + armourLocation.push(key); + } + if (armourLabels[key] == null) { + armourLabels[key] = []; + } + armourLabels[key].push( + `${armour.name} ${maxAp[key]} ${armour.OriginalQualities.concat( + armour.OriginalFlaws + ).join(' ')}` + ); + } + } + } + + const armours = new Texts( + 0, + 0, + armourLocation.map((al) => { + return `${actorStatus?.armour[al]?.label} : ${armourLabels[al]?.join( + ', ' + )}`; + }), + 1, + true ); const imageWidth = 25; @@ -190,6 +236,7 @@ Hooks.on( `${actorDetails?.starsign?.value}` ), ]), + Blank.heightBlank(2), new Row(0, 0, [ new LabelledText( 0, @@ -261,20 +308,51 @@ Hooks.on( new Text(0, 0, 'Skills'), skills, new Separator(0, 0), - new Text(0, 0, 'Talents'), + new Text( + 0, + 0, + `${i18nLocalize('Talents')} : ${i18nLocalize('Tests')}` + ), talents, new Separator(0, 0), new Text(0, 0, 'Traits'), traits, new Separator(0, 0), - new Text(0, 0, 'SHEET.MeleeWeaponHeader'), + new Text( + 0, + 0, + `${i18nLocalize('SHEET.MeleeWeaponHeader')} : ${i18nLocalize( + 'Weapon Group' + )}, ${i18nLocalize('Reach')}, ${i18nLocalize( + 'Damage' + )}, ${i18nLocalize('Qualities')}, ${i18nLocalize('Flaws')}` + ), weaponsMelee, new Separator(0, 0), - new Text(0, 0, 'SHEET.RangedWeaponHeader'), + new Text( + 0, + 0, + `${i18nLocalize('SHEET.RangedWeaponHeader')} : ${i18nLocalize( + 'Weapon Group' + )}, ${i18nLocalize('Range')}, ${i18nLocalize( + 'Damage' + )}, ${i18nLocalize('Qualities')}, ${i18nLocalize('Flaws')}` + ), weaponsRanged, new Separator(0, 0), - new Text(0, 0, 'Ammunition'), + new Text( + 0, + 0, + `${i18nLocalize('Ammunition')} : ${i18nLocalize( + 'Range' + )}, ${i18nLocalize('Damage')}, ${i18nLocalize( + 'Qualities' + )}, ${i18nLocalize('Flaws')}` + ), ammunitions, + new Separator(0, 0), + new Text(0, 0, 'Armour'), + armours, ]), ]); docBuilder.doc.save(`${app.actor.name}.pdf`);