stuff is mostly working again, trying to switch to using a C PDF library
This commit is contained in:
parent
b9945e8097
commit
adec84668e
|
@ -0,0 +1,2 @@
|
|||
pub const packages = struct {};
|
||||
pub const root_deps: []const struct { []const u8, []const u8 } = &.{};
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
Subproject commit 53ea781d446d51ce70492a796c2523286490633f
|
19
build.zig
19
build.zig
|
@ -3,6 +3,8 @@ const std = @import("std");
|
|||
// Although this function looks imperative, note that its job is to
|
||||
// declaratively construct a build graph that will be executed by an external
|
||||
// runner.
|
||||
//
|
||||
const CFlags = &.{};
|
||||
pub fn build(b: *std.Build) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
|
@ -36,6 +38,17 @@ pub fn build(b: *std.Build) void {
|
|||
.optimize = optimize,
|
||||
});
|
||||
|
||||
exe.addCSourceFile(.{
|
||||
.file = .{
|
||||
.path = "src/pdfgen.c",
|
||||
},
|
||||
.flags = CFlags,
|
||||
});
|
||||
|
||||
exe.addIncludePath(.{
|
||||
.path = "include/pdfgen.h",
|
||||
});
|
||||
|
||||
// This declares intent for the executable to be installed into the
|
||||
// standard location when the user invokes the "install" step (the default
|
||||
// step when running `zig build`).
|
||||
|
@ -46,9 +59,9 @@ pub fn build(b: *std.Build) void {
|
|||
// such a dependency.
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
const msgpack = b.dependency("zig-msgpack", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
exe.root_module.addImport("msgpack", msgpack.module("msgpack"));
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
// Once all dependencies are fetched, `zig build` no longer requires
|
||||
// internet connectivity.
|
||||
.dependencies = .{
|
||||
.@"zig-msgpack" = .{
|
||||
.url = "https://github.com/zigcc/zig-msgpack/archive/main.tar.gz",
|
||||
.hash = "1220e4669d29190ac809cd3a7726c20b6b49ea7425b7b89cab16d4dc3172016982bc",
|
||||
},
|
||||
//.@"zig-msgpack" = .{
|
||||
// .url = "https://github.com/zigcc/zig-msgpack/archive/main.tar.gz",
|
||||
// .hash = "1220e4669d29190ac809cd3a7726c20b6b49ea7425b7b89cab16d4dc3172016982bc",
|
||||
//},
|
||||
//.clap = .{
|
||||
// .url = "https://github.com/Hejsil/zig-clap/archive/refs/tags/0.8.0.tar.gz",
|
||||
// .hash = "1220949d4e88864579067b6d4cdad6476c6176f27e782782c2c39b7f2c4817a10efb",
|
||||
|
|
|
@ -0,0 +1,800 @@
|
|||
/**
|
||||
* Simple engine for creating PDF files.
|
||||
* It supports text, shapes, images etc...
|
||||
* Capable of handling millions of objects without too much performance
|
||||
* penalty.
|
||||
* Public domain license - no warrenty implied; use at your own risk.
|
||||
* @file pdfgen.h
|
||||
*/
|
||||
#ifndef PDFGEN_H
|
||||
#define PDFGEN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* @defgroup subsystem Simple PDF Generation
|
||||
* Allows for quick generation of simple PDF documents.
|
||||
* This is useful for producing easily printed output from C code, where
|
||||
* advanced formatting is not required
|
||||
*
|
||||
* Note: All coordinates/sizes are in points (1/72 of an inch).
|
||||
* All coordinates are based on 0,0 being the bottom left of the page.
|
||||
* All colours are specified as a packed 32-bit value - see @ref PDF_RGB.
|
||||
* Text strings are interpreted as UTF-8 encoded, but only a small subset of
|
||||
* characters beyond 7-bit ascii are supported (see @ref pdf_add_text for
|
||||
* details).
|
||||
*
|
||||
* @par PDF library example:
|
||||
* @code
|
||||
#include "pdfgen.h"
|
||||
...
|
||||
struct pdf_info info = {
|
||||
.creator = "My software",
|
||||
.producer = "My software",
|
||||
.title = "My document",
|
||||
.author = "My name",
|
||||
.subject = "My subject",
|
||||
.date = "Today"
|
||||
};
|
||||
struct pdf_doc *pdf = pdf_create(PDF_A4_WIDTH, PDF_A4_HEIGHT, &info);
|
||||
pdf_set_font(pdf, "Times-Roman");
|
||||
pdf_append_page(pdf);
|
||||
pdf_add_text(pdf, NULL, "This is text", 12, 50, 20, PDF_BLACK);
|
||||
pdf_add_line(pdf, NULL, 50, 24, 150, 24);
|
||||
pdf_save(pdf, "output.pdf");
|
||||
pdf_destroy(pdf);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
struct pdf_doc;
|
||||
struct pdf_object;
|
||||
|
||||
/**
|
||||
* pdf_info describes the metadata to be inserted into the
|
||||
* header of the output PDF
|
||||
*/
|
||||
struct pdf_info {
|
||||
char creator[64]; //!< Software used to create the PDF
|
||||
char producer[64]; //!< Software used to create the PDF
|
||||
char title[64]; //!< The title of the PDF (typically displayed in the
|
||||
//!< window bar when viewing)
|
||||
char author[64]; //!< Who created the PDF
|
||||
char subject[64]; //!< What is the PDF about
|
||||
char date[64]; //!< The date the PDF was created
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum that declares the different image file formats we currently support.
|
||||
* Each value has a corresponding header struct used within
|
||||
* the format_specific_img_info union.
|
||||
*/
|
||||
enum {
|
||||
IMAGE_PNG,
|
||||
IMAGE_JPG,
|
||||
IMAGE_PPM,
|
||||
IMAGE_BMP,
|
||||
|
||||
IMAGE_UNKNOWN
|
||||
};
|
||||
|
||||
/**
|
||||
* Since we're casting random areas of memory to these, make sure
|
||||
* they're packed properly to match the image format requirements
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* Information about color type of PNG format
|
||||
* As defined by https://www.w3.org/TR/2003/REC-PNG-20031110/#6Colour-values
|
||||
*/
|
||||
enum /* png colortype */ {
|
||||
// Greyscale
|
||||
PNG_COLOR_GREYSCALE = 0,
|
||||
// Truecolour
|
||||
PNG_COLOR_RGB = 2,
|
||||
// Indexed-colour
|
||||
PNG_COLOR_INDEXED = 3,
|
||||
// Greyscale with alpha
|
||||
PNG_COLOR_GREYSCALE_A = 4,
|
||||
// Truecolour with alpha
|
||||
PNG_COLOR_RGBA = 6,
|
||||
|
||||
PNG_COLOR_INVALID = 255
|
||||
};
|
||||
|
||||
/**
|
||||
* png_header describes the header information extracted from .PNG files
|
||||
*/
|
||||
struct png_header {
|
||||
uint32_t width; //!< Width in pixels
|
||||
uint32_t height; //!< Height in pixels
|
||||
uint8_t bitDepth; //!< Bit Depth
|
||||
uint8_t colorType; //!< Color type - see PNG_COLOR_xx
|
||||
uint8_t deflate; //!< Deflate setting
|
||||
uint8_t filtering; //!< Filtering
|
||||
uint8_t interlace; //!< Interlacing
|
||||
};
|
||||
|
||||
/**
|
||||
* bmp_header describes the header information extracted from .BMP files
|
||||
*/
|
||||
struct bmp_header {
|
||||
uint32_t bfSize; //!< size of BMP in bytes
|
||||
uint16_t bfReserved1; //!< ignore!
|
||||
uint16_t bfReserved2; //!< ignore!
|
||||
uint32_t bfOffBits; //!< Offset to BMP data
|
||||
uint32_t biSize; //!< Size of this header (40)
|
||||
int32_t biWidth; //!< Width in pixels
|
||||
int32_t biHeight; //!< Height in pixels
|
||||
uint16_t biPlanes; //!< Number of colour planes - must be 1
|
||||
uint16_t biBitCount; //!< Bits Per Pixel
|
||||
uint32_t biCompression; //!< Compression Method
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* jpeg_header describes the header information extracted from .JPG files
|
||||
*/
|
||||
struct jpeg_header {
|
||||
int ncolours; //!< Number of colours
|
||||
};
|
||||
|
||||
/**
|
||||
* PPM color spaces
|
||||
*/
|
||||
enum {
|
||||
PPM_BINARY_COLOR_RGB, //!< binary ppm with RGB colors (magic number P5)
|
||||
PPM_BINARY_COLOR_GRAY, //!< binary ppm with grayscale colors (magic number
|
||||
//!< P6)
|
||||
};
|
||||
|
||||
/**
|
||||
* ppm_header describes the header information extracted from .PPM files
|
||||
*/
|
||||
struct ppm_header {
|
||||
size_t size; //!< Indicate the size of the image data
|
||||
size_t data_begin_pos; //!< position in the data where the image starts
|
||||
int color_space; //!< PPM color space
|
||||
};
|
||||
|
||||
/**
|
||||
* pdf_img_info describes the metadata for an arbitrary image
|
||||
*/
|
||||
struct pdf_img_info {
|
||||
int image_format; //!< Indicates the image format (IMAGE_PNG, ...)
|
||||
uint32_t width; //!< Width in pixels
|
||||
uint32_t height; //!< Height in pixels
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// Doxygen doesn't like anonymous unions
|
||||
//!< Image specific details
|
||||
union {
|
||||
struct bmp_header bmp; //!< BMP header info
|
||||
struct jpeg_header jpeg; //!< JPEG header info
|
||||
struct png_header png; //!< PNG header info
|
||||
struct ppm_header ppm; //!< PPM header info
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* pdf_path_operation holds information about a path
|
||||
* drawing operation.
|
||||
* See PDF reference for detailed usage.
|
||||
*/
|
||||
struct pdf_path_operation {
|
||||
char op; /*!< Operation command. Possible operators are: m = move to, l =
|
||||
line to, c = cubic bezier curve with two control points, v =
|
||||
cubic bezier curve with one control point fixed at first
|
||||
point, y = cubic bezier curve with one control point fixed
|
||||
at second point, h = close path */
|
||||
float x1; /*!< X offset of the first point. Used with: m, l, c, v, y */
|
||||
float y1; /*!< Y offset of the first point. Used with: m, l, c, v, y */
|
||||
float x2; /*!< X offset of the second point. Used with: c, v, y */
|
||||
float y2; /*!< Y offset of the second point. Used with: c, v, y */
|
||||
float x3; /*!< X offset of the third point. Used with: c */
|
||||
float y3; /*!< Y offset of the third point. Used with: c */
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a value in inches into a number of points.
|
||||
* @param inch inches value to convert to points
|
||||
*/
|
||||
#define PDF_INCH_TO_POINT(inch) ((float)((inch)*72.0f))
|
||||
|
||||
/**
|
||||
* Convert a value in milli-meters into a number of points.
|
||||
* @param mm millimeter value to convert to points
|
||||
*/
|
||||
#define PDF_MM_TO_POINT(mm) ((float)((mm)*72.0f / 25.4f))
|
||||
|
||||
/*! Point width of a standard US-Letter page */
|
||||
#define PDF_LETTER_WIDTH PDF_INCH_TO_POINT(8.5f)
|
||||
|
||||
/*! Point height of a standard US-Letter page */
|
||||
#define PDF_LETTER_HEIGHT PDF_INCH_TO_POINT(11.0f)
|
||||
|
||||
/*! Point width of a standard A4 page */
|
||||
#define PDF_A4_WIDTH PDF_MM_TO_POINT(210.0f)
|
||||
|
||||
/*! Point height of a standard A4 page */
|
||||
#define PDF_A4_HEIGHT PDF_MM_TO_POINT(297.0f)
|
||||
|
||||
/*! Point width of a standard A3 page */
|
||||
#define PDF_A3_WIDTH PDF_MM_TO_POINT(297.0f)
|
||||
|
||||
/*! Point height of a standard A3 page */
|
||||
#define PDF_A3_HEIGHT PDF_MM_TO_POINT(420.0f)
|
||||
|
||||
/**
|
||||
* Convert three 8-bit RGB values into a single packed 32-bit
|
||||
* colour. These 32-bit colours are used by various functions
|
||||
* in PDFGen
|
||||
*/
|
||||
#define PDF_RGB(r, g, b) \
|
||||
(uint32_t)((((r)&0xff) << 16) | (((g)&0xff) << 8) | (((b)&0xff)))
|
||||
|
||||
/**
|
||||
* Convert four 8-bit ARGB values into a single packed 32-bit
|
||||
* colour. These 32-bit colours are used by various functions
|
||||
* in PDFGen. Alpha values range from 0 (opaque) to 0xff
|
||||
* (transparent)
|
||||
*/
|
||||
#define PDF_ARGB(a, r, g, b) \
|
||||
(uint32_t)(((uint32_t)((a)&0xff) << 24) | (((r)&0xff) << 16) | \
|
||||
(((g)&0xff) << 8) | (((b)&0xff)))
|
||||
|
||||
/*! Utility macro to provide bright red */
|
||||
#define PDF_RED PDF_RGB(0xff, 0, 0)
|
||||
|
||||
/*! Utility macro to provide bright green */
|
||||
#define PDF_GREEN PDF_RGB(0, 0xff, 0)
|
||||
|
||||
/*! Utility macro to provide bright blue */
|
||||
#define PDF_BLUE PDF_RGB(0, 0, 0xff)
|
||||
|
||||
/*! Utility macro to provide black */
|
||||
#define PDF_BLACK PDF_RGB(0, 0, 0)
|
||||
|
||||
/*! Utility macro to provide white */
|
||||
#define PDF_WHITE PDF_RGB(0xff, 0xff, 0xff)
|
||||
|
||||
/*!
|
||||
* Utility macro to provide a transparent colour
|
||||
* This is used in some places for 'fill' colours, where no fill is required
|
||||
*/
|
||||
#define PDF_TRANSPARENT (uint32_t)(0xffu << 24)
|
||||
|
||||
/**
|
||||
* Different alignment options for rendering text
|
||||
*/
|
||||
enum {
|
||||
PDF_ALIGN_LEFT, //!< Align text to the left
|
||||
PDF_ALIGN_RIGHT, //!< Align text to the right
|
||||
PDF_ALIGN_CENTER, //!< Align text in the center
|
||||
PDF_ALIGN_JUSTIFY, //!< Align text in the center, with padding to fill the
|
||||
//!< available space
|
||||
PDF_ALIGN_JUSTIFY_ALL, //!< Like PDF_ALIGN_JUSTIFY, except even short
|
||||
//!< lines will be fully justified
|
||||
PDF_ALIGN_NO_WRITE, //!< Fake alignment for only checking wrap height with
|
||||
//!< no writes
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new PDF object, with the given page
|
||||
* width/height
|
||||
* @param width Width of the page
|
||||
* @param height Height of the page
|
||||
* @param info Optional information to be put into the PDF header
|
||||
* @return PDF document object, or NULL on failure
|
||||
*/
|
||||
struct pdf_doc *pdf_create(float width, float height,
|
||||
const struct pdf_info *info);
|
||||
|
||||
/**
|
||||
* Destroy the pdf object, and all of its associated memory
|
||||
* @param pdf PDF document to clean up
|
||||
*/
|
||||
void pdf_destroy(struct pdf_doc *pdf);
|
||||
|
||||
/**
|
||||
* Retrieve the error message if any operation fails
|
||||
* @param pdf pdf document to retrieve error message from
|
||||
* @param errval optional pointer to an integer to be set to the error code
|
||||
* @return NULL if no error message, string description of error otherwise
|
||||
*/
|
||||
const char *pdf_get_err(const struct pdf_doc *pdf, int *errval);
|
||||
|
||||
/**
|
||||
* Acknowledge an outstanding pdf error
|
||||
* @param pdf pdf document to clear the error message from
|
||||
*/
|
||||
void pdf_clear_err(struct pdf_doc *pdf);
|
||||
|
||||
/**
|
||||
* Sets the font to use for text objects. Default value is Times-Roman if
|
||||
* this function is not called.
|
||||
* Note: The font selection should be done before text is output,
|
||||
* and will remain until pdf_set_font is called again.
|
||||
* @param pdf PDF document to update font on
|
||||
* @param font New font to use. This must be one of the standard PDF fonts:
|
||||
* Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
|
||||
* Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
|
||||
* Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic,
|
||||
* Symbol or ZapfDingbats
|
||||
* @return < 0 on failure, 0 on success
|
||||
*/
|
||||
int pdf_set_font(struct pdf_doc *pdf, const char *font);
|
||||
|
||||
/**
|
||||
* Calculate the width of a given string in the current font
|
||||
* @param pdf PDF document
|
||||
* @param font_name Name of the font to get the width of.
|
||||
* This must be one of the standard PDF fonts:
|
||||
* Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
|
||||
* Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
|
||||
* Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic,
|
||||
* Symbol or ZapfDingbats
|
||||
* @param text Text to determine width of
|
||||
* @param size Size of the text, in points
|
||||
* @param text_width area to store calculated width in
|
||||
* @return < 0 on failure, 0 on success
|
||||
*/
|
||||
int pdf_get_font_text_width(struct pdf_doc *pdf, const char *font_name,
|
||||
const char *text, float size, float *text_width);
|
||||
|
||||
/**
|
||||
* Retrieves a PDF document height
|
||||
* @param pdf PDF document to get height of
|
||||
* @return height of PDF document (in points)
|
||||
*/
|
||||
float pdf_height(const struct pdf_doc *pdf);
|
||||
|
||||
/**
|
||||
* Retrieves a PDF document width
|
||||
* @param pdf PDF document to get width of
|
||||
* @return width of PDF document (in points)
|
||||
*/
|
||||
float pdf_width(const struct pdf_doc *pdf);
|
||||
|
||||
/**
|
||||
* Retrieves page height
|
||||
* @param page Page object to get height of
|
||||
* @return height of page (in points)
|
||||
*/
|
||||
float pdf_page_height(const struct pdf_object *page);
|
||||
|
||||
/**
|
||||
* Retrieves page width
|
||||
* @param page Page object to get width of
|
||||
* @return width of page (in points)
|
||||
*/
|
||||
float pdf_page_width(const struct pdf_object *page);
|
||||
|
||||
/**
|
||||
* Add a new page to the given pdf
|
||||
* @param pdf PDF document to append page to
|
||||
* @return new page object
|
||||
*/
|
||||
struct pdf_object *pdf_append_page(struct pdf_doc *pdf);
|
||||
|
||||
/**
|
||||
* Retrieve a page by its number.
|
||||
*
|
||||
* Note: The page must have already been created via \ref pdf_append_page
|
||||
*
|
||||
* @param pdf PDF document to get page from
|
||||
* @param page_number Page number to retrieve, starting from 1.
|
||||
* @return Page object if the given page is found, NULL otherwise
|
||||
*/
|
||||
struct pdf_object *pdf_get_page(struct pdf_doc *pdf, int page_number);
|
||||
|
||||
/**
|
||||
* Adjust the width/height of a specific page
|
||||
* @param pdf PDF document that the page belongs to
|
||||
* @param page object returned from @ref pdf_append_page
|
||||
* @param width Width of the page in points
|
||||
* @param height Height of the page in points
|
||||
* @return < 0 on failure, 0 on success
|
||||
*/
|
||||
int pdf_page_set_size(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
float width, float height);
|
||||
|
||||
/**
|
||||
* Save the given pdf document to the supplied filename.
|
||||
* @param pdf PDF document to save
|
||||
* @param filename Name of the file to store the PDF into (NULL for stdout)
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_save(struct pdf_doc *pdf, const char *filename);
|
||||
|
||||
/**
|
||||
* Save the given pdf document to the given FILE output
|
||||
* @param pdf PDF document to save
|
||||
* @param fp FILE pointer to store the data into (must be writable)
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_save_file(struct pdf_doc *pdf, FILE *fp);
|
||||
|
||||
/**
|
||||
* Add a text string to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param text String to display
|
||||
* @param size Point size of the font
|
||||
* @param xoff X location to put it in
|
||||
* @param yoff Y location to put it in
|
||||
* @param colour Colour to draw the text
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_text(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
const char *text, float size, float xoff, float yoff,
|
||||
uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add a text string to the document at a rotated angle
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param text String to display
|
||||
* @param size Point size of the font
|
||||
* @param xoff X location to put it in
|
||||
* @param yoff Y location to put it in
|
||||
* @param angle Rotation angle of text (in radians)
|
||||
* @param colour Colour to draw the text
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_text_rotate(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
const char *text, float size, float xoff, float yoff,
|
||||
float angle, uint32_t colour);
|
||||
/**
|
||||
* Add a text string to the document, making it wrap if it is too
|
||||
* long
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param text String to display
|
||||
* @param size Point size of the font
|
||||
* @param xoff X location to put it in
|
||||
* @param yoff Y location to put it in
|
||||
* @param angle Rotation angle of text (in radians)
|
||||
* @param colour Colour to draw the text
|
||||
* @param wrap_width Width at which to wrap the text
|
||||
* @param align Text alignment (see PDF_ALIGN_xxx)
|
||||
* @param height Store the final height of the wrapped text here (optional)
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_add_text_wrap(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
const char *text, float size, float xoff, float yoff,
|
||||
float angle, uint32_t colour, float wrap_width,
|
||||
int align, float *height);
|
||||
|
||||
/**
|
||||
* Add a line to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x1 X offset of start of line
|
||||
* @param y1 Y offset of start of line
|
||||
* @param x2 X offset of end of line
|
||||
* @param y2 Y offset of end of line
|
||||
* @param width Width of the line
|
||||
* @param colour Colour to draw the line
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_line(struct pdf_doc *pdf, struct pdf_object *page, float x1,
|
||||
float y1, float x2, float y2, float width, uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add a cubic bezier curve to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x1 X offset of the initial point of the curve
|
||||
* @param y1 Y offset of the initial point of the curve
|
||||
* @param x2 X offset of the final point of the curve
|
||||
* @param y2 Y offset of the final point of the curve
|
||||
* @param xq1 X offset of the first control point of the curve
|
||||
* @param yq1 Y offset of the first control point of the curve
|
||||
* @param xq2 X offset of the second control of the curve
|
||||
* @param yq2 Y offset of the second control of the curve
|
||||
* @param width Width of the curve
|
||||
* @param colour Colour to draw the curve
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_cubic_bezier(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
float x1, float y1, float x2, float y2, float xq1,
|
||||
float yq1, float xq2, float yq2, float width,
|
||||
uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add a quadratic bezier curve to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x1 X offset of the initial point of the curve
|
||||
* @param y1 Y offset of the initial point of the curve
|
||||
* @param x2 X offset of the final point of the curve
|
||||
* @param y2 Y offset of the final point of the curve
|
||||
* @param xq1 X offset of the control point of the curve
|
||||
* @param yq1 Y offset of the control point of the curve
|
||||
* @param width Width of the curve
|
||||
* @param colour Colour to draw the curve
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_quadratic_bezier(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
float x1, float y1, float x2, float y2,
|
||||
float xq1, float yq1, float width,
|
||||
uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add a custom path to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param operations Array of drawing operations
|
||||
* @param operation_count The number of operations
|
||||
* @param stroke_width Width of the stroke
|
||||
* @param stroke_colour Colour to stroke the curve
|
||||
* @param fill_colour Colour to fill the path
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_custom_path(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
const struct pdf_path_operation *operations,
|
||||
int operation_count, float stroke_width,
|
||||
uint32_t stroke_colour, uint32_t fill_colour);
|
||||
|
||||
/**
|
||||
* Add an ellipse to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x X offset of the center of the ellipse
|
||||
* @param y Y offset of the center of the ellipse
|
||||
* @param xradius Radius of the ellipse in the X axis
|
||||
* @param yradius Radius of the ellipse in the Y axis
|
||||
* @param width Width of the ellipse outline stroke
|
||||
* @param colour Colour to draw the ellipse outline stroke
|
||||
* @param fill_colour Colour to fill the ellipse
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_ellipse(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float xradius, float yradius, float width,
|
||||
uint32_t colour, uint32_t fill_colour);
|
||||
|
||||
/**
|
||||
* Add a circle to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x X offset of the center of the circle
|
||||
* @param y Y offset of the center of the circle
|
||||
* @param radius Radius of the circle
|
||||
* @param width Width of the circle outline stroke
|
||||
* @param colour Colour to draw the circle outline stroke
|
||||
* @param fill_colour Colour to fill the circle
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_circle(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float radius, float width, uint32_t colour,
|
||||
uint32_t fill_colour);
|
||||
|
||||
/**
|
||||
* Add an outline rectangle to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x X offset to start rectangle at
|
||||
* @param y Y offset to start rectangle at
|
||||
* @param width Width of rectangle
|
||||
* @param height Height of rectangle
|
||||
* @param border_width Width of rectangle border
|
||||
* @param colour Colour to draw the rectangle
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_rectangle(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float width, float height, float border_width,
|
||||
uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add a filled rectangle to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x X offset to start rectangle at
|
||||
* @param y Y offset to start rectangle at
|
||||
* @param width Width of rectangle
|
||||
* @param height Height of rectangle
|
||||
* @param border_width Width of rectangle border
|
||||
* @param colour_fill Colour to fill the rectangle
|
||||
* @param colour_border Colour to draw the rectangle
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_filled_rectangle(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
float x, float y, float width, float height,
|
||||
float border_width, uint32_t colour_fill,
|
||||
uint32_t colour_border);
|
||||
|
||||
/**
|
||||
* Add an outline polygon to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x array of X offsets for points comprising the polygon
|
||||
* @param y array of Y offsets for points comprising the polygon
|
||||
* @param count Number of points comprising the polygon
|
||||
* @param border_width Width of polygon border
|
||||
* @param colour Colour to draw the polygon
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_polygon(struct pdf_doc *pdf, struct pdf_object *page, float x[],
|
||||
float y[], int count, float border_width,
|
||||
uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add a filled polygon to the document
|
||||
* @param pdf PDF document to add to
|
||||
* @param page Page to add object to (NULL => most recently added page)
|
||||
* @param x array of X offsets of points comprising the polygon
|
||||
* @param y array of Y offsets of points comprising the polygon
|
||||
* @param count Number of points comprising the polygon
|
||||
* @param border_width Width of polygon border
|
||||
* @param colour Colour to draw the polygon
|
||||
* @return 0 on success, < 0 on failure
|
||||
*/
|
||||
int pdf_add_filled_polygon(struct pdf_doc *pdf, struct pdf_object *page,
|
||||
float x[], float y[], int count,
|
||||
float border_width, uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add a bookmark to the document
|
||||
* @param pdf PDF document to add bookmark to
|
||||
* @param page Page to jump to for bookmark
|
||||
(or NULL for the most recently added page)
|
||||
* @param parent ID of a previously created bookmark that is the parent
|
||||
of this one. -1 if this should be a top-level bookmark.
|
||||
* @param name String to associate with the bookmark
|
||||
* @return < 0 on failure, new bookmark id on success
|
||||
*/
|
||||
int pdf_add_bookmark(struct pdf_doc *pdf, struct pdf_object *page, int parent,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* Add a link annotation to the document
|
||||
* @param pdf PDF document to add link to
|
||||
* @param page Page that holds the clickable rectangle
|
||||
(or NULL for the most recently added page)
|
||||
* @param x X coordinate of bottom LHS corner of clickable rectangle
|
||||
* @param y Y coordinate of bottom LHS corner of clickable rectangle
|
||||
* @param width width of clickable rectangle
|
||||
* @param height height of clickable rectangle
|
||||
* @param target_page Page to jump to for link
|
||||
* @param target_x X coordinate to position at the left of the view
|
||||
* @param target_y Y coordinate to position at the top of the view
|
||||
* @return < 0 on failure, new bookmark id on success
|
||||
*/
|
||||
int pdf_add_link(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float width, float height,
|
||||
struct pdf_object *target_page, float target_x,
|
||||
float target_y);
|
||||
|
||||
/**
|
||||
* List of different barcode encodings that are supported
|
||||
*/
|
||||
enum {
|
||||
PDF_BARCODE_128A, //!< Produce code-128A style barcodes
|
||||
PDF_BARCODE_39, //!< Produce code-39 style barcodes
|
||||
PDF_BARCODE_EAN13, //!< Produce EAN-13 style barcodes
|
||||
PDF_BARCODE_UPCA, //!< Produce UPC-A style barcodes
|
||||
PDF_BARCODE_EAN8, //!< Produce EAN-8 style barcodes
|
||||
PDF_BARCODE_UPCE, //!< Produce UPC-E style barcodes
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a barcode to the document
|
||||
* @param pdf PDF document to add barcode to
|
||||
* @param page Page to add barcode to (NULL => most recently added page)
|
||||
* @param code Type of barcode to add (PDF_BARCODE_xxx)
|
||||
* @param x X offset to put barcode at
|
||||
* @param y Y offset to put barcode at
|
||||
* @param width Width of barcode
|
||||
* @param height Height of barcode
|
||||
* @param string Barcode contents
|
||||
* @param colour Colour to draw barcode
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_add_barcode(struct pdf_doc *pdf, struct pdf_object *page, int code,
|
||||
float x, float y, float width, float height,
|
||||
const char *string, uint32_t colour);
|
||||
|
||||
/**
|
||||
* Add image data as an image to the document.
|
||||
* Image data must be one of: JPEG, PNG, PPM, PGM or BMP formats
|
||||
* Passing 0 for either the display width or height will
|
||||
* include the image but not render it visible.
|
||||
* Passing a negative number either the display height or width will
|
||||
* have the image be resized while keeping the original aspect ratio.
|
||||
* @param pdf PDF document to add image to
|
||||
* @param page Page to add image to (NULL => most recently added page)
|
||||
* @param x X offset to put image at
|
||||
* @param y Y offset to put image at
|
||||
* @param display_width Displayed width of image
|
||||
* @param display_height Displayed height of image
|
||||
* @param data Image data bytes
|
||||
* @param len Length of data
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_add_image_data(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float display_width, float display_height,
|
||||
const uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* Add a raw 24 bit per pixel RGB buffer as an image to the document
|
||||
* Passing 0 for either the display width or height will
|
||||
* include the image but not render it visible.
|
||||
* Passing a negative number either the display height or width will
|
||||
* have the image be resized while keeping the original aspect ratio.
|
||||
* @param pdf PDF document to add image to
|
||||
* @param page Page to add image to (NULL => most recently added page)
|
||||
* @param x X offset to put image at
|
||||
* @param y Y offset to put image at
|
||||
* @param display_width Displayed width of image
|
||||
* @param display_height Displayed height of image
|
||||
* @param data RGB data to add
|
||||
* @param width width of image in pixels
|
||||
* @param height height of image in pixels
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_add_rgb24(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float display_width, float display_height,
|
||||
const uint8_t *data, uint32_t width, uint32_t height);
|
||||
|
||||
/**
|
||||
* Add a raw 8 bit per pixel grayscale buffer as an image to the document
|
||||
* @param pdf PDF document to add image to
|
||||
* @param page Page to add image to (NULL => most recently added page)
|
||||
* @param x X offset to put image at
|
||||
* @param y Y offset to put image at
|
||||
* @param display_width Displayed width of image
|
||||
* @param display_height Displayed height of image
|
||||
* @param data grayscale pixel data to add
|
||||
* @param width width of image in pixels
|
||||
* @param height height of image in pixels
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_add_grayscale8(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float display_width, float display_height,
|
||||
const uint8_t *data, uint32_t width, uint32_t height);
|
||||
|
||||
/**
|
||||
* Add an image file as an image to the document.
|
||||
* Passing 0 for either the display width or height will
|
||||
* include the image but not render it visible.
|
||||
* Passing a negative number either the display height or width will
|
||||
* have the image be resized while keeping the original aspect ratio.
|
||||
* Supports image formats: JPEG, PNG, PPM, PGM & BMP
|
||||
* @param pdf PDF document to add bookmark to
|
||||
* @param page Page to add image to (NULL => most recently added page)
|
||||
* @param x X offset to put image at
|
||||
* @param y Y offset to put image at
|
||||
* @param display_width Displayed width of image
|
||||
* @param display_height Displayed height of image
|
||||
* @param image_filename Filename of image file to display
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_add_image_file(struct pdf_doc *pdf, struct pdf_object *page, float x,
|
||||
float y, float display_width, float display_height,
|
||||
const char *image_filename);
|
||||
|
||||
/**
|
||||
* Parse image data to determine the image type & metadata
|
||||
* @param info structure to hold the parsed metadata
|
||||
* @param data image data to parse
|
||||
* @param length number of bytes in data
|
||||
* @param err_msg area to put any failure details
|
||||
* @param err_msg_length maximum number of bytes to store in err_msg
|
||||
* @return < 0 on failure, >= 0 on success
|
||||
*/
|
||||
int pdf_parse_image_header(struct pdf_img_info *info, const uint8_t *data,
|
||||
size_t length, char *err_msg,
|
||||
size_t err_msg_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PDFGEN_H
|
848
src/out.md
848
src/out.md
|
@ -1,371 +1,161 @@
|
|||
```
|
||||
|Abrupt Decay {B}{G} (Instant) |Badlands (Land Swamp |Bayou (Land Swamp Forest) >>
|
||||
|>> This spell can't be |Mountain) >> ({T}: Add {B} or |({T}: Add {B} or {G}.)
|
||||
|countered. Destroy target |{R}.) |
|
||||
|nonland permanent with mana | |
|
||||
|value 3 or less. | |
|
||||
| | |
|
||||
|Birds of Paradise {G} |City of Brass (Land) >> |Eladamri's Call {G}{W}
|
||||
|(Creature Bird) >> Flying |Whenever City of Brass |(Instant) >> Search your
|
||||
|{T}: Add one mana of any |becomes tapped, it deals 1 |library for a creature card,
|
||||
|color. >> 0/1 |damage to you. {T}: Add one |reveal that card, put it into
|
||||
| |mana of any color. |your hand, then shuffle.
|
||||
| | |
|
||||
|Elvish Spirit Guide {2}{G} |Forest (Basic Land Forest) |Gitaxian Probe {U/P}
|
||||
|(Creature Elf Spirit) >> |>> ({T}: Add {G}.) |(Sorcery) >> ({U/P} can be
|
||||
|Exile Elvish Spirit Guide | |paid with either {U} or 2
|
||||
|from your hand: Add {G}. >> | |life.) Look at target
|
||||
|2/2 | |player's hand. Draw a card.
|
||||
| | |
|
||||
|Karakas (Legendary Land) >> |Lotus Petal {0} (Artifact) >> |Mana Confluence (Land) >>
|
||||
|{T}: Add {W}. {T}: Return |{T}, Sacrifice Lotus Petal: |{T}, Pay 1 life: Add one mana
|
||||
|target legendary creature to |Add one mana of any color. |of any color.
|
||||
|its owner's hand. | |
|
||||
| | |
|
||||
| | |
|
||||
|Mental Misstep {U/P} |Mox Emerald {0} (Artifact) >> |Mox Jet {0} (Artifact) >>
|
||||
|(Instant) >> ({U/P} can be |{T}: Add {G}. |{T}: Add {B}.
|
||||
|paid with either {U} or 2 | |
|
||||
|life.) Counter target spell | |
|
||||
|with mana value 1. | |
|
||||
| | |
|
||||
|Mox Pearl {0} (Artifact) >> |Plains (Basic Land Plains) |Plateau (Land Mountain
|
||||
|{T}: Add {W}. |>> ({T}: Add {W}.) |Plains) >> ({T}: Add {R} or
|
||||
| | |{W}.)
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Razorverge Thicket (Land) >> |Savannah (Land Forest |Scrubland (Land Plains
|
||||
|Razorverge Thicket enters the |Plains) >> ({T}: Add {G} or |Swamp) >> ({T}: Add {W} or
|
||||
|battlefield tapped unless you |{W}.) |{B}.)
|
||||
|control two or fewer other | |
|
||||
|lands. {T}: Add {G} or {W}. | |
|
||||
| | |
|
||||
|Simian Spirit Guide {2}{R} |Swamp (Basic Land Swamp) >> |Swords to Plowshares {W}
|
||||
|(Creature Ape Spirit) >> |({T}: Add {B}.) |(Instant) >> Exile target
|
||||
|Exile Simian Spirit Guide | |creature. Its controller
|
||||
|from your hand: Add {R}. >> | |gains life equal to its
|
||||
|2/2 | |power.
|
||||
| | |
|
||||
|Taiga (Land Mountain Forest) |Thalia, Guardian of Thraben |Wasteland (Land) >> {T}: Add
|
||||
|>> ({T}: Add {R} or {G}.) |{1}{W} (Legendary Creature |{C}. {T}, Sacrifice
|
||||
| |Human Soldier) >> First |Wasteland: Destroy target
|
||||
| |strike Noncreature spells |nonbasic land.
|
||||
| |cost {1} more to cast. >> 2/1 |
|
||||
| | |
|
||||
|Arid Mesa (Land) >> {T}, Pay |Duress {B} (Sorcery) >> |Flooded Strand (Land) >> {T},
|
||||
|1 life, Sacrifice Arid Mesa: |Target opponent reveals their |Pay 1 life, Sacrifice Flooded
|
||||
|Search your library for a |hand. You choose a |Strand: Search your library
|
||||
|Mountain or Plains card, put |noncreature, nonland card |for a Plains or Island card,
|
||||
|it onto the battlefield, then |from it. That player discards |put it onto the battlefield,
|
||||
|shuffle. |that card. |then shuffle.
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Luminarch Aspirant {1}{W} |Marsh Flats (Land) >> {T}, |Misty Rainforest (Land) >>
|
||||
|(Creature Human Cleric) >> |Pay 1 life, Sacrifice Marsh |{T}, Pay 1 life, Sacrifice
|
||||
|At the beginning of combat on |Flats: Search your library |Misty Rainforest: Search your
|
||||
|your turn, put a +1/+1 |for a Plains or Swamp card, |library for a Forest or
|
||||
|counter on target creature |put it onto the battlefield, |Island card, put it onto the
|
||||
|you control. >> 1/1 |then shuffle. |battlefield, then shuffle.
|
||||
| | |
|
||||
|Mother of Runes {W} (Creature |Polluted Delta (Land) >> {T}, |Prismatic Vista (Land) >>
|
||||
| Human Cleric) >> {T}: Target |Pay 1 life, Sacrifice |{T}, Pay 1 life, Sacrifice
|
||||
|creature you control gains |Polluted Delta: Search your |Prismatic Vista: Search your
|
||||
|protection from the color of |library for an Island or |library for a basic land
|
||||
|your choice until end of |Swamp card, put it onto the |card, put it onto the
|
||||
|turn. >> 1/1 |battlefield, then shuffle. |battlefield, then shuffle.
|
||||
| | |
|
||||
|Reanimate {B} (Sorcery) >> |Thoughtseize {B} (Sorcery) >> |Verdant Catacombs (Land) >>
|
||||
|Put target creature card from |Target player reveals their |{T}, Pay 1 life, Sacrifice
|
||||
|a graveyard onto the |hand. You choose a nonland |Verdant Catacombs: Search
|
||||
|battlefield under your |card from it. That player |your library for a Swamp or
|
||||
|control. You lose life equal |discards that card. You lose |Forest card, put it onto the
|
||||
|to its mana value. |2 life. |battlefield, then shuffle.
|
||||
| | |
|
||||
|Windswept Heath (Land) >> |Wooded Foothills (Land) >> |Archon of Emeria {2}{W}
|
||||
|{T}, Pay 1 life, Sacrifice |{T}, Pay 1 life, Sacrifice |(Creature Archon) >> Flying
|
||||
|Windswept Heath: Search your |Wooded Foothills: Search your |Each player can't cast more
|
||||
|library for a Forest or |library for a Mountain or |than one spell each turn.
|
||||
|Plains card, put it onto the |Forest card, put it onto the |Nonbasic lands your opponents
|
||||
|battlefield, then shuffle. |battlefield, then shuffle. |control enter the battlefield
|
||||
| | |tapped. >> 2/3
|
||||
| | |
|
||||
|Bloodstained Mire (Land) >> |Chrome Mox {0} (Artifact) >> |Godless Shrine (Land Plains
|
||||
|{T}, Pay 1 life, Sacrifice |Imprint When Chrome Mox |Swamp) >> ({T}: Add {W} or
|
||||
|Bloodstained Mire: Search |enters the battlefield, you |{B}.) As Godless Shrine
|
||||
|your library for a Swamp or |may exile a nonartifact, |enters the battlefield, you
|
||||
|Mountain card, put it onto |nonland card from your hand. |may pay 2 life. If you don't,
|
||||
|the battlefield, then |{T}: Add one mana of any of |it enters the battlefield
|
||||
|shuffle. |the exiled card's colors. |tapped.
|
||||
| | |
|
||||
|Ignoble Hierarch {G} |Inquisition of Kozilek {B} |Noble Hierarch {G} (Creature
|
||||
|(Creature Goblin Shaman) >> |(Sorcery) >> Target player |Human Druid) >> Exalted
|
||||
|Exalted (Whenever a creature |reveals their hand. You |(Whenever a creature you
|
||||
|you control attacks alone, |choose a nonland card from it |control attacks alone, that
|
||||
|that creature gets +1/+1 |with mana value 3 or less. |creature gets +1/+1 until end
|
||||
|until end of turn.) {T}: Add |That player discards that |of turn.) {T}: Add {G}, {W},
|
||||
|{B}, {R}, or {G}. >> 0/1 |card. |or {U}. >> 0/1
|
||||
| | |
|
||||
|Overgrown Tomb (Land Swamp |Path to Exile {W} (Instant) |Prismatic Ending {X}{W}
|
||||
|Forest) >> ({T}: Add {B} or |>> Exile target creature. Its |(Sorcery) >> Converge Exile
|
||||
|{G}.) As Overgrown Tomb |controller may search their |target nonland permanent if
|
||||
|enters the battlefield, you |library for a basic land |its mana value is less than
|
||||
|may pay 2 life. If you don't, |card, put that card onto the |or equal to the number of
|
||||
|it enters the battlefield |battlefield tapped, then |colors of mana spent to cast
|
||||
|tapped. |shuffle. |this spell.
|
||||
| | |
|
||||
|Scalding Tarn (Land) >> {T}, |Scavenging Ooze {1}{G} |Stomping Ground (Land
|
||||
|Pay 1 life, Sacrifice |(Creature Ooze) >> {G}: |Mountain Forest) >> ({T}: Add
|
||||
|Scalding Tarn: Search your |Exile target card from a |{R} or {G}.) As Stomping
|
||||
|library for an Island or |graveyard. If it was a |Ground enters the
|
||||
|Mountain card, put it onto |creature card, put a +1/+1 |battlefield, you may pay 2
|
||||
|the battlefield, then |counter on Scavenging Ooze |life. If you don't, it enters
|
||||
|shuffle. |and you gain 1 life. >> 2/2 |the battlefield tapped.
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Tarmogoyf {1}{G} (Creature |Temple Garden (Land Forest |Thalia, Heretic Cathar {2}{W}
|
||||
|Lhurgoyf) >> Tarmogoyf's |Plains) >> ({T}: Add {G} or |(Legendary Creature Human
|
||||
|power is equal to the number |{W}.) As Temple Garden enters |Soldier) >> First strike
|
||||
|of card types among cards in |the battlefield, you may pay |Creatures and nonbasic lands
|
||||
|all graveyards and its |2 life. If you don't, it |your opponents control enter
|
||||
|toughness is equal to that |enters the battlefield |the battlefield tapped. >>
|
||||
|number plus 1. >> */1+* |tapped. |3/2
|
||||
| | |
|
||||
|Unearth {B} (Sorcery) >> |Dark Confidant {1}{B} |Fatal Push {B} (Instant) >>
|
||||
|Return target creature card |(Creature Human Wizard) >> |Destroy target creature if it
|
||||
|with mana value 3 or less |At the beginning of your |has mana value 2 or less.
|
||||
|from your graveyard to the |upkeep, reveal the top card |Revolt Destroy that creature
|
||||
|battlefield. Cycling {2} |of your library and put that |if it has mana value 4 or
|
||||
|({2}, Discard this card: Draw |card into your hand. You lose |less instead if a permanent
|
||||
|a card.) |life equal to its mana value. |you controlled left the
|
||||
| |>> 2/1 |battlefield this turn.
|
||||
| | |
|
||||
|Green Sun's Zenith {X}{G} |Hexdrinker {G} (Creature |Shadowspear {1} (Legendary
|
||||
|(Sorcery) >> Search your |Snake) >> Level up {1} ({1}: |Artifact Equipment) >>
|
||||
|library for a green creature |Put a level counter on this. |Equipped creature gets +1/+1
|
||||
|card with mana value X or |Level up only as a sorcery.) |and has trample and lifelink.
|
||||
|less, put it onto the |LEVEL 3-7 4/4 Protection from |{1}: Permanents your
|
||||
|battlefield, then shuffle. |instants LEVEL 8+ 6/6 |opponents control lose
|
||||
|Shuffle Green Sun's Zenith |Protection from everything >> |hexproof and indestructible
|
||||
|into its owner's library. |2/1 |until end of turn. Equip {2}
|
||||
| | |
|
||||
|Forth Eorlingas! {X}{R}{W} |Mox Diamond {0} (Artifact) >> |Undermountain Adventurer
|
||||
|(Sorcery) >> Create X 2/2 red |If Mox Diamond would enter |{3}{G} (Creature Giant
|
||||
|Human Knight creature tokens |the battlefield, you may |Warrior) >> Vigilance When
|
||||
|with trample and haste. |discard a land card instead. |Undermountain Adventurer
|
||||
|Whenever one or more |If you do, put Mox Diamond |enters the battlefield, you
|
||||
|creatures you control deal |onto the battlefield. If you |take the initiative. {T}: Add
|
||||
|combat damage to one or more |don't, put it into its |{G}{G}. If you've completed a
|
||||
|players this turn, you become |owner's graveyard. {T}: Add |dungeon, add six {G} instead.
|
||||
|the monarch. |one mana of any color. |>> 3/4
|
||||
| | |
|
||||
|Endurance {1}{G}{G} (Creature |Orcish Bowmasters {1}{B} |Troll of Khazad-dm {5}{B}
|
||||
| Elemental Incarnation) >> |(Creature Orc Archer) >> |(Creature Troll) >> Troll of
|
||||
|Flash Reach When Endurance |Flash When Orcish Bowmasters |Khazad-dm can't be blocked
|
||||
|enters the battlefield, up to |enters the battlefield and |except by three or more
|
||||
|one target player puts all |whenever an opponent draws a |creatures. Swampcycling {1}
|
||||
|the cards from their |card except the first one |({1}, Discard this card:
|
||||
|graveyard on the bottom of |they draw in each of their |Search your library for a
|
||||
|their library in a random |draw steps, Orcish Bowmasters |Swamp card, reveal it, put it
|
||||
|order. EvokeExile a green |deals 1 damage to any target. |into your hand, then
|
||||
|card from your hand. >> 3/4 |Then amass Orcs 1. >> 1/1 |shuffle.) >> 6/5
|
||||
| | |
|
||||
|Underground Mortuary (Land |Cankerbloom {1}{G} (Creature |Leyline Binding {5}{W}
|
||||
|Swamp Forest) >> ({T}: Add |Phyrexian Fungus) >> {1}, |(Enchantment) >> Flash Domain
|
||||
|{B} or {G}.) Underground |Sacrifice Cankerbloom: Choose | This spell costs {1} less to
|
||||
|Mortuary enters the |one Destroy target |cast for each basic land type
|
||||
|battlefield tapped. When |artifact. Destroy target |among lands you control. When
|
||||
|Underground Mortuary enters |enchantment. Proliferate. |Leyline Binding enters the
|
||||
|the battlefield, surveil 1. |(Choose any number of |battlefield, exile target
|
||||
|(Look at the top card of your |permanents and/or players, |nonland permanent an opponent
|
||||
|library. You may put it into |then give each another |controls until Leyline
|
||||
|your graveyard.) |counter of each kind already |Binding leaves the
|
||||
| |there.) >> 3/2 |battlefield.
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Tidehollow Sculler {W}{B} |White Plume Adventurer {2}{W} |Ayara's Oathsworn {1}{B}
|
||||
|(Artifact Creature Zombie) |(Creature Orc Cleric) >> |(Creature Human Knight) >>
|
||||
|>> When Tidehollow Sculler |When White Plume Adventurer |Menace Whenever Ayara's
|
||||
|enters the battlefield, |enters the battlefield, you |Oathsworn deals combat damage
|
||||
|target opponent reveals their |take the initiative. At the |to a player, if it has fewer
|
||||
|hand and you choose a nonland |beginning of each opponent's |than four +1/+1 counters on
|
||||
|card from it. Exile that |upkeep, untap a creature you |it, put a +1/+1 counter on
|
||||
|card. When Tidehollow Sculler |control. If you've completed |it. Then if it has exactly
|
||||
|leaves the battlefield, |a dungeon, untap all |four +1/+1 counters on it,
|
||||
|return the exiled card to its |creatures you control |search your library for a
|
||||
|owner's hand. >> 2/2 |instead. >> 3/3 |card, put it into your hand,
|
||||
| | |then shuffle. >> 2/2
|
||||
| | |
|
||||
|Deathrite Shaman {B/G} |Laelia, the Blade Reforged |Lord Skitter, Sewer King
|
||||
|(Creature Elf Shaman) >> |{2}{R} (Legendary Creature |{2}{B} (Legendary Creature
|
||||
|{T}: Exile target land card |Spirit Warrior) >> Haste |Rat Noble) >> Whenever
|
||||
|from a graveyard. Add one |Whenever Laelia, the Blade |another Rat enters the
|
||||
|mana of any color. {B}, {T}: |Reforged attacks, exile the |battlefield under your
|
||||
|Exile target instant or |top card of your library. You |control, exile up to one
|
||||
|sorcery card from a |may play that card this turn. |target card from an
|
||||
|graveyard. Each opponent |Whenever one or more cards |opponent's graveyard. At the
|
||||
|loses 2 life. {G}, {T}: Exile |are put into exile from your |beginning of combat on your
|
||||
|target creature card from a |library and/or your |turn, create a 1/1 black Rat
|
||||
|graveyard. You gain 2 life. |graveyard, put a +1/+1 |creature token with "This
|
||||
|>> 1/2 |counter on Laelia. >> 2/2 |creature can't block." >> 3/3
|
||||
| | |
|
||||
|Once Upon a Time {1}{G} |Sentinel of the Nameless City |Witherbloom Command {B}{G}
|
||||
|(Instant) >> If this spell is |{2}{G} (Creature Merfolk |(Sorcery) >> Choose two
|
||||
|the first spell you've cast |Warrior Scout) >> Vigilance |Target player mills three
|
||||
|this game, you may cast it |Whenever Sentinel of the |cards, then you return a land
|
||||
|without paying its mana cost. |Nameless City enters the |card from your graveyard to
|
||||
|Look at the top five cards of |battlefield or attacks, |your hand. Destroy target
|
||||
|your library. You may reveal |create a Map token. (It's an |noncreature, nonland
|
||||
|a creature or land card from |artifact with "{1}, {T}, |permanent with mana value 2
|
||||
|among them and put it into |Sacrifice this artifact: |or less. Target creature
|
||||
|your hand. Put the rest on |Target creature you control |gets -3/-1 until end of turn.
|
||||
|the bottom of your library in |explores. Activate only as a | Target opponent loses 2 life
|
||||
|a random order. |sorcery.") >> 3/4 |and you gain 2 life.
|
||||
| | |
|
||||
|Broadside Bombardiers {2}{R} |Generous Ent {5}{G} (Creature |Inti, Seneschal of the Sun
|
||||
|(Creature Goblin Pirate) >> | Treefolk) >> Reach When |{1}{R} (Legendary Creature
|
||||
|Menace, haste Boast |Generous Ent enters the |Human Knight) >> Whenever you
|
||||
|Sacrifice another creature or |battlefield, create a Food |attack, you may discard a
|
||||
|artifact: Broadside |token. (It's an artifact with |card. When you do, put a
|
||||
|Bombardiers deals damage |"{2}, {T}, Sacrifice this |+1/+1 counter on target
|
||||
|equal to 2 plus the |artifact: You gain 3 life.") |attacking creature. It gains
|
||||
|sacrificed permanent's mana |Forestcycling {1} ({1}, |trample until end of turn.
|
||||
|value to any target. |Discard this card: Search |Whenever you discard one or
|
||||
|(Activate only if this |your library for a Forest |more cards, exile the top
|
||||
|creature attacked this turn |card, reveal it, put it into |card of your library. You may
|
||||
|and only once each turn.) >> |your hand, then shuffle.) >> |play that card until your
|
||||
|2/2 |5/7 |next end step. >> 2/2
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Legolas's Quick Reflexes {G} |Mawloc {X}{R}{G} (Creature |Mosswood Dreadknight // Dread
|
||||
|(Instant) >> Split second (As |Tyranid) >> Ravenous (This |Whispers {1}{G} // {1}{B}
|
||||
|long as this spell is on the |creature enters the |(Creature Human Knight //
|
||||
|stack, players can't cast |battlefield with X +1/+1 |Sorcery Adventure) >> >>
|
||||
|spells or activate abilities |counters on it. If X is 5 or |3/2Trample When Mosswood
|
||||
|that aren't mana abilities.) |more, draw a card when it |Dreadknight dies, you may
|
||||
|Untap target creature. Until |enters.) Terror from the Deep |cast it from your graveyard
|
||||
|end of turn, it gains | When Mawloc enters the |as an Adventure until the end
|
||||
|hexproof, reach, and |battlefield, it fights up to |of your next turn. 3/2 // You
|
||||
|"Whenever this creature |one target creature an |draw a card and you lose 1
|
||||
|becomes tapped, it deals |opponent controls. If that |life. (Then exile this card.
|
||||
|damage equal to its power to |creature would die this turn, |You may cast the creature
|
||||
|up to one target creature." |exile it instead. >> 2/2 |later from exile.)
|
||||
| | |
|
||||
|Anointed Peacekeeper {2}{W} |Caves of Chaos Adventurer |Opposition Agent {2}{B}
|
||||
|(Creature Human Cleric) >> |{3}{R} (Creature Human |(Creature Human Rogue) >>
|
||||
|Vigilance As Anointed |Barbarian) >> Trample When |Flash You control your
|
||||
|Peacekeeper enters the |Caves of Chaos Adventurer |opponents while they're
|
||||
|battlefield, look at an |enters the battlefield, you |searching their libraries.
|
||||
|opponent's hand, then choose |take the initiative. Whenever |While an opponent is
|
||||
|any card name. Spells your |Caves of Chaos Adventurer |searching their library, they
|
||||
|opponents cast with the |attacks, exile the top card |exile each card they find.
|
||||
|chosen name cost {2} more to |of your library. If you've |You may play those cards for
|
||||
|cast. Activated abilities of |completed a dungeon, you may |as long as they remain
|
||||
|sources with the chosen name |play that card this turn |exiled, and you may spend
|
||||
|cost {2} more to activate |without paying its mana cost. |mana as though it were mana
|
||||
|unless they're mana |Otherwise, you may play that |of any color to cast them. >>
|
||||
|abilities. >> 3/3 |card this turn. >> 5/3 |3/2
|
||||
| | |
|
||||
|Questing Beast {2}{G}{G} |Boseiju, Who Endures |Sungold Sentinel {1}{W}
|
||||
|(Legendary Creature Beast) |(Legendary Land) >> {T}: Add |(Creature Human Soldier) >>
|
||||
|>> Vigilance, deathtouch, |{G}. Channel {1}{G}, Discard |Whenever Sungold Sentinel
|
||||
|haste Questing Beast can't be |Boseiju, Who Endures: Destroy |enters the battlefield or
|
||||
|blocked by creatures with |target artifact, enchantment, |attacks, exile up to one
|
||||
|power 2 or less. Combat |or nonbasic land an opponent |target card from a graveyard.
|
||||
|damage that would be dealt by |controls. That player may |Coven {1}{W}: Choose a
|
||||
|creatures you control can't |search their library for a |color. Sungold Sentinel gains
|
||||
|be prevented. Whenever |land card with a basic land |hexproof from that color
|
||||
|Questing Beast deals combat |type, put it onto the |until end of turn and can't
|
||||
|damage to an opponent, it |battlefield, then shuffle. |be blocked by creatures of
|
||||
|deals that much damage to |This ability costs {1} less |that color this turn.
|
||||
|target planeswalker that |to activate for each |Activate only if you control
|
||||
|player controls. >> 4/4 |legendary creature you |three or more creatures with
|
||||
| |control. |different powers. >> 3/2
|
||||
| | |
|
||||
|Tenth District Hero {1}{W} |Wrenn and Six {R}{G} |Seasoned Dungeoneer {3}{W}
|
||||
|(Creature Human) >> {1}{W}, |(Legendary Planeswalker |(Creature Human Warrior) >>
|
||||
|Collect evidence 2: Tenth |Wrenn) >> +1: Return up to |When Seasoned Dungeoneer
|
||||
|District Hero becomes a Human |one target land card from |enters the battlefield, you
|
||||
|Detective with base power and |your graveyard to your hand. |take the initiative. Whenever
|
||||
|toughness 4/4 and gains |1: Wrenn and Six deals 1 |you attack, target attacking
|
||||
|vigilance. {2}{W}, Collect |damage to any target. 7: You |Cleric, Rogue, Warrior, or
|
||||
|evidence 4: If Tenth District |get an emblem with "Instant |Wizard gains protection from
|
||||
|Hero is a Detective, it |and sorcery cards in your |creatures until end of turn.
|
||||
|becomes a legendary creature |graveyard have retrace." (You |It explores. (Reveal the top
|
||||
|named Mileva, the Stalwart, |may cast instant and sorcery |card of your library. Put
|
||||
|it has base power and |cards from your graveyard by |that card into your hand if
|
||||
|toughness 5/5, and it gains |discarding a land card in |it's a land. Otherwise, put a
|
||||
|"Other creatures you control |addition to paying their |+1/+1 counter on the
|
||||
|have indestructible." >> 2/3 |other costs.) |creature, then put the card
|
||||
| | |back or put it into your
|
||||
| | |graveyard.) >> 3/4
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Comet, Stellar Pup {2}{R}{W} |Kellan, Daring Traveler // |Grist, the Hunger Tide
|
||||
|(Legendary Planeswalker |Journey On {1}{W} // {G} |{1}{B}{G} (Legendary
|
||||
|Comet) >> 0: Roll a six-sided |(Legendary Creature Human |Planeswalker Grist) >> As
|
||||
|die. 1 or 2 [+2], then |Faerie Scout // Sorcery |long as Grist, the Hunger
|
||||
|create two 1/1 green Squirrel |Adventure) >> >> 2/3Whenever |Tide isn't on the
|
||||
|creature tokens. They gain |Kellan, Daring Traveler |battlefield, it's a 1/1
|
||||
|haste until end of turn. 3 |attacks, reveal the top card |Insect creature in addition
|
||||
|[1], then return a card with |of your library. If it's a |to its other types. +1:
|
||||
|mana value 2 or less from |creature card with mana value |Create a 1/1 black and green
|
||||
|your graveyard to your hand. |3 or less, put it into your |Insect creature token, then
|
||||
|4 or 5 Comet, Stellar Pup |hand. Otherwise, you may put |mill a card. If an Insect
|
||||
|deals damage equal to the |it into your graveyard. 2/3 |card was milled this way, put
|
||||
|number of loyalty counters on |// Create X Map tokens, where |a loyalty counter on Grist
|
||||
|him to a creature or player, |X is one plus the number of |and repeat this process. 2:
|
||||
|then [2]. 6 [+1], and you |opponents who control an |You may sacrifice a creature.
|
||||
|may activate Comet, Stellar |artifact. (Then exile this |When you do, destroy target
|
||||
|Pup's loyalty ability two |card. You may cast the |creature or planeswalker. 5:
|
||||
|more times this turn. |creature later from exile.) |Each opponent loses life
|
||||
| | |equal to the number of
|
||||
| | |creature cards in your
|
||||
| | |graveyard.
|
||||
| | |
|
||||
|Minsc & Boo, Timeless Heroes | |
|
||||
|{2}{R}{G} (Legendary | |
|
||||
|Planeswalker Minsc) >> When | |
|
||||
|Minsc & Boo, Timeless Heroes | |
|
||||
|enters the battlefield and at | |
|
||||
|the beginning of your upkeep, | |
|
||||
|you may create Boo, a | |
|
||||
|legendary 1/1 red Hamster | |
|
||||
|creature token with trample | |
|
||||
|and haste. +1: Put three | |
|
||||
|+1/+1 counters on up to one | |
|
||||
|target creature with trample | |
|
||||
|or haste. 2: Sacrifice a | |
|
||||
|creature. When you do, Minsc | |
|
||||
|& Boo, Timeless Heroes deals | |
|
||||
|Prismatic Vista (Land) >> |Mox Jet {0} (Artifact) >> |Tenth District Hero {1}{W}
|
||||
|{T}, Pay 1 life, Sacrifice |{T}: Add {B}. |(Creature Human) >> {1}{W},
|
||||
|Prismatic Vista: Search your | |Collect evidence 2: Tenth
|
||||
|library for a basic land | |District Hero becomes a Human
|
||||
|card, put it onto the | |Detective with base power and
|
||||
|battlefield, then shuffle. | |toughness 4/4 and gains
|
||||
| | |vigilance. {2}{W}, Collect
|
||||
| | |evidence 4: If Tenth District
|
||||
| | |Hero is a Detective, it
|
||||
| | |becomes a legendary creature
|
||||
| | |named Mileva, the Stalwart,
|
||||
| | |it has base power and
|
||||
| | |toughness 5/5, and it gains
|
||||
| | |"Other creatures you control
|
||||
| | |have indestructible." (2/3)
|
||||
| | |
|
||||
|Wasteland (Land) >> {T}: Add |Misty Rainforest (Land) >> |Green Sun's Zenith {X}{G}
|
||||
|{C}. {T}, Sacrifice |{T}, Pay 1 life, Sacrifice |(Sorcery) >> Search your
|
||||
|Wasteland: Destroy target |Misty Rainforest: Search your |library for a green creature
|
||||
|nonbasic land. |library for a Forest or |card with mana value X or
|
||||
| |Island card, put it onto the |less, put it onto the
|
||||
| |battlefield, then shuffle. |battlefield, then shuffle.
|
||||
| | |Shuffle Green Sun's Zenith
|
||||
| | |into its owner's library.
|
||||
| | |
|
||||
|Grist, the Hunger Tide |Wrenn and Six {R}{G} |Thalia, Heretic Cathar {2}{W}
|
||||
|{1}{B}{G} (Legendary |(Legendary Planeswalker |(Legendary Creature Human
|
||||
|Planeswalker Grist) >> As |Wrenn) >> +1: Return up to |Soldier) >> First strike
|
||||
|long as Grist, the Hunger |one target land card from |Creatures and nonbasic lands
|
||||
|Tide isn't on the |your graveyard to your hand. |your opponents control enter
|
||||
|battlefield, it's a 1/1 |1: Wrenn and Six deals 1 |the battlefield tapped. (3/2)
|
||||
|Insect creature in addition |damage to any target. 7: You |
|
||||
|to its other types. +1: |get an emblem with "Instant |
|
||||
|Create a 1/1 black and green |and sorcery cards in your |
|
||||
|Insect creature token, then |graveyard have retrace." (You |
|
||||
|mill a card. If an Insect |may cast instant and sorcery |
|
||||
|card was milled this way, put |cards from your graveyard by |
|
||||
|a loyalty counter on Grist |discarding a land card in |
|
||||
|and repeat this process. 2: |addition to paying their |
|
||||
|You may sacrifice a creature. |other costs.) |
|
||||
|When you do, destroy target | |
|
||||
|creature or planeswalker. 5: | |
|
||||
|Each opponent loses life | |
|
||||
|equal to the number of | |
|
||||
|creature cards in your | |
|
||||
|graveyard. | |
|
||||
| | |
|
||||
|Badlands (Land Swamp |Stomping Ground (Land |Fatal Push {B} (Instant) >>
|
||||
|Mountain) >> ({T}: Add {B} or |Mountain Forest) >> ({T}: Add |Destroy target creature if it
|
||||
|{R}.) |{R} or {G}.) As Stomping |has mana value 2 or less.
|
||||
| |Ground enters the |Revolt Destroy that creature
|
||||
| |battlefield, you may pay 2 |if it has mana value 4 or
|
||||
| |life. If you don't, it enters |less instead if a permanent
|
||||
| |the battlefield tapped. |you controlled left the
|
||||
| | |battlefield this turn.
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Inti, Seneschal of the Sun |Mental Misstep {U/P} |Abrupt Decay {B}{G} (Instant)
|
||||
|{1}{R} (Legendary Creature |(Instant) >> ({U/P} can be |>> This spell can't be
|
||||
|Human Knight) >> Whenever you |paid with either {U} or 2 |countered. Destroy target
|
||||
|attack, you may discard a |life.) Counter target spell |nonland permanent with mana
|
||||
|card. When you do, put a |with mana value 1. |value 3 or less.
|
||||
|+1/+1 counter on target | |
|
||||
|attacking creature. It gains | |
|
||||
|trample until end of turn. | |
|
||||
|Whenever you discard one or | |
|
||||
|more cards, exile the top | |
|
||||
|card of your library. You may | |
|
||||
|play that card until your | |
|
||||
|next end step. (2/2) | |
|
||||
| | |
|
||||
|Gitaxian Probe {U/P} |Opposition Agent {2}{B} |Scavenging Ooze {1}{G}
|
||||
|(Sorcery) >> ({U/P} can be |(Creature Human Rogue) >> |(Creature Ooze) >> {G}:
|
||||
|paid with either {U} or 2 |Flash You control your |Exile target card from a
|
||||
|life.) Look at target |opponents while they're |graveyard. If it was a
|
||||
|player's hand. Draw a card. |searching their libraries. |creature card, put a +1/+1
|
||||
| |While an opponent is |counter on Scavenging Ooze
|
||||
| |searching their library, they |and you gain 1 life. (2/2)
|
||||
| |exile each card they find. |
|
||||
| |You may play those cards for |
|
||||
| |as long as they remain |
|
||||
| |exiled, and you may spend |
|
||||
| |mana as though it were mana |
|
||||
| |of any color to cast them. |
|
||||
| |(3/2) |
|
||||
| | |
|
||||
|Dark Confidant {1}{B} |Troll of Khazad-dm {5}{B} |Taiga (Land Mountain Forest)
|
||||
|(Creature Human Wizard) >> |(Creature Troll) >> Troll of |>> ({T}: Add {R} or {G}.)
|
||||
|At the beginning of your |Khazad-dm can't be blocked |
|
||||
|upkeep, reveal the top card |except by three or more |
|
||||
|of your library and put that |creatures. Swampcycling {1} |
|
||||
|card into your hand. You lose |({1}, Discard this card: |
|
||||
|life equal to its mana value. |Search your library for a |
|
||||
|(2/1) |Swamp card, reveal it, put it |
|
||||
| |into your hand, then |
|
||||
| |shuffle.) (6/5) |
|
||||
| | |
|
||||
|Deathrite Shaman {B/G} |Windswept Heath (Land) >> |Prismatic Ending {X}{W}
|
||||
|(Creature Elf Shaman) >> |{T}, Pay 1 life, Sacrifice |(Sorcery) >> Converge Exile
|
||||
|{T}: Exile target land card |Windswept Heath: Search your |target nonland permanent if
|
||||
|from a graveyard. Add one |library for a Forest or |its mana value is less than
|
||||
|mana of any color. {B}, {T}: |Plains card, put it onto the |or equal to the number of
|
||||
|Exile target instant or |battlefield, then shuffle. |colors of mana spent to cast
|
||||
|sorcery card from a | |this spell.
|
||||
|graveyard. Each opponent | |
|
||||
|loses 2 life. {G}, {T}: Exile | |
|
||||
|target creature card from a | |
|
||||
|graveyard. You gain 2 life. | |
|
||||
|(1/2) | |
|
||||
| | |
|
||||
|Undermountain Adventurer |Lotus Petal {0} (Artifact) >> |Duress {B} (Sorcery) >>
|
||||
|{3}{G} (Creature Giant |{T}, Sacrifice Lotus Petal: |Target opponent reveals their
|
||||
|Warrior) >> Vigilance When |Add one mana of any color. |hand. You choose a
|
||||
|Undermountain Adventurer | |noncreature, nonland card
|
||||
|enters the battlefield, you | |from it. That player discards
|
||||
|take the initiative. {T}: Add | |that card.
|
||||
|{G}{G}. If you've completed a | |
|
||||
|dungeon, add six {G} instead. | |
|
||||
|(3/4) | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Forth Eorlingas! {X}{R}{W} |Mox Emerald {0} (Artifact) >> |Inquisition of Kozilek {B}
|
||||
|(Sorcery) >> Create X 2/2 red |{T}: Add {G}. |(Sorcery) >> Target player
|
||||
|Human Knight creature tokens | |reveals their hand. You
|
||||
|with trample and haste. | |choose a nonland card from it
|
||||
|Whenever one or more | |with mana value 3 or less.
|
||||
|creatures you control deal | |That player discards that
|
||||
|combat damage to one or more | |card.
|
||||
|players this turn, you become | |
|
||||
|the monarch. | |
|
||||
| | |
|
||||
|Minsc & Boo, Timeless Heroes |Tarmogoyf (Token Creature |Sungold Sentinel {1}{W}
|
||||
|{2}{R}{G} (Legendary |Lhurgoyf) >> Tarmogoyf's |(Creature Human Soldier) >>
|
||||
|Planeswalker Minsc) >> When |power is equal to the number |Whenever Sungold Sentinel
|
||||
|Minsc & Boo, Timeless Heroes |of card types among cards in |enters the battlefield or
|
||||
|enters the battlefield and at |all graveyards and its |attacks, exile up to one
|
||||
|the beginning of your upkeep, |toughness is equal to that |target card from a graveyard.
|
||||
|you may create Boo, a |number plus 1. (This token's |Coven {1}{W}: Choose a
|
||||
|legendary 1/1 red Hamster |mana cost is {1}{G}.) (*/1+*) |color. Sungold Sentinel gains
|
||||
|creature token with trample | |hexproof from that color
|
||||
|and haste. +1: Put three | |until end of turn and can't
|
||||
|+1/+1 counters on up to one | |be blocked by creatures of
|
||||
|target creature with trample | |that color this turn.
|
||||
|or haste. 2: Sacrifice a | |Activate only if you control
|
||||
|creature. When you do, Minsc | |three or more creatures with
|
||||
|& Boo, Timeless Heroes deals | |different powers. (3/2)
|
||||
|X damage to any target, where | |
|
||||
|X is that creature's power. | |
|
||||
|If the sacrificed creature | |
|
||||
|
@ -373,4 +163,328 @@
|
|||
|Minsc & Boo, Timeless Heroes | |
|
||||
|can be your commander. | |
|
||||
| | |
|
||||
|Simian Spirit Guide {2}{R} |Eladamri's Call {G}{W} |Unearth {B} (Sorcery) >>
|
||||
|(Creature Ape Spirit) >> |(Instant) >> Search your |Return target creature card
|
||||
|Exile Simian Spirit Guide |library for a creature card, |with mana value 3 or less
|
||||
|from your hand: Add {R}. |reveal that card, put it into |from your graveyard to the
|
||||
|(2/2) |your hand, then shuffle. |battlefield. Cycling {2}
|
||||
| | |({2}, Discard this card: Draw
|
||||
| | |a card.)
|
||||
| | |
|
||||
|Tidehollow Sculler {W}{B} |White Plume Adventurer {2}{W} |Swamp (Basic Land Swamp) >>
|
||||
|(Artifact Creature Zombie) |(Creature Orc Cleric) >> |({T}: Add {B}.)
|
||||
|>> When Tidehollow Sculler |When White Plume Adventurer |
|
||||
|enters the battlefield, |enters the battlefield, you |
|
||||
|target opponent reveals their |take the initiative. At the |
|
||||
|hand and you choose a nonland |beginning of each opponent's |
|
||||
|card from it. Exile that |upkeep, untap a creature you |
|
||||
|card. When Tidehollow Sculler |control. If you've completed |
|
||||
|leaves the battlefield, |a dungeon, untap all |
|
||||
|return the exiled card to its |creatures you control |
|
||||
|owner's hand. (2/2) |instead. (3/3) |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Mosswood Dreadknight // Dread |Karakas (Legendary Land) >> |Legolas's Quick Reflexes {G}
|
||||
|Whispers {1}{G} // {1}{B} |{T}: Add {W}. {T}: Return |(Instant) >> Split second (As
|
||||
|(Creature Human Knight // |target legendary creature to |long as this spell is on the
|
||||
|Sorcery Adventure) >> (3/2) |its owner's hand. |stack, players can't cast
|
||||
|Trample When Mosswood | |spells or activate abilities
|
||||
|Dreadknight dies, you may | |that aren't mana abilities.)
|
||||
|cast it from your graveyard | |Untap target creature. Until
|
||||
|as an Adventure until the end | |end of turn, it gains
|
||||
|of your next turn. (3/2) | |hexproof, reach, and
|
||||
| // | |"Whenever this creature
|
||||
|You draw a card and you lose | |becomes tapped, it deals
|
||||
|1 life. (Then exile this | |damage equal to its power to
|
||||
|card. You may cast the | |up to one target creature."
|
||||
|creature later from exile.) | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Seasoned Dungeoneer {3}{W} |Mother of Runes {W} (Creature |Wooded Foothills (Land) >>
|
||||
|(Creature Human Warrior) >> | Human Cleric) >> {T}: Target |{T}, Pay 1 life, Sacrifice
|
||||
|When Seasoned Dungeoneer |creature you control gains |Wooded Foothills: Search your
|
||||
|enters the battlefield, you |protection from the color of |library for a Mountain or
|
||||
|take the initiative. Whenever |your choice until end of |Forest card, put it onto the
|
||||
|you attack, target attacking |turn. (1/1) |battlefield, then shuffle.
|
||||
|Cleric, Rogue, Warrior, or | |
|
||||
|Wizard gains protection from | |
|
||||
|creatures until end of turn. | |
|
||||
|It explores. (Reveal the top | |
|
||||
|card of your library. Put | |
|
||||
|that card into your hand if | |
|
||||
|it's a land. Otherwise, put a | |
|
||||
|+1/+1 counter on the | |
|
||||
|creature, then put the card | |
|
||||
|back or put it into your | |
|
||||
|graveyard.) (3/4) | |
|
||||
| | |
|
||||
|Verdant Catacombs (Land) >> |Hexdrinker {G} (Creature |Elvish Spirit Guide {2}{G}
|
||||
|{T}, Pay 1 life, Sacrifice |Snake) >> Level up {1} ({1}: |(Creature Elf Spirit) >>
|
||||
|Verdant Catacombs: Search |Put a level counter on this. |Exile Elvish Spirit Guide
|
||||
|your library for a Swamp or |Level up only as a sorcery.) |from your hand: Add {G}.
|
||||
|Forest card, put it onto the |LEVEL 3-7 4/4 Protection from |(2/2)
|
||||
|battlefield, then shuffle. |instants LEVEL 8+ 6/6 |
|
||||
| |Protection from everything |
|
||||
| |(2/1) |
|
||||
| | |
|
||||
|Savannah (Land Forest |Godless Shrine (Land Plains |Kellan, Daring Traveler //
|
||||
|Plains) >> ({T}: Add {G} or |Swamp) >> ({T}: Add {W} or |Journey On {1}{W} // {G}
|
||||
|{W}.) |{B}.) As Godless Shrine |(Legendary Creature Human
|
||||
| |enters the battlefield, you |Faerie Scout // Sorcery
|
||||
| |may pay 2 life. If you don't, |Adventure) >> (2/3) Whenever
|
||||
| |it enters the battlefield |Kellan, Daring Traveler
|
||||
| |tapped. |attacks, reveal the top card
|
||||
| | |of your library. If it's a
|
||||
| | |creature card with mana value
|
||||
| | |3 or less, put it into your
|
||||
| | |hand. Otherwise, you may put
|
||||
| | |it into your graveyard. (2/3)
|
||||
| | |
|
||||
| | |// Create X Map tokens, where
|
||||
| | |X is one plus the number of
|
||||
| | |opponents who control an
|
||||
| | |artifact. (Then exile this
|
||||
| | |card. You may cast the
|
||||
| | |creature later from exile.)
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Witherbloom Command {B}{G} |Mox Pearl {0} (Artifact) >> |Underground Mortuary (Land
|
||||
|(Sorcery) >> Choose two |{T}: Add {W}. |Swamp Forest) >> ({T}: Add
|
||||
|Target player mills three | |{B} or {G}.) Underground
|
||||
|cards, then you return a land | |Mortuary enters the
|
||||
|card from your graveyard to | |battlefield tapped. When
|
||||
|your hand. Destroy target | |Underground Mortuary enters
|
||||
|noncreature, nonland | |the battlefield, surveil 1.
|
||||
|permanent with mana value 2 | |(Look at the top card of your
|
||||
|or less. Target creature | |library. You may put it into
|
||||
|gets -3/-1 until end of turn. | |your graveyard.)
|
||||
| Target opponent loses 2 life | |
|
||||
|and you gain 2 life. | |
|
||||
| | |
|
||||
|Shadowspear {1} (Legendary |Razorverge Thicket (Land) >> |Overgrown Tomb (Land Swamp
|
||||
|Artifact Equipment) >> |Razorverge Thicket enters the |Forest) >> ({T}: Add {B} or
|
||||
|Equipped creature gets +1/+1 |battlefield tapped unless you |{G}.) As Overgrown Tomb
|
||||
|and has trample and lifelink. |control two or fewer other |enters the battlefield, you
|
||||
|{1}: Permanents your |lands. {T}: Add {G} or {W}. |may pay 2 life. If you don't,
|
||||
|opponents control lose | |it enters the battlefield
|
||||
|hexproof and indestructible | |tapped.
|
||||
|until end of turn. Equip {2} | |
|
||||
| | |
|
||||
|Noble Hierarch {G} (Creature |Thalia, Guardian of Thraben |Reanimate {B} (Sorcery) >>
|
||||
|Human Druid) >> Exalted |{1}{W} (Legendary Creature |Put target creature card from
|
||||
|(Whenever a creature you |Human Soldier) >> First |a graveyard onto the
|
||||
|control attacks alone, that |strike Noncreature spells |battlefield under your
|
||||
|creature gets +1/+1 until end |cost {1} more to cast. (2/1) |control. You lose life equal
|
||||
|of turn.) {T}: Add {G}, {W}, | |to its mana value.
|
||||
|or {U}. (0/1) | |
|
||||
| | |
|
||||
|Laelia, the Blade Reforged |Sentinel of the Nameless City |Anointed Peacekeeper {2}{W}
|
||||
|{2}{R} (Legendary Creature |{2}{G} (Creature Merfolk |(Creature Human Cleric) >>
|
||||
|Spirit Warrior) >> Haste |Warrior Scout) >> Vigilance |Vigilance As Anointed
|
||||
|Whenever Laelia, the Blade |Whenever Sentinel of the |Peacekeeper enters the
|
||||
|Reforged attacks, exile the |Nameless City enters the |battlefield, look at an
|
||||
|top card of your library. You |battlefield or attacks, |opponent's hand, then choose
|
||||
|may play that card this turn. |create a Map token. (It's an |any card name. Spells your
|
||||
|Whenever one or more cards |artifact with "{1}, {T}, |opponents cast with the
|
||||
|are put into exile from your |Sacrifice this artifact: |chosen name cost {2} more to
|
||||
|library and/or your |Target creature you control |cast. Activated abilities of
|
||||
|graveyard, put a +1/+1 |explores. Activate only as a |sources with the chosen name
|
||||
|counter on Laelia. (2/2) |sorcery.") (3/4) |cost {2} more to activate
|
||||
| | |unless they're mana
|
||||
| | |abilities. (3/3)
|
||||
| | |
|
||||
|Swords to Plowshares {W} |Forest (Basic Land Forest) |Leyline Binding {5}{W}
|
||||
|(Instant) >> Exile target |>> ({T}: Add {G}.) |(Enchantment) >> Flash Domain
|
||||
|creature. Its controller | | This spell costs {1} less to
|
||||
|gains life equal to its | |cast for each basic land type
|
||||
|power. | |among lands you control. When
|
||||
| | |Leyline Binding enters the
|
||||
| | |battlefield, exile target
|
||||
| | |nonland permanent an opponent
|
||||
| | |controls until Leyline
|
||||
| | |Binding leaves the
|
||||
| | |battlefield.
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Questing Beast {2}{G}{G} |Generous Ent {5}{G} (Creature |Bayou (Land Swamp Forest) >>
|
||||
|(Legendary Creature Beast) | Treefolk) >> Reach When |({T}: Add {B} or {G}.)
|
||||
|>> Vigilance, deathtouch, |Generous Ent enters the |
|
||||
|haste Questing Beast can't be |battlefield, create a Food |
|
||||
|blocked by creatures with |token. (It's an artifact with |
|
||||
|power 2 or less. Combat |"{2}, {T}, Sacrifice this |
|
||||
|damage that would be dealt by |artifact: You gain 3 life.") |
|
||||
|creatures you control can't |Forestcycling {1} ({1}, |
|
||||
|be prevented. Whenever |Discard this card: Search |
|
||||
|Questing Beast deals combat |your library for a Forest |
|
||||
|damage to an opponent, it |card, reveal it, put it into |
|
||||
|deals that much damage to |your hand, then shuffle.) |
|
||||
|target planeswalker that |(5/7) |
|
||||
|player controls. (4/4) | |
|
||||
| | |
|
||||
|Plains (Basic Land Plains) |Boseiju, Who Endures |Arid Mesa (Land) >> {T}, Pay
|
||||
|>> ({T}: Add {W}.) |(Legendary Land) >> {T}: Add |1 life, Sacrifice Arid Mesa:
|
||||
| |{G}. Channel {1}{G}, Discard |Search your library for a
|
||||
| |Boseiju, Who Endures: Destroy |Mountain or Plains card, put
|
||||
| |target artifact, enchantment, |it onto the battlefield, then
|
||||
| |or nonbasic land an opponent |shuffle.
|
||||
| |controls. That player may |
|
||||
| |search their library for a |
|
||||
| |land card with a basic land |
|
||||
| |type, put it onto the |
|
||||
| |battlefield, then shuffle. |
|
||||
| |This ability costs {1} less |
|
||||
| |to activate for each |
|
||||
| |legendary creature you |
|
||||
| |control. |
|
||||
| | |
|
||||
|Plateau (Land Mountain |Endurance {1}{G}{G} (Creature |Scrubland (Land Plains
|
||||
|Plains) >> ({T}: Add {R} or | Elemental Incarnation) >> |Swamp) >> ({T}: Add {W} or
|
||||
|{W}.) |Flash Reach When Endurance |{B}.)
|
||||
| |enters the battlefield, up to |
|
||||
| |one target player puts all |
|
||||
| |the cards from their |
|
||||
| |graveyard on the bottom of |
|
||||
| |their library in a random |
|
||||
| |order. EvokeExile a green |
|
||||
| |card from your hand. (3/4) |
|
||||
| | |
|
||||
|Ignoble Hierarch {G} |Scalding Tarn (Land) >> {T}, |Luminarch Aspirant {1}{W}
|
||||
|(Creature Goblin Shaman) >> |Pay 1 life, Sacrifice |(Creature Human Cleric) >>
|
||||
|Exalted (Whenever a creature |Scalding Tarn: Search your |At the beginning of combat on
|
||||
|you control attacks alone, |library for an Island or |your turn, put a +1/+1
|
||||
|that creature gets +1/+1 |Mountain card, put it onto |counter on target creature
|
||||
|until end of turn.) {T}: Add |the battlefield, then |you control. (1/1)
|
||||
|{B}, {R}, or {G}. (0/1) |shuffle. |
|
||||
| | |
|
||||
|Archon of Emeria {2}{W} |Once Upon a Time {1}{G} |Mana Confluence (Land) >>
|
||||
|(Creature Archon) >> Flying |(Instant) >> If this spell is |{T}, Pay 1 life: Add one mana
|
||||
|Each player can't cast more |the first spell you've cast |of any color.
|
||||
|than one spell each turn. |this game, you may cast it |
|
||||
|Nonbasic lands your opponents |without paying its mana cost. |
|
||||
|control enter the battlefield |Look at the top five cards of |
|
||||
|tapped. (2/3) |your library. You may reveal |
|
||||
| |a creature or land card from |
|
||||
| |among them and put it into |
|
||||
| |your hand. Put the rest on |
|
||||
| |the bottom of your library in |
|
||||
| |a random order. |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Birds of Paradise {G} |Cankerbloom {1}{G} (Creature |Path to Exile {W} (Instant)
|
||||
|(Creature Bird) >> Flying |Phyrexian Fungus) >> {1}, |>> Exile target creature. Its
|
||||
|{T}: Add one mana of any |Sacrifice Cankerbloom: Choose |controller may search their
|
||||
|color. (0/1) |one Destroy target |library for a basic land
|
||||
| |artifact. Destroy target |card, put that card onto the
|
||||
| |enchantment. Proliferate. |battlefield tapped, then
|
||||
| |(Choose any number of |shuffle.
|
||||
| |permanents and/or players, |
|
||||
| |then give each another |
|
||||
| |counter of each kind already |
|
||||
| |there.) (3/2) |
|
||||
| | |
|
||||
|Marsh Flats (Land) >> {T}, |Broadside Bombardiers {2}{R} |Caves of Chaos Adventurer
|
||||
|Pay 1 life, Sacrifice Marsh |(Creature Goblin Pirate) >> |{3}{R} (Creature Human
|
||||
|Flats: Search your library |Menace, haste Boast |Barbarian) >> Trample When
|
||||
|for a Plains or Swamp card, |Sacrifice another creature or |Caves of Chaos Adventurer
|
||||
|put it onto the battlefield, |artifact: Broadside |enters the battlefield, you
|
||||
|then shuffle. |Bombardiers deals damage |take the initiative. Whenever
|
||||
| |equal to 2 plus the |Caves of Chaos Adventurer
|
||||
| |sacrificed permanent's mana |attacks, exile the top card
|
||||
| |value to any target. |of your library. If you've
|
||||
| |(Activate only if this |completed a dungeon, you may
|
||||
| |creature attacked this turn |play that card this turn
|
||||
| |and only once each turn.) |without paying its mana cost.
|
||||
| |(2/2) |Otherwise, you may play that
|
||||
| | |card this turn. (5/3)
|
||||
| | |
|
||||
|Mawloc {X}{R}{G} (Creature |Comet, Stellar Pup {2}{R}{W} |Orcish Bowmasters {1}{B}
|
||||
|Tyranid) >> Ravenous (This |(Legendary Planeswalker |(Creature Orc Archer) >>
|
||||
|creature enters the |Comet) >> 0: Roll a six-sided |Flash When Orcish Bowmasters
|
||||
|battlefield with X +1/+1 |die. 1 or 2 [+2], then |enters the battlefield and
|
||||
|counters on it. If X is 5 or |create two 1/1 green Squirrel |whenever an opponent draws a
|
||||
|more, draw a card when it |creature tokens. They gain |card except the first one
|
||||
|enters.) Terror from the Deep |haste until end of turn. 3 |they draw in each of their
|
||||
| When Mawloc enters the |[1], then return a card with |draw steps, Orcish Bowmasters
|
||||
|battlefield, it fights up to |mana value 2 or less from |deals 1 damage to any target.
|
||||
|one target creature an |your graveyard to your hand. |Then amass Orcs 1. (1/1)
|
||||
|opponent controls. If that |4 or 5 Comet, Stellar Pup |
|
||||
|creature would die this turn, |deals damage equal to the |
|
||||
|exile it instead. (2/2) |number of loyalty counters on |
|
||||
| |him to a creature or player, |
|
||||
| |then [2]. 6 [+1], and you |
|
||||
| |may activate Comet, Stellar |
|
||||
| |Pup's loyalty ability two |
|
||||
| |more times this turn. |
|
||||
| | |
|
||||
|Chrome Mox {0} (Artifact) >> |Thoughtseize {B} (Sorcery) >> |Polluted Delta (Land) >> {T},
|
||||
|Imprint When Chrome Mox |Target player reveals their |Pay 1 life, Sacrifice
|
||||
|enters the battlefield, you |hand. You choose a nonland |Polluted Delta: Search your
|
||||
|may exile a nonartifact, |card from it. That player |library for an Island or
|
||||
|nonland card from your hand. |discards that card. You lose |Swamp card, put it onto the
|
||||
|{T}: Add one mana of any of |2 life. |battlefield, then shuffle.
|
||||
|the exiled card's colors. | |
|
||||
| | |
|
||||
|City of Brass (Land) >> |Mox Diamond {0} (Artifact) >> |Flooded Strand (Land) >> {T},
|
||||
|Whenever City of Brass |If Mox Diamond would enter |Pay 1 life, Sacrifice Flooded
|
||||
|becomes tapped, it deals 1 |the battlefield, you may |Strand: Search your library
|
||||
|damage to you. {T}: Add one |discard a land card instead. |for a Plains or Island card,
|
||||
|mana of any color. |If you do, put Mox Diamond |put it onto the battlefield,
|
||||
| |onto the battlefield. If you |then shuffle.
|
||||
| |don't, put it into its |
|
||||
| |owner's graveyard. {T}: Add |
|
||||
| |one mana of any color. |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|Temple Garden (Land Forest |Lord Skitter, Sewer King |Bloodstained Mire (Land) >>
|
||||
|Plains) >> ({T}: Add {G} or |{2}{B} (Legendary Creature |{T}, Pay 1 life, Sacrifice
|
||||
|{W}.) As Temple Garden enters |Rat Noble) >> Whenever |Bloodstained Mire: Search
|
||||
|the battlefield, you may pay |another Rat enters the |your library for a Swamp or
|
||||
|2 life. If you don't, it |battlefield under your |Mountain card, put it onto
|
||||
|enters the battlefield |control, exile up to one |the battlefield, then
|
||||
|tapped. |target card from an |shuffle.
|
||||
| |opponent's graveyard. At the |
|
||||
| |beginning of combat on your |
|
||||
| |turn, create a 1/1 black Rat |
|
||||
| |creature token with "This |
|
||||
| |creature can't block." (3/3) |
|
||||
| | |
|
||||
|Ayara's Oathsworn {1}{B} | |
|
||||
|(Creature Human Knight) >> | |
|
||||
|Menace Whenever Ayara's | |
|
||||
|Oathsworn deals combat damage | |
|
||||
|to a player, if it has fewer | |
|
||||
|than four +1/+1 counters on | |
|
||||
|it, put a +1/+1 counter on | |
|
||||
|it. Then if it has exactly | |
|
||||
|four +1/+1 counters on it, | |
|
||||
|search your library for a | |
|
||||
|card, put it into your hand, | |
|
||||
|then shuffle. (2/2) | |
|
||||
| | |
|
||||
```
|
||||
|
|
File diff suppressed because it is too large
Load Diff
176
src/print.zig
176
src/print.zig
|
@ -1,6 +1,11 @@
|
|||
//TODO:
|
||||
//TODO: re-implement sorting
|
||||
//c library usage based on https://medium.com/@eddo2626/lets-learn-zig-4-using-c-libraries-in-zig-5fcc3206f0dc
|
||||
//
|
||||
const std = @import("std");
|
||||
const clap = @import("clap");
|
||||
const c = @cImport({
|
||||
@cInclude("pdfgen.h");
|
||||
});
|
||||
const print = std.debug.print;
|
||||
const io = std.io;
|
||||
const fs = std.fs;
|
||||
|
@ -21,7 +26,9 @@ const Card = struct {
|
|||
card_faces: ?[]Card = null, //array of cards
|
||||
};
|
||||
|
||||
const TextCard = struct { lines: [][]const u8 = undefined };
|
||||
const TextCard = struct {
|
||||
lines: [][]const u8 = undefined,
|
||||
};
|
||||
|
||||
const PandocOptions = &[_][]const u8{ "pandoc", "out.md", "-o", "out.pdf", "--pdf-engine", "xelatex", "-V", "mainfont:Liberation Mono", "-V", "geometry:margin=0cm" };
|
||||
|
||||
|
@ -47,7 +54,17 @@ test "Check constants" {
|
|||
try expect(pageWidth == markdownFormatString.len);
|
||||
}
|
||||
|
||||
const pdf_info = struct { .creator = "My software", .producer = "My software", .title = "My document", .author = "My name", .subject = "My subject", .date = "Today" };
|
||||
|
||||
pub fn main() !void {
|
||||
const pdf_doc: *c.pdf = c.pdf_create(c.PDF_A4_WIDTH, c.PDF_A4_HEIGHT, &pdf_info);
|
||||
c.pdf_set_font(pdf_doc, "Times-Roman");
|
||||
c.pdf_append_page(pdf_doc);
|
||||
c.pdf_add_text(pdf_doc, c.NULL, "This is text", 12, 50, 20, c.PDF_BLACK);
|
||||
c.pdf_add_line(pdf_doc, c.NULL, 50, 24, 150, 24, 3, c.PDF_BLACK);
|
||||
c.pdf_save(pdf_doc, "output.pdf");
|
||||
c.pdf_destroy(pdf_doc);
|
||||
|
||||
var args = try std.process.argsWithAllocator(std.heap.page_allocator);
|
||||
|
||||
//TODO: properly handle program arguments
|
||||
|
@ -62,8 +79,8 @@ pub fn main() !void {
|
|||
const allocator = arena.allocator();
|
||||
|
||||
const oracleFile = try cwd.openFile(oracleFileName, .{});
|
||||
// var jsonReader = json.reader(allocator, oracleFile.reader());
|
||||
// const parsedJson = try json.parseFromTokenSource([]Card, allocator, &jsonReader, .{.ignore_unknown_fields = true});
|
||||
var jsonReader = json.reader(allocator, oracleFile.reader());
|
||||
const parsedJson = try json.parseFromTokenSource([]Card, allocator, &jsonReader, .{ .ignore_unknown_fields = true });
|
||||
|
||||
var cardNames = std.ArrayList([]const u8).init(allocator);
|
||||
const listReader = (try cwd.openFile(listFileName, .{})).reader();
|
||||
|
@ -77,133 +94,76 @@ pub fn main() !void {
|
|||
else => return err,
|
||||
}
|
||||
|
||||
var depth: u32 = 0;
|
||||
var cardString = std.ArrayList(u8).init(allocator);
|
||||
var cards = std.StringHashMap(Card).init(allocator);
|
||||
while (oracleFile.reader().readByte()) |char| {
|
||||
if (char == '{') depth += 1;
|
||||
if (depth != 0) try cardString.append(char);
|
||||
if (char == '}') {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
// print("{s}\n", .{cardString.items});
|
||||
const parsedCard = try std.json.parseFromSlice(Card, allocator, cardString.items, .{ .ignore_unknown_fields = true });
|
||||
var lookupTimer = try std.time.Timer.start();
|
||||
for (cardNames.items, 0..) |cardName, i| {
|
||||
if (std.mem.eql(u8, parsedCard.value.name, cardName)) {
|
||||
// print("{s}\n", .{parsedCard.value.name});
|
||||
try cards.putNoClobber(try allocator.dupe(u8, parsedCard.value.name), (try allocator.dupe(Card, &[_]Card{parsedCard.value}))[0]);
|
||||
_ = cardNames.orderedRemove(i);
|
||||
}
|
||||
}
|
||||
cardString.clearAndFree();
|
||||
print("took {d:.10}\n", .{lookupTimer.read() / (1000 * 1000 * 1000)});
|
||||
var cards = std.StringArrayHashMap(TextCard).init(allocator);
|
||||
for (parsedJson.value) |cardObj| {
|
||||
for (cardNames.items, 0..) |cardName, i| {
|
||||
if (std.mem.eql(u8, cardName, cardObj.name)) {
|
||||
const printableCard = try card(cardObj, allocator, false);
|
||||
try cards.put(cardObj.name, printableCard);
|
||||
_ = cardNames.orderedRemove(i);
|
||||
}
|
||||
}
|
||||
} else |e| {
|
||||
switch (e) {
|
||||
error.EndOfStream => {},
|
||||
else => {
|
||||
return e;
|
||||
},
|
||||
}
|
||||
}
|
||||
var cardIterator = cards.valueIterator();
|
||||
while (cardIterator.next()) |cardObj| {
|
||||
print("{any}\n", .{cardObj});
|
||||
}
|
||||
|
||||
// var allCards = std.StringHashMap(Card).init(allocator);
|
||||
// for(parsedJson.value) |cardObj| {
|
||||
// try allCards.put(cardObj.name, cardObj);
|
||||
// }
|
||||
// parsedJson.deinit();
|
||||
//
|
||||
|
||||
// var allPrinted = std.ArrayList(u8).init(allocator);
|
||||
|
||||
// var cards = std.ArrayList(TextCard).init(allocator);
|
||||
// // var pages = std.ArrayList(page).init(allocator);
|
||||
// while (listReader.streamUntilDelimiter(line.writer(), '\n', null)) {
|
||||
// defer line.clearRetainingCapacity();
|
||||
// const cardName = line.items[indexOf(u8, line.items, " ").? + 1..indexOf(u8, line.items, "(").? - 1];
|
||||
// assert(cardName.len > 0);
|
||||
// const cardText = try card(allCards.get(cardName).?);
|
||||
// try cards.append(cardText);
|
||||
// } else |err| switch(err) {
|
||||
// error.EndOfStream => {},
|
||||
// else => return err,
|
||||
// }
|
||||
//
|
||||
// for(cards.items) |cardText| {
|
||||
// std.debug.print("{any}\n", .{cardText});
|
||||
// }
|
||||
//sort the cards
|
||||
// std.mem.sort(TextCard, cards.items, {}, compareTwo);
|
||||
var allPrinted = std.ArrayList(u8).init(allocator);
|
||||
|
||||
//TODO (fixme): absolutely GARBAGE hack to get pandoc to preserve whitespace
|
||||
// try allPrinted.appendSlice(markdownFormatString);
|
||||
|
||||
// var rowToPrint = std.ArrayList(TextCard).init(allocator);
|
||||
// for(cards.items) |cardObj| {
|
||||
// try rowToPrint.append(cardObj);
|
||||
// std.debug.print("{any}\n", .{cardObj});
|
||||
// if(rowToPrint.items.len >= 3) {
|
||||
// try cardRow.print(allocator, rowToPrint.items, &allPrinted);
|
||||
// rowToPrint.clearAndFree();
|
||||
// }
|
||||
// // } else {
|
||||
// try cardRow.print(allocator, rowToPrint.items, &allPrinted);
|
||||
// try allPrinted.appendSlice(markdownFormatString);
|
||||
// std.debug.print("{s}", .{allPrinted.items});
|
||||
// try cwd.writeFile(.{.sub_path = "out.md", .data = allPrinted.items});
|
||||
// rowToPrint.clearAndFree();
|
||||
// var pandocProcess = std.process.Child.init(PandocOptions, allocator);
|
||||
// _ = try pandocProcess.spawnAndWait();
|
||||
// }
|
||||
}
|
||||
|
||||
fn compareTwo(_: void, a: TextCard, b: TextCard) bool {
|
||||
return a.lines.len < b.lines.len;
|
||||
try allPrinted.appendSlice(markdownFormatString);
|
||||
var rowToPrint = std.ArrayList(TextCard).init(allocator);
|
||||
// var cardIterator = cards.valueIterator();
|
||||
for (cards.values()) |cardText| {
|
||||
try rowToPrint.append(cardText);
|
||||
if (rowToPrint.items.len >= 3) {
|
||||
try cardRow.print(allocator, rowToPrint.items, &allPrinted);
|
||||
rowToPrint.clearAndFree();
|
||||
}
|
||||
} else {
|
||||
try cardRow.print(allocator, rowToPrint.items, &allPrinted);
|
||||
try allPrinted.appendSlice(markdownFormatString);
|
||||
std.debug.print("{s}", .{allPrinted.items});
|
||||
try cwd.writeFile(.{ .sub_path = "out.md", .data = allPrinted.items });
|
||||
rowToPrint.clearAndFree();
|
||||
var pandocProcess = std.process.Child.init(PandocOptions, allocator);
|
||||
_ = try pandocProcess.spawnAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
fn card(
|
||||
cardObj: Card,
|
||||
allocator: std.mem.Allocator,
|
||||
isFace: bool,
|
||||
) !TextCard {
|
||||
var buffer: [cardHeight * 1024]u8 = undefined;
|
||||
var cardTextAllocator = std.heap.FixedBufferAllocator.init(&buffer);
|
||||
defer cardTextAllocator.reset();
|
||||
const cta = cardTextAllocator.allocator();
|
||||
var cardText = std.ArrayList([]const u8).init(cta);
|
||||
var cardText = std.ArrayList([]const u8).init(allocator);
|
||||
|
||||
var fullUnformattedText = std.ArrayList(u8).init(cta);
|
||||
try fullUnformattedText.appendSlice(cardObj.name);
|
||||
try fullUnformattedText.appendSlice(try std.mem.concat(cta, u8, &[_][]const u8{
|
||||
if (cardObj.mana_cost.len > 0) " " else "",
|
||||
cardObj.mana_cost,
|
||||
" (",
|
||||
cardObj.type_line,
|
||||
") >> ",
|
||||
var fullUnformattedText = std.ArrayList(u8).init(allocator);
|
||||
if (!isFace) {
|
||||
try fullUnformattedText.appendSlice(try std.mem.concat(allocator, u8, &[_][]const u8{
|
||||
cardObj.name,
|
||||
if (cardObj.mana_cost.len > 0) " " else "",
|
||||
cardObj.mana_cost,
|
||||
" (",
|
||||
cardObj.type_line,
|
||||
") >> ",
|
||||
}));
|
||||
}
|
||||
try fullUnformattedText.appendSlice(try std.mem.concat(allocator, u8, &[_][]const u8{
|
||||
cardObj.oracle_text,
|
||||
if (cardObj.power.len > 0) " >> " else "",
|
||||
if (cardObj.power.len > 0) " (" else "",
|
||||
cardObj.power,
|
||||
if (cardObj.power.len > 0) "/" else "",
|
||||
cardObj.toughness,
|
||||
if (cardObj.power.len > 0) ") " else "",
|
||||
}));
|
||||
|
||||
if (cardObj.card_faces) |faces| {
|
||||
for (faces, 0..) |face, idx| {
|
||||
try fullUnformattedText.appendSlice(face.oracle_text);
|
||||
if (face.power.len > 0) try fullUnformattedText.appendSlice(" ");
|
||||
try fullUnformattedText.appendSlice(face.power);
|
||||
if (face.power.len > 0) try fullUnformattedText.appendSlice("/");
|
||||
try fullUnformattedText.appendSlice(face.toughness);
|
||||
const faceText = (try card(face, allocator, true)).lines;
|
||||
try fullUnformattedText.appendSlice(std.mem.trim(u8, try std.mem.join(allocator, " ", faceText), "\n"));
|
||||
if (idx == 0) try fullUnformattedText.appendSlice(" // ");
|
||||
}
|
||||
}
|
||||
|
||||
var line = std.ArrayList(u8).init(cta);
|
||||
var word = std.ArrayList(u8).init(cta);
|
||||
var line = std.ArrayList(u8).init(allocator);
|
||||
var word = std.ArrayList(u8).init(allocator);
|
||||
|
||||
for (fullUnformattedText.items) |char| {
|
||||
try switch (char) {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
const std = @import("std");
|
||||
const cwd = std.fs.cwd;
|
||||
const json = std.json;
|
||||
const print = std.debug.print;
|
||||
const oracleFileName = "oracle-cards-20240701090158.json";
|
||||
|
||||
const Card = struct {
|
||||
name: []const u8 = "", //string
|
||||
mana_cost: []const u8 = "", //string
|
||||
cmc: f32 = 0, //technically a float? but I think we can always cast safely cast. EDIT: NOPE
|
||||
type_line: []const u8 = "", //string
|
||||
oracle_text: []const u8 = "", //string
|
||||
power: []const u8 = "", //coerced to string
|
||||
toughness: []const u8 = "", //coerced to string
|
||||
card_faces: ?[]Card = null, //array of cards
|
||||
};
|
||||
|
||||
const testCardName = "Raffine, Scheming Seer";
|
||||
|
||||
const cardList = std.MultiArrayList(Card);
|
||||
pub fn main() !void {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = arena.allocator();
|
||||
const oracleFile = try cwd().openFile(oracleFileName, .{});
|
||||
const fileReader = oracleFile.reader();
|
||||
var bufferedReader = std.io.bufferedReader(fileReader);
|
||||
const readerReader = bufferedReader.reader();
|
||||
// var jsonReader = json.reader(allocator, oracleFile.reader());
|
||||
// var fields = std.ArrayList(Field).init(allocator);
|
||||
// var isVal = false;
|
||||
// var cards = std.StringHashMap(*StringHashMap);
|
||||
// var currentCard = std.ArrayList(std.json.Token).init(allocator);
|
||||
var depth: u32 = 0;
|
||||
var cardString = std.ArrayList(u8).init(allocator);
|
||||
var idx: u32 = 0;
|
||||
while (readerReader.readByte()) |char| {
|
||||
if (char == '{') depth += 1;
|
||||
if (depth != 0) try cardString.append(char);
|
||||
if (char == '}') {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
// print("{s}\n", .{cardString.items});
|
||||
const parsedCard = try std.json.parseFromSlice(Card, allocator, cardString.items, .{ .ignore_unknown_fields = true });
|
||||
print("{s}\n", .{parsedCard.value.name});
|
||||
cardString.clearAndFree();
|
||||
}
|
||||
}
|
||||
idx += 1;
|
||||
} else |e| {
|
||||
return e;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue