diff --git a/data/magic-spoiler.mse-export-template/export-template b/data/magic-spoiler.mse-export-template/export-template
index a350d9c8..e3e97c99 100644
--- a/data/magic-spoiler.mse-export-template/export-template
+++ b/data/magic-spoiler.mse-export-template/export-template
@@ -147,7 +147,7 @@ script:
}"
}
write_group := {
- cards := filter_list(set.cards, filter: { sort_index(card:input) == code } )
+ cards := filter_list(set.cards, filter: { contains(match:sort_index(card:input), code } )
count := number_of_items(in:cards)
if count > 0 then
"
{title} ({count} {if count == 1 then "card" else "cards"})
" +
@@ -194,16 +194,17 @@ script:
{ to_html(set.description) }
{ if options.grouping == "group by color" then
# Codes as by sort_index
- write_group(title: "White", code:"A") +
- write_group(title: "Blue", code:"B") +
- write_group(title: "Black", code:"C") +
- write_group(title: "Red", code:"D") +
- write_group(title: "Green", code:"E") +
- write_group(title: "Multicolor", code:"F") +
- write_group(title: "Hybrids", code:"G") +
- write_group(title: "Colorless", code:"I") +
- write_group(title: "Non-basic lands", code:"J") +
- write_group(title: "Basic lands", code:"K")
+ write_group(title: "White", code:"A") +
+ write_group(title: "Blue", code:"B") +
+ write_group(title: "Black", code:"C") +
+ write_group(title: "Red", code:"D") +
+ write_group(title: "Green", code:"E") +
+ write_group(title: "Multicolor", code:"F") +
+ write_group(title: "Hybrids", code:"G") +
+ write_group(title: "Multicolor split cards", code:"H") +
+ write_group(title: "Colorless", code:"I") +
+ write_group(title: "Non-basic lands", code:"K") +
+ write_group(title: "Basic lands", code:"LMNOPQ")
else
write_cards(cards: set.cards)
}
diff --git a/data/magic.mse-game/game b/data/magic.mse-game/game
index 74493d96..658cdee2 100644
--- a/data/magic.mse-game/game
+++ b/data/magic.mse-game/game
@@ -1,8 +1,8 @@
-mse version: 0.3.4
+mse version: 0.3.5
short name: Magic
full name: Magic the Gathering
icon: card-back.png
-version: 2007-07-01
+version: 2007-08-28
position hint: 01
############################################################## Functions & filters
@@ -126,7 +126,8 @@ init script:
}
# The color of a card
- is_creature := match_rule(match: "(?i)Creature|Tribal")
+ is_creature := match_rule(match: "(?i)Creature")
+ is_tribal := match_rule(match: "(?i)Tribal")
is_artifact := match_rule(match: "(?i)Artifact")
is_land := match_rule(match: "(?i)Land")
is_enchantment := match_rule(match: "(?i)Enchantment")
@@ -176,17 +177,17 @@ init script:
card_color := card.card_color
casting_cost := card.casting_cost
if card.casting_cost_2 != "" and
- card_color != card.card_color_2 then "H" # multicolor splits
+ card_color != card.card_color_2 then "H" # multicolor splits
else if chosen(choice: "land", card_color) then (
# land
- if card.rarity != "basic land" then "K" # nonbasic land
+ if card.rarity != "basic land" then "K" # nonbasic land
else (
if contains(card.name, match:"Plains") then "M"
else if contains(card.name, match:"Island") then "N"
else if contains(card.name, match:"Swamp") then "O"
else if contains(card.name, match:"Mountain") then "P"
else if contains(card.name, match:"Forest") then "Q"
- else "L" # other basic land
+ else "L" # other basic land
)
) else if is_null_cost(casting_cost) then (
# no casting cost; use frame
@@ -368,24 +369,31 @@ init script:
type_over_type +
{ "{input}" }
- space_to_wlclass := replace_rule(match:" +", replace:" ")
+ space_to_wltags := replace_rule(match:"( +| )",
+ replace:{"{_1}"})
sub_type_filter :=
tag_remove_rule(tag: ""
- else (
- first := only_first(input);
- next := trim(only_next(input));
- if next != "" then next := next + " ";
- "{first} " +
- "" + space_to_wlclass(next) + ""
- )
+ replace_rule(match: " $", replace: "") + # remove trailing soft space
+ tag_remove_rule(tag: " "
+ else first := first + " "
+ input := next
+ ) else (
+ first := ""
)
- else if is_land(type) then "{ input}"
- else if is_artifact(type) then "{ input}"
- else if is_enchantment(type) then "{input}"
- else if is_spell(type) then "{ input}"
- else input
+ if list_type != "" then (
+ if input != "" then input := input + " " # Add a new box at the end
+ first + "{ space_to_wltags(input) }"
+ ) else first + input
}
# all sub types, for word list
@@ -398,7 +406,7 @@ init script:
}
all_races := {
for each card in set do
- if contains(card.super_type, match:"Creature") then
+ if is_creature(card.super_type) or is_tribal(card.super_type) then
"," + only_first(to_text(card.sub_type))
}
all_classes := {
@@ -1247,7 +1255,9 @@ word list:
script: all_classes()
line below: true
word: Cleric
+ word: Druid
word: Lord
+ word: Shaman
word: Soldier
word: Warrior
word:
diff --git a/doc/type/tagged_string.txt b/doc/type/tagged_string.txt
index e1ae225b..fbc569b0 100644
--- a/doc/type/tagged_string.txt
+++ b/doc/type/tagged_string.txt
@@ -37,6 +37,7 @@ This is written as the character with code 1 in files.
Inserting this tag manually will confuse that function!
This tag can never be selected, and its contents can not be edited.
| @""@ Like @""@, only hidden. This is inserted by [[fun:combined_editor]]
+| @""@ Text who's width is ignored for alignment, similair to @""@, but not a separator.
| @""@ Indicate that the text inside the tag should be selected from a [[type:word list]].
The ? must be the name of a word list in the game.
| any other tag Other tags are ignored.
diff --git a/src/gui/value/text.cpp b/src/gui/value/text.cpp
index 29a24e0a..ad646d30 100644
--- a/src/gui/value/text.cpp
+++ b/src/gui/value/text.cpp
@@ -1297,7 +1297,7 @@ void TextValueEditor::clearWordListIndicators(RotatedDC& dc) {
}
// restore background
if (wl->behind.Ok()) {
- dc.DrawBitmap(wl->behind, wl->rect.topRight() + RealSize(0,-1));
+ dc.DrawPreRotatedBitmap(wl->behind, wl->rect.topRight() + RealSize(0,-1));
}
}
}
diff --git a/src/render/text/element.cpp b/src/render/text/element.cpp
index 59c8fabc..5a6ff19f 100644
--- a/src/render/text/element.cpp
+++ b/src/render/text/element.cpp
@@ -33,12 +33,12 @@ void TextElements::getCharInfo(RotatedDC& dc, double scale, size_t start, size_t
FOR_EACH_CONST(e, elements) {
// characters before this element, after the previous
while (out.size() < e->start) {
- out.push_back(CharInfo(RealSize(0,0), BREAK_NO));
+ out.push_back(CharInfo());
}
e->getCharInfo(dc, scale, out);
}
while (out.size() < end) {
- out.push_back(CharInfo(RealSize(0,0), BREAK_NO));
+ out.push_back(CharInfo());
}
}
@@ -100,6 +100,8 @@ struct TextElementsFromString {
else if (is_substr(text, tag_start, _(" {
// ----------------------------------------------------------------------------- : TextElements
/// A list of text elements
-class TextElements : public vector {
+class TextElements {
public:
/// Draw all the elements (as need to show the range start..end)
void draw (RotatedDC& dc, double scale, const RealRect& rect, const double* xs, DrawWhat what, size_t start, size_t end) const;
diff --git a/src/render/text/font.cpp b/src/render/text/font.cpp
index 097c6898..2f7233a8 100644
--- a/src/render/text/font.cpp
+++ b/src/render/text/font.cpp
@@ -37,13 +37,15 @@ void FontTextElement::getCharInfo(RotatedDC& dc, double scale, vector&
for (size_t i = start ; i < end ; ++i) {
Char c = content.GetChar(i - this->start);
if (c == _('\n')) {
- out.push_back(CharInfo(RealSize(0, dc.GetCharHeight()), break_style));
+ out.push_back(CharInfo(RealSize(0, dc.GetCharHeight()), break_style, draw_as == DRAW_ACTIVE));
line_start = i + 1;
prev_width = 0;
} else {
RealSize s = dc.GetTextExtent(content.substr(line_start - this->start, i - line_start + 1));
- out.push_back(CharInfo(RealSize(s.width - prev_width, s.height),
- c == _(' ') ? BREAK_SPACE : BREAK_MAYBE
+ out.push_back(CharInfo(
+ RealSize(s.width - prev_width, s.height),
+ c == _(' ') ? BREAK_SPACE : BREAK_MAYBE,
+ draw_as == DRAW_ACTIVE // from tag
));
prev_width = s.width;
}
diff --git a/src/render/text/viewer.cpp b/src/render/text/viewer.cpp
index 4b4d1994..a3206699 100644
--- a/src/render/text/viewer.cpp
+++ b/src/render/text/viewer.cpp
@@ -16,6 +16,7 @@ DECLARE_TYPEOF_COLLECTION(double);
struct TextViewer::Line {
size_t start; ///< Index of the first character in this line
+ size_t end_or_soft; ///< Index just beyond the last non-soft character
vector positions; ///< x position of each character in this line, gives the number of characters + 1, never empty
double top; ///< y position of (the top of) this line
double line_height; ///< The height of this line in pixels
@@ -23,13 +24,13 @@ struct TextViewer::Line {
//% Alignment alignment; ///< Alignment of this line
Line()
- : start(0), top(0), line_height(0), break_after(BREAK_NO)
+ : start(0), end_or_soft(0), top(0), line_height(0), break_after(BREAK_NO)
{}
/// The position (just beyond) the bottom of this line
double bottom() const { return top + line_height; }
/// The width of this line
- double width() const { return positions.back() - positions.front(); }
+ double width() const { return positions[end_or_soft-start] - positions.front(); }
/// Index just beyond the last character on this line
size_t end() const { return start + positions.size() - 1; }
/// Find the index of the character at the given position on this line
@@ -158,7 +159,7 @@ bool TextViewer::prepare(RotatedDC& dc, const String& text, TextStyle& style, Co
}
}
void TextViewer::reset(bool related) {
- elements.clear();
+ elements.elements.clear();
lines.clear();
if (!related) scale = 1.0;
}
@@ -169,6 +170,7 @@ bool TextViewer::prepared() const {
// ----------------------------------------------------------------------------- : Positions
const TextViewer::Line& TextViewer::findLine(size_t index) const {
+ assert(!lines.empty());
FOR_EACH_CONST(l, lines) {
if (l.end() >= index) return l;
}
@@ -295,6 +297,7 @@ void TextViewer::scrollBy(double delta) {
}
bool TextViewer::ensureVisible(double height, size_t char_id) {
+ if (lines.empty()) return true;
const Line& line = findLine(char_id);
if (line.top < 0) {
// scroll up
@@ -511,6 +514,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars,
// The word we are currently reading
RealSize word_size;
vector positions_word; // positios for this word
+ size_t word_end_or_soft = 0;
size_t word_start = 0;
// For each character ...
for(size_t i = 0 ; i < chars.size() ; ++i) {
@@ -539,6 +543,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars,
word_size = add_horizontal(word_size, c.size);
}
positions_word.push_back(word_size.width);
+ if (!c.soft) word_end_or_soft = i + 1;
// Did the word become too long?
if (style.field().multi_line && !break_now) {
double max_width = lineRight(dc, style, line.top);
@@ -565,11 +570,13 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars,
FOR_EACH(p, positions_word) {
line.positions.push_back(line_size.width + p);
}
- // add size; next word
+ if (word_end_or_soft != 0) line.end_or_soft = word_end_or_soft;
line_size = add_horizontal(line_size, word_size);
+ // next word
word_size = RealSize(0, 0);
word_start = i + 1;
positions_word.clear();
+ word_end_or_soft = 0;
}
// Breaking (ending the current line)
if (break_now) {
@@ -583,10 +590,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars,
} else {
line.line_height = line_size.height;
}
-// // too low?
-// if (stop_if_too_long && line.bottom() > dc.getInternalSize().height - style.padding_bottom) {
-// return false;
-// }
+ line.end_or_soft = max(line.start, min(line.end_or_soft, line.end()));
// push
lines.push_back(line);
// reset line object for next line
@@ -612,6 +616,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars,
FOR_EACH(p, positions_word) {
line.positions.push_back(line_size.width + p);
}
+ if (word_end_or_soft != 0) line.end_or_soft = word_end_or_soft;
line_size = add_horizontal(line_size, word_size);
// the last line
if (line_size.height < 0.01 && !lines.empty()) {
@@ -619,6 +624,7 @@ bool TextViewer::prepareLinesScale(RotatedDC& dc, const vector& chars,
} else {
line.line_height = line_size.height;
}
+ line.end_or_soft = max(line.start, min(line.end_or_soft, line.end()));
lines.push_back(line);
// does it fit vertically?
return lines.empty() ||
@@ -688,14 +694,14 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const
FOR_EACH(l, lines) {
l.top += vdelta;
// amount to shift all characters horizontally
- double width = l.positions.back();
+ double width = l.positions[l.end_or_soft - l.start];
if ((style.alignment & ALIGN_JUSTIFY) ||
(style.alignment & ALIGN_JUSTIFY_OVERFLOW && width > s.width)) {
// justify text
justifying = true;
- double hdelta = s.width - width; // amount of space to distribute
- int count = (int)l.positions.size() - 1; // distribute it among this many characters
- if (count == 0) count = 1; // prevent div by 0
+ double hdelta = s.width - width; // amount of space to distribute
+ int count = (int)(l.end_or_soft - l.start); // distribute it among this many characters
+ if (count <= 0) count = 1; // prevent div by 0
int i = 0;
FOR_EACH(c, l.positions) {
c += hdelta * i++ / count;
@@ -703,16 +709,16 @@ void TextViewer::alignLines(RotatedDC& dc, const vector& chars, const
} else if (style.alignment & ALIGN_JUSTIFY_WORDS) {
// justify text, by words
justifying = true;
- double hdelta = s.width - width; // amount of space to distribute
- int count = 0; // distribute it among this many words
- for (size_t k = l.start + 1 ; k < l.end() - 1 ; ++k) {
+ double hdelta = s.width - width; // amount of space to distribute
+ int count = 0; // distribute it among this many words
+ for (size_t k = l.start + 1 ; k < l.end_or_soft - 1 ; ++k) {
if (chars[k].break_after == BREAK_SPACE) ++count;
}
- if (count == 0) count = 1; // prevent div by 0
+ if (count == 0) count = 1; // prevent div by 0
int i = 0; size_t j = l.start;
FOR_EACH(c, l.positions) {
c += hdelta * i / count;
- if (j < l.end() && chars[j++].break_after == BREAK_SPACE) i++;
+ if (j < l.end_or_soft && chars[j++].break_after == BREAK_SPACE) i++;
}
} else {
// simple alignment
diff --git a/src/script/parser.cpp b/src/script/parser.cpp
index eea9bf46..7ff312d4 100644
--- a/src/script/parser.cpp
+++ b/src/script/parser.cpp
@@ -190,7 +190,7 @@ void TokenIterator::readToken() {
filename = include_file;
InputStreamP is = packages.openFileFromPackage(include_file);
input = read_utf8_line(*is, true, true);
- } else if (isAlpha(c)) {
+ } else if (isAlpha(c) || c == _('_')) {
// name
size_t start = pos - 1;
while (pos < input.size() && isAlnum_(input.GetChar(pos))) ++pos;
diff --git a/src/util/rotation.cpp b/src/util/rotation.cpp
index 9a6ef6d0..dadee2a0 100644
--- a/src/util/rotation.cpp
+++ b/src/util/rotation.cpp
@@ -153,7 +153,7 @@ void RotatedDC::DrawText (const String& text, const RealPoint& pos, int blur_ra
void RotatedDC::DrawBitmap(const Bitmap& bitmap, const RealPoint& pos) {
if (angle == 0) {
RealPoint p_ext = tr(pos);
- dc.DrawBitmap(bitmap, (int) p_ext.x, (int) p_ext.y, true);
+ dc.DrawBitmap(bitmap, to_int(p_ext.x), to_int(p_ext.y), true);
} else {
DrawImage(bitmap.ConvertToImage(), pos);
}
@@ -161,15 +161,15 @@ void RotatedDC::DrawBitmap(const Bitmap& bitmap, const RealPoint& pos) {
void RotatedDC::DrawImage (const Image& image, const RealPoint& pos, ImageCombine combine, int angle) {
Image rotated = rotate_image(image, angle + this->angle);
wxRect r = trNoNegNoZoom(RealRect(pos, RealSize(image)));
- draw_combine_image(dc, r.x, r.y, rotated, combine);
+ draw_combine_image(dc, to_int(r.x), to_int(r.y), rotated, combine);
}
void RotatedDC::DrawPreRotatedBitmap(const Bitmap& bitmap, const RealPoint& pos) {
RealPoint p_ext = tr(pos) - RealSize(revX()?bitmap.GetWidth():0, revY()?bitmap.GetHeight():0);
- dc.DrawBitmap(bitmap, (int) p_ext.x, (int) p_ext.y, true);
+ dc.DrawBitmap(bitmap, to_int(p_ext.x), to_int(p_ext.y), true);
}
void RotatedDC::DrawPreRotatedImage (const Image& image, const RealPoint& pos, ImageCombine combine) {
RealPoint p_ext = tr(pos) - RealSize(revX()?image.GetWidth():0, revY()?image.GetHeight():0);
- draw_combine_image(dc, p_ext.x, p_ext.y, image, combine);
+ draw_combine_image(dc, to_int(p_ext.x), to_int(p_ext.y), image, combine);
}
void RotatedDC::DrawLine (const RealPoint& p1, const RealPoint& p2) {
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 38def722..f6cdb300 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -166,7 +166,7 @@ String cannocial_name_form(const String& str) {
bool leading = true;
FOR_EACH_CONST(c, str) {
if ((c == _('_') || c == _(' '))) {
- if (!leading) ret += _(' ');
+ ret += leading ? c : _(' ');
} else {
ret += c;
leading = false;