diff --git a/data/magic.mse-game/game b/data/magic.mse-game/game
index df2df3e9..bf83e53f 100644
--- a/data/magic.mse-game/game
+++ b/data/magic.mse-game/game
@@ -156,7 +156,7 @@ init script:
# step 2 : reminder text for keywords
expand_keywords_rule(
default_expand: { contains(match:mode, set.automatic_reminder_text, match:mode) },
- combine: { "{keyword} ({reminder})" }
+ combine: { "{keyword} ({process_english_hints(reminder)})" }
) +
# step 3a : expand shortcut words ~ and CARDNAME
replace_rule(
@@ -1035,8 +1035,7 @@ keyword:
reminder: You may play this card for its madness cost at the time you discard it.
keyword:
keyword: Threshold
- separator: dash [ - ]
- parameter: action
+ match: Threshold - action
mode: expert
reminder: You have threshold as long as seven or more cards are in your graveyard.
keyword:
@@ -1053,10 +1052,9 @@ keyword:
reminder: You may play this face down as a 2/2 creature for [3]. Turn it face up any time for its morph cost.
keyword:
keyword: Amplify
- separator: whitespace [ ]
- parameter: number (a, two, ...)
+ match: Amplify number
mode: expert
- reminder: As this card comes into play, put {param1} +1/+1 counter(s) on it for each creature that shares a type with this that you reveal in your hand.
+ reminder: As this card comes into play, put {english_number(param1)} +1/+1 counter(s) on it for each creature that shares a type with this that you reveal in your hand.
keyword:
keyword: Double strike
mode: expert
@@ -1101,25 +1099,18 @@ keyword:
reminder: This comes into play with {param1} +1/+1 counter(s) on it. When it’s put into a graveyard, you may put its +1/+1 counters on target artifact creature.
keyword:
keyword: Scry
- separator: whitespace [ ]
- parameter: number (, two, ...)
+ match: Scry number
mode: expert
- reminder: Look at the top {param1} card(s) of your library. Put any number of them on the bottom of your library in any order and the rest on top of your library in any order.
+ reminder: Look at the top {english_number_multiple(param1)} card(s) of your library. Put any number of them on the bottom of your library in any order and the rest on top of your library in any order.
keyword:
keyword: Sunburst
mode: expert
reminder: This comes into play with a +1/+1 counter on it for each color of mana used to pay its cost. If it is not a creature, use charge counters instead.
-#keyword:
+keyword:
keyword: Splice
match: Splice onto name cost
mode: expert
reminder: As you play a {param1} spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card’s effects to that spell.
-keyword:
- keyword: Splice onto Arcane
- separator: whitespace [ ]
- parameter: cost
- mode: expert
- reminder: As you play an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card’s effects to that spell.
keyword:
keyword: Offering
separator: dash [ - ]
@@ -1203,16 +1194,15 @@ keyword:
reminder: This creature can’t be blocked, targeted, dealt damage, or enchanted by anything {param1}.
keyword:
keyword: Dredge
- separator: whitespace [ ]
- parameter: number (one, two, ...)
+ match: Dredge number
mode: expert
- reminder: As long as you have at least {param1} card(s) in your library, if you would draw a card, you may instead put exactly {param1} card(s) from the top of your library into your graveyard and return this card from your graveyard to your hand.
+ reminder: As long as you have at least {english_number(param1)} card(s) in your library, if you would draw a card, you may instead put exactly {param1} card(s) from the top of your library into your graveyard and return this card from your graveyard to your hand.
keyword:
keyword: Graft
separator: whitespace [ ]
- parameter: number (a, two, ...)
+ parameter: number
mode: expert
- reminder: This creature comes into play with {param1} +1/+1 counter(s) on it. Whenever another creature comes into play, you may move a +1/+1 counter from this creature onto it.
+ reminder: This creature comes into play with {english_number(param1)} +1/+1 counter(s) on it. Whenever another creature comes into play, you may move a +1/+1 counter from this creature onto it.
keyword:
keyword: Forecast
separator: whitespace [ ]
diff --git a/src/data/keyword.cpp b/src/data/keyword.cpp
index e4e60364..3932f589 100644
--- a/src/data/keyword.cpp
+++ b/src/data/keyword.cpp
@@ -405,8 +405,12 @@ String KeywordDatabase::expand(const String& text,
ctx.setVariable(_("input"), to_script(part));
param = kwp.script.invoke(ctx)->toString();
}
- part = _("") + part + _("");
- param = _("") + param + _("");
+ String param_type = replace_all(replace_all(replace_all(kwp.name,
+ _("("),_("-")),
+ _(")"),_("-")),
+ _(" "),_("-"));
+ part = _("") + part + _("");
+ param = _("") + param + _("");
ctx.setVariable(String(_("param")) << (int)(j/2), to_script(param));
}
total += part;
diff --git a/src/data/keyword.hpp b/src/data/keyword.hpp
index 81830800..a3bd41a4 100644
--- a/src/data/keyword.hpp
+++ b/src/data/keyword.hpp
@@ -16,9 +16,18 @@
DECLARE_POINTER_TYPE(KeywordParam);
DECLARE_POINTER_TYPE(KeywordMode);
DECLARE_POINTER_TYPE(Keyword);
+DECLARE_POINTER_TYPE(ParamReferenceType);
class KeywordTrie;
-// ----------------------------------------------------------------------------- : Keyword components
+// ----------------------------------------------------------------------------- : Keyword parameters
+
+class ParamReferenceType {
+ String name; ///< Name of the parameter reference type
+ String description; ///< Description (for status bar)
+ StringScript code; ///< Code to insert into the reminder text script, input is the actual parameter name
+
+ DECLARE_REFLECTION();
+};
/// Parameter type of keywords
class KeywordParam {
@@ -30,7 +39,8 @@ class KeywordParam {
bool optional; ///< Can this parameter be left out (a placeholder is then used)
String match; ///< Regular expression to match
OptionalScript script; ///< Transformation of the value for showing in the reminder text
- String example; ///< Example for preview dialog
+ String example; ///< Example for the keyword editor
+ vector refer_script;///< Way to refer to a parameter from the reminder text script
DECLARE_REFLECTION();
};
diff --git a/src/data/set.cpp b/src/data/set.cpp
index 61fa6bb0..297588b7 100644
--- a/src/data/set.cpp
+++ b/src/data/set.cpp
@@ -217,7 +217,7 @@ IndexMap& Set::stylingDataFor(const StyleSheet& stylesheet) {
if (!styling) {
styling = new_shared();
styling->data.init(stylesheet.styling_fields);
- } else if (!styling->unread_data.empty()) {
+ } else if (!styling->unread_data.empty() || (styling->data.empty()) && !stylesheet.styling_fields.empty()) {
// we delayed the reading of the data, read it now
styling->data.init(stylesheet.styling_fields);
Reader reader(new_shared1(styling->unread_data), _("styling data of ") + stylesheet.stylesheetName());
diff --git a/src/script/functions/english.cpp b/src/script/functions/english.cpp
index 086abd96..b9a20d31 100644
--- a/src/script/functions/english.cpp
+++ b/src/script/functions/english.cpp
@@ -52,81 +52,145 @@ String english_number(int i) {
}
}
}
+/// Write a number using words, use "a" for 1
+String english_number_a(int i) {
+ if (i == 1) return _("a");
+ else return english_number(i);
+}
+/// Write a number using words, use "" for 1
+String english_number_multiple(int i) {
+ if (i == 1) return _("");
+ else return english_number(i);
+}
+
+
+// script_english_number_*
+String do_english_num(String input, String(*fun)(int)) {
+ if (is_substr(input, 0, _("123"
+ size_t start = skip_tag(input, 0);
+ if (start != String::npos) {
+ size_t end = input.find_first_of(_('<'), start);
+ if (end != String::npos) {
+ String is = input.substr(start, end - start);
+ long i = 0;
+ if (is.ToLong(&i)) {
+ if (i == 1) {
+ return _("") + substr_replace(input, start, end, fun(i));
+ } else {
+ return _("") + substr_replace(input, start, end, fun(i));
+ }
+ }
+ }
+ }
+ } else {
+ long i = 0;
+ if (input.ToLong(&i)) {
+ return fun(i);
+ }
+ }
+ return input;
+}
SCRIPT_FUNCTION(english_number) {
- SCRIPT_PARAM(int, input);
- SCRIPT_RETURN(english_number(input));
+ SCRIPT_PARAM(String, input);
+ SCRIPT_RETURN(do_english_num(input, english_number));
}
-
SCRIPT_FUNCTION(english_number_a) {
- SCRIPT_PARAM(int, input);
- if (input == 1) {
- SCRIPT_RETURN(_("a"));
- } else {
- SCRIPT_RETURN(english_number(input));
- }
+ SCRIPT_PARAM(String, input);
+ SCRIPT_RETURN(do_english_num(input, english_number_a));
}
-
-// ----------------------------------------------------------------------------- : A/an
-
-
-// ----------------------------------------------------------------------------- : Singular/plural
-
-SCRIPT_FUNCTION(english_singular) {
- throw InternalError(_("TODO"));
-}
-
-SCRIPT_FUNCTION(english_plural) {
- throw InternalError(_("TODO"));
+SCRIPT_FUNCTION(english_number_multiple) {
+ SCRIPT_PARAM(String, input);
+ SCRIPT_RETURN(do_english_num(input, english_number_multiple));
}
// ----------------------------------------------------------------------------- : Hints
-// insert a hint, for singular, otherwise
-SCRIPT_FUNCTION(plural_hint) {
- SCRIPT_PARAM(int, input);
- SCRIPT_RETURN(input == 1 ? _("") : _(""));
+bool is_vowel(Char c) {
+ return c == _('a') || c == _('e') || c == _('i') || c == _('o') || c == _('u')
+ || c == _('A') || c == _('E') || c == _('I') || c == _('O') || c == _('U');
}
/// Process english hints in the input string
-/** Hints have the following meaning:
- * - "xxx(yyy)zzz" ---> "xxxzzz" (singular)
- * - "xxx(yyy)zzz" ---> "xxxyyyzzz" (plural)
- * - "[^., ]a [aeiou]" ---> "\1 an \2" (articla 'an', case insensitive)
- * - "" ---> "" (remove s afterwards)
+/** A hint is formed by
+ * 1. an insertion of a parameter, ....
+ * 2. a or tag
+ *
+ * Hints have the following meaning:
+ * - "xxx(yyy)zzz" ---> "xxxzzz" (singular)
+ * - "xxx(yyy)zzz" ---> "xxxyyyzzz" (plural)
+ * - "[^., ]a [aeiou]" ---> "\1 an \2" (articla 'an', case insensitive)
+ * - "" ---> "" (remove s afterwards)
*
* Note: there is no close tags for hints
*/
String process_english_hints(const String& str) {
String ret; ret.reserve(str.size());
- int singplur = 0; // 1 for singular, 2 for plural
+ // have we seen a ?
+ // 1 for singular, 2 for plural
+ int singplur = 0;
for (size_t i = 0 ; i < str.size() ; ) {
Char c = str.GetChar(i);
- if (i + 6 < str.size() && is_substr(str, i, _("= 2) {
+ // a -> an?
+ // is there "a" before this?
+ String last = ret.substr(ret.size() - 2);
+ if ( (ret.size() == 2 || !isAlpha(ret.GetChar(ret.size() - 3))) &&
+ (last == _("a ") || last == _("A ")) ) {
+ ret.insert(ret.size() - 1, _('n'));
+ }
+ } else if (is_substr(str, after, _("= 1 &&
+ ret.GetChar(ret.size() - 1) == _(' ')) {
+ // empty param, drop space before it
+ ret.resize(ret.size() - 1);
+ }
+ }
+ ret += c;
+ ++i;
} else if (c == _('(') && singplur) {
// singular -> drop (...), plural -> keep it
- // TODO
+ size_t end = str.find_first_of(_(')'), i);
+ if (end != String::npos) {
+ if (singplur == 2) {
+ ret += str.substr(i + 1, end - i - 1);
+ }
+ i = end + 1;
+ } else { // handle like normal
+ ret += c;
+ ++i;
+ }
+ singplur = 0;
} else {
ret += c;
++i;
}
}
- return ret; // TODO
+ return ret;
}
+SCRIPT_FUNCTION(process_english_hints) {
+ SCRIPT_PARAM(String, input);
+ SCRIPT_RETURN(process_english_hints(input));
+}
// ----------------------------------------------------------------------------- : Init
void init_script_english_functions(Context& ctx) {
- ctx.setVariable(_("english number"), script_english_number);
- ctx.setVariable(_("english number a"), script_english_number_a);
+ ctx.setVariable(_("english number"), script_english_number);
+ ctx.setVariable(_("english number a"), script_english_number_a);
+ ctx.setVariable(_("english number multiple"), script_english_number_multiple);
+ ctx.setVariable(_("process english hints"), script_process_english_hints);
}