def draw_artifact_card(self, metadata, card, svg, svg_group): id = metadata['id'] name = card[0] attrs = card[1] # Validate attributes self.validate_attrs(name, attrs) # Build list of template ids and then load from svg file. svg_ids = [] svg_ids.append('artifact-title') svg_ids.extend(['icon-star-{0}'.format(n) for n in [1,2,3]]) svg_ids.append('artifact-description') svg_ids.append('artifact-extra-action') svg_ids.append('artifact-bonus') svg_ids.append('artifact-bonus-border') svg_ids.append('artifact-flavor') #svg_ids.append('separator') svg_ids.extend(['op-{0}'.format(op) for op in valid_ops]) svg.load_ids(WovenArtifactCards.CARD_TEMPLATE, svg_ids) # Add Op masters (hidden, used for cloning). g_masters = SVG.group('masters') g_masters.set_style("display:none") SVG.add_node(svg_group, g_masters) for e in [ 'op-tapestry', 'op-eye', 'op-mmove', 'op-thread', 'op-action', ]: svg.add_loaded_element(g_masters, e) # Draw artifact title. title = svg.add_loaded_element(svg_group, 'artifact-title') SVG.set_text(title, name) self.draw_description(attrs, 'description', svg, svg_group) svg.add_loaded_element(svg_group, 'artifact-extra-action') self.draw_bonus(attrs, 'bonus', svg, svg_group) self.draw_flavor(attrs, 'flavor', svg, svg_group) #svg.add_loaded_element(svg_group, 'separator') # Draw alternate action. #svg.add_loaded_element(svg_group, 'op-{0}'.format(attrs['op'])) self.draw_vp(attrs['vp'], svg, svg_group)
def pre_card(self): if self._called_pre_card: raise Exception("pre_card() should only be called once per card") if self.curr_filename == '': self.curr_file += 1 self.curr_filename = 'out{0:02d}'.format(self.curr_file) self.__create_svg_file() self.curr_card += 1 layer = self.svg.add_inkscape_layer( 'card{0:02d}'.format(self.curr_card), "Card {0}".format(self.curr_card)) cut_line = SVG.rect_round(0, 0, 0, self.card_width, self.card_height, 3) style = Style() style.set('fill', "#ffffff") style.set('stroke', "none") cut_line.set_style(style) SVG.add_node(layer, cut_line) self._called_pre_card = True return (self.svg, layer)
class Sketch: def __init__(self, width=600, height=600): self.width = width self.height = height self.svg = SVG(viewBox=f"0 0 {width} {height}", style="stroke: black; fill: none;") self.background("white") self.tcount = 0 def background(self, color): self.svg.rect(x=0, y=0, width=self.width, height=self.height, fill=color, stroke="none") def circle(self, x, y, d): self.svg.circle(cx=x, cy=y, r=d / 2) def line(self, x1, y1, x2, y2, **kwargs): self.svg.line(x1=x1, y1=y1, x2=x2, y2=y2, **kwargs) def rect(self, x, y, w, h): self.svg.rect(x=x, y=y, width=w, height=h) def path(self, d): self.svg.path(d=d, stroke="black") def show(self, node, margin=0, scale=False, size=260): if margin or scale: s = (self.width - 2 * margin) / size if scale else 1 g = Node( "g", transform=f"translate({margin}, {margin}) scale({s}, {s})") g.add_node(node) self.svg.add_node(g) else: self.svg.add_node(node) def transform(self, node, dx, dy, sx, sy): g = Node("g", transform=f"translate({dx}, {dy}) scale({sx}, {sy})") g.add_node(node) return g def thumbnail(self, shape): size = 260 / 4 x = self.tcount * (size + 20) + 20 y = 10 self.show(self.transform(shape, x, y, 0.25, 0.25)) self.tcount += 1 def clear(): self.tcount = 0 def tostring(self): return self.svg.tostring() def render(self, code): g = self.get_globals() exec(code, g, g) return self.tostring() def show_grid(self): size = 100 for y in range(0, self.height + 1, size): self.line(0, y, self.width, y, stroke="#ccc") for x in range(0, self.width + 1, size): self.line(x, 0, x, self.height, stroke="#ccc") def get_globals(self): return { "circle": self.circle, "rect": self.rect, "line": self.line, "path": self.path, "width": self.width, "height": self.height, "show_grid": self.show_grid, "Node": Node, "show": self.show, "thumbnail": self.thumbnail, **g.exports }
def draw_pattern(self, id, pattern_raw, element, svg_group): pattern = [x.split() for x in pattern_raw] pheight = len(pattern) if pheight == 0: raise Exception("Missing pattern for {0}".format(id)) if pheight > 3: raise Exception("Tall pattern for {0}".format(id)) pwidth = len(pattern[0]) # Max pattern size that fits on the card. max_width = 7 max_height = 3 # Center of pattern area. pcenter_x = self.width / 2 pcenter_y = 22.4 # Size and spacing for each box in pattern. box_size = 5.5 box_spacing = 7 # Upper left corner of pattern area px0 = pcenter_x - (((max_width - 1) * box_spacing) + box_size) / 2 py0 = pcenter_y - (((max_height - 1) * box_spacing) + box_size) / 2 # Calc offsets to center the patterns that are less than max size. if pwidth % 2 == 0: px0 += box_spacing / 2 max_width = 6 else: max_width = 7 if pheight % 2 == 0: py0 += box_spacing / 2 max_height = 2 else: max_height = 3 dot_x0 = px0 + (box_size / 2) dot_y0 = py0 + (box_size / 2) # The x,y ranges for this pattern (to center on the card) x_begin = int((max_width - pwidth) / 2) x_end = x_begin + pwidth y_begin = int((max_height - pheight) / 2) y_end = y_begin + pheight for iy in range(0, max_height): for ix in range(0, max_width): if ix >= x_begin and ix < x_end and iy >= y_begin and iy < y_end: x = ix * box_spacing y = iy * box_spacing col = ix - x_begin row = iy - y_begin cell = pattern[row][col] if cell == '@': elemaster = '#element-{0}'.format(element) eleclone = SVG.clone(0, elemaster, px0 + x, py0 + y) SVG.add_node(svg_group, eleclone) elif cell == 'X': box = SVG.rect(0, px0 + x, py0 + y, box_size, box_size) style_box = Style() style_box.set_fill("none") style_box.set_stroke("#000000", 0.5) style_box.set('stroke-linecap', "round") style_box.set('stroke-miterlimit', 2) box.set_style(style_box) SVG.add_node(svg_group, box) elif cell == '.': dot = SVG.circle(0, dot_x0 + x, dot_y0 + y, 0.8) style_dot = Style() style_dot.set_fill("#c0c0c0") style_dot.set_stroke("none") dot.set_style(style_dot) SVG.add_node(svg_group, dot) else: raise Exception( "Unrecognized pattern symbol: {0}".format(cell))
def draw_spell_card(self, metadata, card, svg, svg_group): id = metadata['id'] name = card[0] attrs = card[1] desc = card[2] # Validate attributes if attrs['category'] != 'blank': self.validate_attrs(name, attrs) pattern_id = attrs['pattern'] pattern = self.card_patterns[pattern_id]['pattern'] if attrs['category'] != 'blank': self.record_spell_info(name, pattern, attrs, desc) if attrs['category'] != 'blank' and pattern_id != 'blank': pe_tag = self.pattern_key(pattern) + '-' + attrs['element'] if pe_tag in self.pattern_elements: raise Exception( 'Pattern for "{0:s}" already used for "{1:s}"'.format( name, self.pattern_elements[pe_tag])) self.pattern_elements[pe_tag] = name # Validate desc self.validate_desc(name, desc) # Verify pattern matches spell element element = attrs['element'] pelem_data = self.card_patterns[pattern_id]['elements'] pelems = [] if pelem_data == "none": pelems.append("none") else: pelems = [elem_map[p] for p in pelem_data] if not element in pelems: raise Exception( "{0:s}: Spell pattern does not match element {1:s}".format( name, element)) # Build list of template ids and then load from svg file. svg_ids = [] svg_ids.extend(['element-{0}'.format(elem_map[e]) for e in elem_map]) svg_ids.append('spell-title') svg_ids.append('spell-pattern-border') svg_ids.append('spell-description') svg_ids.append('spell-id') svg_ids.extend(['icon-star-{0}'.format(n) for n in [1, 2, 3]]) svg_ids.append('icon-vp') svg_ids.append('spell-flavor') svg_ids.append('separator') svg_ids.extend(['op-{0}'.format(op) for op in valid_ops]) svg.load_ids(WovenSpellCards.CARD_TEMPLATE, svg_ids) # Add Element and Op masters (hidden, used for cloning). g_masters = SVG.group('masters') g_masters.set_style("display:none") SVG.add_node(svg_group, g_masters) for e in [ 'op-tapestry', 'op-eye', 'op-mmove', 'op-thread', 'op-action', 'element-air', 'element-earth', 'element-fire', 'element-water', ]: svg.add_loaded_element(g_masters, e) if attrs['category'] != 'blank': # Draw spell title. title = svg.add_loaded_element(svg_group, 'spell-title') SVG.set_text(title, name) # Draw elements in title bar elemaster = '#element-{0}'.format(element) SVG.add_node(svg_group, SVG.clone(0, elemaster, 4, 4)) SVG.add_node(svg_group, SVG.clone(0, elemaster, 54, 4)) # Draw spell id. id_text = svg.add_loaded_element(svg_group, 'spell-id') SVG.set_text( id_text, "{0:d}/{1:d}".format(spell_card_revision, attrs['id'])) # Draw flavor text (if present). if 'flavor' in attrs: flavor_text = svg.add_loaded_element(svg_group, 'spell-flavor') SVG.set_text(flavor_text, attrs['flavor']) svg.add_loaded_element(svg_group, 'separator') # Draw alternate action. svg.add_loaded_element(svg_group, 'op-{0}'.format(attrs['op'])) # Add spell pattern. self.draw_pattern(pattern_id, pattern, element, svg_group) svg.add_loaded_element(svg_group, 'spell-pattern-border') if attrs['category'] != 'blank': self.draw_description(attrs['id'], desc, svg, svg_group) self.draw_vp(attrs['vp'], svg, svg_group)