I solved this problem by ignoring Stock's sprite-sheet support and handling it myself in CSS. To achieve this I pass an empty string for the image file path when initializing the Stock.
Code: Select all
this.playerHand.addItemType(card_type_id, card_type_id, "", i);
In the create() method I pass in dynamic values (based on the user's screen width) for the dimensions of each stock item. The technique is
described by Een in this thread.
Code: Select all
let topbarCoords = dojo.position("topbar");
// Determine layout size based on screen width.
if (topbarCoords.w >= 1900)
{
dojo.addClass("ebd-body", "fistfulofgold_large");
this.dontPreloadImage("playmat.jpg");
}
else
{
this.dontPreloadImage("playmat_1480.jpg");
}
I use the class added to ebd-body to define the card size for each layout.
Code: Select all
/* default card dimensions */
.fog_card {
position: absolute;
width: 103px;
height: 144px;
}
/* card dimensions for large screens */
.fistfulofgold_large .fog_card {
width: 206px;
height: 288px;
}
I also use this technique to define the size of the card art, which is independent of the card itself. The art is also used in the tooltip, which doesn't need any of the other styling belonging to actual cards.
Code: Select all
/* the art is the actual image size in the sprite-sheet */
.fog_card_art {
position: relative;
width: 206px; /* this must be the card width from the sprite-sheet */
height: 288px; /* this must be the card height from the sprite-sheet */
transform: scale(0.5); /* the default layout uses half-size cards */
transform-origin: top left;
margin: auto; /* center the image horizontally */
border-radius: 20px;
background-image: url('img/cards.jpg');
}
.fistfulofgold_large .fog_card_art {
transform: scale(1.0); /* use full-size cards for large screens */
}
Note there is only one sprite-sheet - I use the high-res version for all layouts and scale down accordingly. This allows for zooming, e.g. on mobile where card text can be hard to read otherwise.
In the HTML template (.tpl) file, I added a couple of dummy card elements (with display: none) so I can read their computed style when the game is loaded and real cards don't exist yet. I also have a JS template for the real card that will be created later in Stock's onItemCreate().
Code: Select all
<div id="dummy_card" class="fog_card"></div>
<div id="dummy_card_art" class="fog_card_art"></div>
let jstpl_card = '\
<div class="fog_card fog_card_art" style="background-position:-${x}px -${y}px">\
<div class="fog_card_content">\
<div class="fog_card_text">${text}</div>\
<div class="fog_card_note">${note}</div>\
</div>\
</div>';
Back in Javascript I query the card size from the dummy element. Since this happens after the screen width detection, the computed width and height will already be scaled appropriately for the screen size.
Code: Select all
// Read the computed card dimensions from CSS now that the layout size has been determined.
let dummy_card_element = dojo.byId("dummy_card");
let cardWidth = dojo.getStyle(dummy_card_element, "width");
let cardHeight = dojo.getStyle(dummy_card_element, "height");
this.playerHand = new ebg.stock();
this.playerHand.create(this, $("my_hand"), cardWidth, cardHeight);
this.playerHand.image_items_per_row = 10;
this.playerHand.item_margin = 2;
this.playerHand.centerItems = true;
this.playerHand.onItemCreate = dojo.hitch(this, "setupNewCard");
dojo.connect(this.playerHand, "onChangeSelection", this, "onPlayerHandSelectionChanged");
I use the same technique to query the sprite size.
Code: Select all
getCardSpriteOffset: function(card_type_id)
{
let card = this.gamedatas.card_defs[card_type_id];
// Read the computed card art dimensions from CSS.
let dummy_card_art_element = dojo.byId("dummy_card_art");
let card_sprite_width = dojo.getStyle(dummy_card_art_element, "width");
let card_sprite_height = dojo.getStyle(dummy_card_art_element, "height");
let card_sprite_x_offset = card_sprite_width * (card_type_id - 1 - (card.color == this.colorRed ? 10 : 0));
let card_sprite_y_offset = card_sprite_height * (card.color == this.colorRed ? 1 : 0); // red cards are on the second row in the sprite-sheet
return {
x: card_sprite_x_offset,
y: card_sprite_y_offset
}
},
The final step is implementing Stock's onItemCreate callback (seen above) to generate the card's html and attach it to the stock item.
Code: Select all
setupNewCard: function(card_div, card_type_id, card_id)
{
let card = this.gamedatas.card_defs[card_type_id];
let card_sprite_offset = this.getCardSpriteOffset(card_type_id);
if (typeof card.text == "undefined")
card.text = "";
if (typeof card.note == "undefined")
card.note = "";
card.text = this.nl2br(_(card.text), false);
card.note = this.nl2br(_(card.note), false);
if (card.text.length > 0 || card.note.length > 0)
{
let tooltipHtml = this.format_block("jstpl_card_tooltip",
{
name: card.name,
x: card_sprite_offset.x,
y: card_sprite_offset.y,
text: card.text,
note: card.note
});
this.addTooltipHtml(card_div.id, tooltipHtml, 100);
}
dojo.place(
this.format_block("jstpl_card",
{
id: card_id,
x: card_sprite_offset.x,
y: card_sprite_offset.y,
text: card.text,
note: card.note
}), card_div.id);
},
Hopefully this helps someone!