1
0
Files
robolitik/src/deck.rb
2025-06-15 18:33:04 +02:00

201 lines
5.6 KiB
Ruby

require 'squib'
DPI = 150
CELL_PX = DPI / 8.0
BLEED = 0.125 # In inches
WIDTH = (2.5 + 2*BLEED) * DPI
HEIGHT = (3.5 + 2*BLEED) * DPI
EFFECT_FONT_SIZE = 8
EFFECT_FONT_SPACING = 5
EMBED_SIZE = EFFECT_FONT_SIZE / 8.0 # In cells
EMBED_DY = - (0.7 * EMBED_SIZE + 0.2) * DPI / 300 # In cells
#data = Squib.xlsx file: 'data/cards.xlsx', explode: 'quantite'
data = Squib.csv file: 'data/cards.csv', explode: 'quantite'
data['rang'].map! { it.nil? ? nil : it.to_s.sub(/\A\++/, "+") }
data['rang_alt'].map! { it.nil? ? nil : it.to_s.sub(/\A\++/, "+") }
['effet_1', 'effet_2', 'effet_3'].each { data[it].each { it&.gsub! '\n', "\n" } }
def icon_to_svg(icon)
icon.nil? ? nil : "icone_#{icon}.svg"
end
def ret_icon_to_svg(icon)
icon.nil? ? nil : "retourner_#{icon}.svg"
end
def banner_text_layout(rank)
if rank.nil?
nil
elsif rank.start_with?('+')
"banniere_bonus.svg"
elsif rank.start_with?('-')
"banniere_malus.svg"
else
"banniere_rang.svg"
end
end
def rank_to_banner_svg(rank)
if rank.nil?
nil
elsif rank.start_with?('+')
"banniere_bonus.svg"
elsif rank.start_with?('-')
"banniere_malus.svg"
else
"banniere_rang.svg"
end
end
def get_art(data, idx)
art = data['art'][idx]
unless art.nil?
return "#{art}.svg"
end
icon = data['icone'][idx]
icon_alt = data['icone_alt'][idx]
icon_alt = icon_alt.nil? ? '' : "_#{icon_alt}"
return "default_art_#{icon}#{icon_alt}.svg"
end
def get_grouped_effects(data, idx)
if data['effet_1'].nil?
n_effects = 0
elsif data['effet_2'].nil?
n_effects = 1
elsif data['effet_3'].nil?
n_effects = 2
else
n_effects = 3
end
effects = []
(0..3).each do |i|
effects.append([data["type_effet_#{i}"], data["effet_#{i}"]])
end
return [n_effects, effects]
end
def get_n_effects(data, idx)
if data['effet_1'][idx].nil?
0
elsif data['effet_2'][idx].nil?
1
elsif data['effet_3'][idx].nil?
2
else
3
end
end
def embed_custom(embed, id)
embed.svg width: "#{EMBED_SIZE}c", height: "#{EMBED_SIZE}c", dx: '0c', dy: "#{EMBED_DY}c", key: ":#{id}:", file: "._graphics/#{id}.svg"
end
Squib.configure cell_px: CELL_PX
Squib::Deck.new(
cards: data['nom'].size,
layout: '._layouts/poker.yml',
width: WIDTH,
height: HEIGHT,
dpi: DPI,
) do
background color: 'white'
svg file: 'bg_numbers.svg', layout: 'background'
build :debug do
rect layout: 'border', stroke_color: 'black'
rect layout: 'cut', dash: '0.5mm 0.5mm', stroke_color: 'red'
rect layout: 'safe', dash: '0.5mm 0.5mm', stroke_color: 'green'
end
art_file = (0..data['icone'].length).map { |idx| get_art(data, idx) }
svg file: art_file, layout: 'art'
icon_file = data['icone'].map { |icon| icon_to_svg(icon) }
svg file: icon_file, layout: 'icon'
banner_file = data['rang'].map { |rank| rank_to_banner_svg(rank) }
svg file: banner_file, layout: 'banner'
text str: data['rang'], layout: 'banner_text'
text str: data['nom'], layout: banner_file.map { |banner| banner.nil? ? 'name' : 'name_with_banner'}
paparazzo_file = data['type'].map { |type| type=='action' ? 'paparazzo.svg' : nil }
svg file: paparazzo_file, layout: 'paparazzo'
alt_icon_file = data['icone_alt'].map { |icon| icon_to_svg(icon) }
svg file: alt_icon_file, layout: 'alt_icon'
ret_icon_file = data['icone_alt'].map { |icon| ret_icon_to_svg(icon) }
svg file: ret_icon_file, layout: 'ret_icon'
alt_ret_icon_file = data['icone'].zip(data['icone_alt']).map { |icon, alt_icon| alt_icon.nil? ? nil : ret_icon_to_svg(icon) }
svg file: alt_ret_icon_file, layout: 'alt_ret_icon'
alt_banner_file = data['rang_alt'].map { |rank| rank_to_banner_svg(rank) }
svg file: alt_banner_file, layout: 'alt_banner'
text str: data['rang_alt'], layout: 'alt_banner_text'
fill_color = data['effet_1'].map { |effet| effet.nil? ? '#0000': '#f7f7f7ff' }
stroke_color = data['effet_1'].map { |effet| effet.nil? ? '#0000': '#e3ca0eff' }
rect layout: 'effect_frame', fill_color: fill_color, stroke_color: stroke_color
n_effects = (0..data['icone'].length).map { |idx| get_n_effects(data, idx) }
(1..3).each do |n|
n.times do |i|
# Effect texts
text(str: (0..data['icone'].length).map { |idx| (n == n_effects[idx]) ? data["effet_#{i+1}"][idx] : nil}, layout: "effect_text_#{n}_#{i}", font_size: EFFECT_FONT_SIZE, spacing: EFFECT_FONT_SPACING) do |embed|
[
'effet',
'magouille',
'pv',
'symbole_ind',
'symbole_gau',
'symbole_roy',
'symbole_ana',
'symbole_dro',
'symbole_eco',
'm1',
'm2',
'm3',
'p1',
'p2',
'p3',
].each { embed_custom(embed, it) }
end
# Effect icons
svg file: (0..data['icone'].length).map { |idx| (n == n_effects[idx]) ? data["type_effet_#{i+1}"][idx] + ".svg" : nil}, layout: "effect_icon_#{n}_#{i}"
end
end
(2..3).each do |n|
#Effect separators
(n-1).times do |i|
svg file: (0..data['icone'].length).map { |idx| (n == n_effects[idx]) ? "separateur_effet.svg" : nil}, layout: "effect_separator_#{n}_#{i}"
end
end
build :debug do
save_pdf sprue: 'sprues/debug.yml', file: 'debug.pdf'
end
build :pnp do
rect layout: 'cut'
save_pdf sprue: 'sprues/A4_poker.yml', trim: inches(BLEED), file: 'pnp_A4.pdf'
end
build :showcase do
hand range: [0, 6, 13, 21, 38, 59, 62], trim_radius: inches(0.125), fill_color: 'black'
showcase range: [0, 6, 13, 21, 38, 59, 62], trim: inches(BLEED), trim_radius: inches(0.125), fill_color: 'black'
end
build :full do
save_png dir: '_output/full/front'
end
end