diff --git a/demos/stefan/untitled-board-game/ubg-card.js b/demos/stefan/untitled-board-game/ubg-card.js
index 8c7584c78..63320aeef 100644
--- a/demos/stefan/untitled-board-game/ubg-card.js
+++ b/demos/stefan/untitled-board-game/ubg-card.js
@@ -54,6 +54,20 @@ export default class Card {
this.versions.last.cost = cost;
}
+ getBaseVP() {
+ return this.versions.last.baseVP;
+ }
+
+ setBaseVP(baseVP) {
+ this.ensureUnprintedVersion();
+
+ if (!baseVP) {
+ delete this.versions.last.baseVP;
+ } else {
+ this.versions.last.baseVP = baseVP;
+ }
+ }
+
getText() {
return this.versions.last.text;
}
diff --git a/src/components/widgets/ubg-cards-editor.html b/src/components/widgets/ubg-cards-editor.html
index a85d8462a..12e286c11 100644
--- a/src/components/widgets/ubg-cards-editor.html
+++ b/src/components/widgets/ubg-cards-editor.html
@@ -128,7 +128,7 @@
#form-layout {
display: grid;
grid-template-columns: min-content auto 2.5in;
- grid-template-rows: repeat(6, auto) 1fr .5fr auto;
+ grid-template-rows: repeat(7, auto) 1fr .5fr auto;
grid-template-areas:
"isPrinted-key isPrinted-value preview"
"id-key id-value preview"
@@ -136,6 +136,7 @@
"type-key type-value preview"
"element-key element-value preview"
"cost-key cost-value preview"
+ "vp-key vp-value preview"
"text-key text-value preview"
"notes-key notes-value preview"
"art-key art-value preview"
@@ -216,6 +217,8 @@
cost
+ base vp
+
text
notes
diff --git a/src/components/widgets/ubg-cards-editor.js b/src/components/widgets/ubg-cards-editor.js
index bd35677f8..4d3eef893 100644
--- a/src/components/widgets/ubg-cards-editor.js
+++ b/src/components/widgets/ubg-cards-editor.js
@@ -22,6 +22,7 @@ export default class UBGCardsEditor extends Morph {
this.$type.addEventListener(eventName, evt => this.modify$type(evt), false);
this.$element.addEventListener(eventName, evt => this.modify$element(evt), false);
this.$cost.addEventListener(eventName, evt => this.modify$cost(evt), false);
+ this.$vp.addEventListener(eventName, evt => this.modify$vp(evt), false);
this.$text.addEventListener(eventName, evt => this.modify$text(evt), false);
this.$notes.addEventListener(eventName, evt => this.modify$notes(evt), false);
this.$art.addEventListener(eventName, evt => this.modify$art(evt), false);
@@ -212,6 +213,9 @@ export default class UBGCardsEditor extends Morph {
get $cost() {
return this.get('#cost');
}
+ get $vp() {
+ return this.get('#vp');
+ }
get $text() {
return this.get('#text');
}
@@ -349,6 +353,35 @@ export default class UBGCardsEditor extends Morph {
this.$cost.value = cost;
}
+ modify$vp(evt) {
+ const vp = this.$vp.value;
+
+ if (vp === '') {
+ this.card.setBaseVP();
+ } else if ('*+-'.split('').some(char => vp.endsWith(char))) {
+ this.card.setBaseVP(vp);
+ } else {
+ const intCost = parseInt(vp);
+ if (_.isNaN(intCost)) {
+ this.card.setBaseVP();
+ } else {
+ this.card.setBaseVP(intCost);
+ }
+ }
+
+ this.propagateChange()
+ }
+ display$vp() {
+ const vp = this.card.getBaseVP();
+
+ if (vp === undefined) {
+ this.$vp.value = '';
+ return;
+ }
+
+ this.$vp.value = vp;
+ }
+
modify$text(evt) {
const text = this.$text.value;
if (text === '') {
@@ -444,6 +477,7 @@ export default class UBGCardsEditor extends Morph {
this.display$type();
this.display$element();
this.display$cost();
+ this.display$vp();
this.display$text();
this.display$notes();
this.display$art();
diff --git a/src/components/widgets/ubg-cards-entry.html b/src/components/widgets/ubg-cards-entry.html
index f6e428eef..47b549e26 100644
--- a/src/components/widgets/ubg-cards-entry.html
+++ b/src/components/widgets/ubg-cards-entry.html
@@ -135,6 +135,9 @@
#cost {
color: goldenrod;
}
+ #vp {
+ color: violet;
+ }
#name {
font-weight: 600;
}
@@ -152,6 +155,7 @@
+
diff --git a/src/components/widgets/ubg-cards-entry.js b/src/components/widgets/ubg-cards-entry.js
index 3c1f0cd44..6e5e5830a 100644
--- a/src/components/widgets/ubg-cards-entry.js
+++ b/src/components/widgets/ubg-cards-entry.js
@@ -129,6 +129,7 @@ export default class UBGCardEntry extends Morph {
this.renderElement(v);
this.get('#cost').innerHTML = v.cost || '/';
+ this.get('#vp').innerHTML = card.getBaseVP() || '-';
this.get('#name').innerHTML = card.versions.last.name || 'no name yet';
this.get('#text').innerHTML = card.versions.last.text || 'no text';
diff --git a/src/components/widgets/ubg-cards.html b/src/components/widgets/ubg-cards.html
index ea26266e5..e84ae0b65 100644
--- a/src/components/widgets/ubg-cards.html
+++ b/src/components/widgets/ubg-cards.html
@@ -139,6 +139,7 @@
+
diff --git a/src/components/widgets/ubg-cards.js b/src/components/widgets/ubg-cards.js
index 8f14f9364..ca532e7c7 100644
--- a/src/components/widgets/ubg-cards.js
+++ b/src/components/widgets/ubg-cards.js
@@ -6,6 +6,7 @@ import ContextMenu from 'src/client/contextmenu.js';
import { Paper } from 'src/client/literature.js';
import Bibliography from "src/client/bibliography.js";
import pdf from "src/external/pdf.js";
+import { shake } from 'utils';
import { serialize, deserialize } from 'src/client/serialize.js';
import Card from 'demos/stefan/untitled-board-game/ubg-card.js';
@@ -196,6 +197,9 @@ const SORT_BY = {
NAME: 'name'
};
+const VP_FILL = 'violet';
+const VP_STROKE = '#9400d3'; // darkviolet
+
export default class Cards extends Morph {
async initialize() {
@@ -585,6 +589,10 @@ export default class Cards extends Morph {
return this.buildCards(doc, cards); // .slice(0,12)
}
+ async fetchAssetsInfo() {
+ return (await this.assetsFolder.fetchStats()).contents;
+ }
+
async buildCards(doc, cardsToPrint) {
const GAP = lively.pt(.2, .2);
@@ -600,8 +608,7 @@ export default class Cards extends Morph {
const progress = await lively.showProgress(progressLabel(0));
try {
- const ASSET_FOLDER = this.assetsFolder;
- const assetsInfo = (await ASSET_FOLDER.fetchStats()).contents;
+ const assetsInfo = await this.fetchAssetsInfo();
let i = 0;
let currentPage = 0;
@@ -1172,10 +1179,13 @@ export default class Cards extends Morph {
// cost
const coinCenter = coinLeftCenter.addXY(costCoinRadius, 0);
this.renderCost(doc, cardDesc, coinCenter, costCoinRadius)
+ const vpCenter = coinCenter.addY(costCoinRadius * 2.75);
+ this.renderBaseVP(doc, cardDesc, vpCenter, costCoinRadius)
}
renderCost(doc, cardDesc, pos, coinRadius) {
- const COST_SIZE = coinRadius / 4;
+ const costSize = coinRadius / 4;
+
const costDesc = cardDesc.getCost();
const cost = Array.isArray(costDesc) ? costDesc.first : costDesc;
@@ -1184,17 +1194,54 @@ export default class Cards extends Morph {
doc.setGState(new doc.GState({ opacity: 0.9 }));
doc.setFillColor('#b8942d');
doc.setDrawColor(148, 0, 211);
- doc.setLineWidth(0.2 * COST_SIZE)
+ doc.setLineWidth(0.2 * costSize)
doc.circle(...coinCenter.toPair(), coinRadius, 'DF');
});
- if (cost !== undefined) {
- doc::withGraphicsState(() => {
- doc.setFontSize(12 * COST_SIZE);
- doc.setTextColor('#000000');
- doc.text('' + cost, ...coinCenter.toPair(), { align: 'center', baseline: 'middle' });
- });
+ this.renderIconText(doc, coinCenter, costSize, cost)
+ }
+
+ renderBaseVP(doc, cardDesc, pos, coinRadius) {
+ const costSize = coinRadius / 4;
+
+ const vp = cardDesc.getBaseVP();
+ if (!vp) {
+ return;
+ }
+
+ const iconCenter = pos;
+ doc::withGraphicsState(() => {
+ doc.setGState(new doc.GState({ opacity: 0.9 }))
+ // doc.setFillColor('#b8942d');
+ doc.setDrawColor(VP_STROKE)
+ doc.setLineWidth(0.2 * costSize)
+ // doc.circle(...coinCenter.toPair(), coinRadius, 'DF');
+ doc.setFillColor(VP_FILL)
+ // doc.rect(coinCenter.x - coinRadius, coinCenter.y - coinRadius, 2 * coinRadius, 2 * coinRadius, 'DF');
+
+ // diamond shape
+ const diagonal = coinRadius * .9 * Math.sqrt(2)
+ const rightAbsolute = iconCenter.addX(diagonal).toPair()
+ const down = lively.pt(-diagonal, diagonal).toPair()
+ const left = lively.pt(-diagonal, -diagonal).toPair()
+ const up = lively.pt(diagonal, -diagonal).toPair()
+ const rightAgain = lively.pt(diagonal, diagonal).toPair()
+ doc.lines([down, left, up, rightAgain], ...rightAbsolute, [1,1], 'DF', true)
+ });
+
+ this.renderIconText(doc, iconCenter, costSize, vp)
+ }
+
+ renderIconText(doc, centerPos, size, text) {
+ if (text === undefined) {
+ return
}
+
+ doc::withGraphicsState(() => {
+ doc.setFontSize(12 * size);
+ doc.setTextColor('#000000');
+ doc.text('' + text, ...centerPos.toPair(), { align: 'center', baseline: 'middle' });
+ });
}
// #important
@@ -1240,6 +1287,13 @@ ${smallElementIcon(others[2], lively.pt(11, 7))}
`;
}
+ function printVP(vp) {
+ return ``;
+ }
+
let printedRules = rulesText;
printedRules = printedRules.replace(/t3x(fire|water|earth|wind|gray)/gmi, 'tap 3x$1');
printedRules = printedRules.replace(/(^|\n)tap 3x(fire|water|earth|wind|gray)([^\n]*)/gi, function replacer(match, p1, pElement, pText, offset, string, groups) {
@@ -1259,6 +1313,9 @@ ${smallElementIcon(others[2], lively.pt(11, 7))}
printedRules = printedRules.replace(/(fire|water|earth|wind|gray)/gmi, function replacer(match, pElement, offset, string, groups) {
return element(pElement);
});
+ printedRules = printedRules.replace(/(\d+|\*|d+\*|\d+x|x|\b)VP\b/gmi, function replacer(match, vp, offset, string, groups) {
+ return printVP(vp);
+ });
printedRules = printedRules.replace(/\(([*0-9x+-]*)\)/gmi, function replacer(match, p1, offset, string, groups) {
return coin(p1);
});
@@ -1510,7 +1567,7 @@ width: ${ruleTextBox.width}mm; min-height: ${ruleTextBox.height}mm;`}>;
if (that && that.localName === 'lively-code-mirror' && document.contains(that)) {
lively.showElement(that)
- const matches = that.value.matchAll(/^([^0-9]+)?\s([0-9]+)?\s?([a-zA-Z ]+)?\s?(?:\(([0-9,]+)\))?\.\s(.*)?$/gmi);
+ const matches = that.value.matchAll(/^([^0-9]+)?\s([0-9]+)?\s?([a-zA-Z ]+)?\s?(?:\(([0-9,]+)\))?(?:\s?([0-9*+-]+))?\.\s(.*)?$/gmi);
const newCards = [...matches].map(match => {
const card = new Card();
@@ -1525,7 +1582,7 @@ width: ${ruleTextBox.width}mm; min-height: ${ruleTextBox.height}mm;`}>;
card.setName(match[1])
card.setType(match[3])
- card.setText(match[5])
+ card.setText(match[6])
let type = ''
let element;
@@ -1562,6 +1619,16 @@ width: ${ruleTextBox.width}mm; min-height: ${ruleTextBox.height}mm;`}>;
}
}
+ const baseVP = match[5];
+ const intBaseVP = parseInt(baseVP);
+ if (!_.isNaN(intBaseVP)) {
+ card.setBaseVP(intBaseVP)
+ } else {
+ if (baseVP) {
+ card.setBaseVP(baseVP)
+ }
+ }
+
return card;
});
@@ -1582,6 +1649,52 @@ width: ${ruleTextBox.width}mm; min-height: ${ruleTextBox.height}mm;`}>;
}
}
+ async onArtDesc(evt) {
+ const text = do {
+ const assetsInfo = await this.fetchAssetsInfo();
+ let ids = []
+ for (let entry of assetsInfo) {
+ if (entry.type !== 'file') {
+ continue
+ }
+
+ const match = entry.name.match(/^(.+)\.jpg$/)
+ if (!match) {
+ continue
+ }
+
+ // const id = parseInt(match[1])
+ // if (_.isInteger(id)) {
+ // ids.push(id)
+ // }
+ ids.push(match[1])
+ }
+
+ let cards = this.cards;
+ cards = cards
+ .filter(c => !c.getIsBad())
+ // we just use a string match for now
+ .filter(c => !ids.includes(c.getId() + '')).sortBy('id')
+ cards.map(c => {
+ const artDesc = c.getArtDirection() || c.getName();
+ return `[${c.getId()}, '${artDesc}'],`
+ }).join('\n')
+ };
+
+ const type = "text/plain";
+ const blob = new Blob([text], { type });
+ // evt.clipboardData.setData('text/html', html);
+ const data = [new ClipboardItem({ [type]: blob })];
+
+ try {
+ await navigator.clipboard.write(data);
+ lively.success('copied art description!');
+ } catch (e) {
+ shake(this.get('#artDesc'));
+ lively.error('copying failed', e.message);
+ }
+ }
+
async onPrintAll(evt) {
if (!this.cards) {
return;