mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Added count_chosen function;
Added I_DUP instruction git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1007 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -15,3 +15,6 @@ Is the given choice selected in the [[type:value#multiple_choice|multiple choice
|
|||||||
> chosen(choice: "red", "blue") == false
|
> chosen(choice: "red", "blue") == false
|
||||||
> chosen(choice: "red", "red, blue") == true
|
> chosen(choice: "red", "red, blue") == true
|
||||||
> chosen(choice: "blue", "red, blue") == true
|
> chosen(choice: "blue", "red, blue") == true
|
||||||
|
|
||||||
|
--See also--
|
||||||
|
| [[fun:count_chosen]] Count then number of choices selected in a multiple choice value.
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
Function: count_chosen
|
||||||
|
|
||||||
|
DOC_MSE_VERSION: since 0.3.7
|
||||||
|
|
||||||
|
--Usage--
|
||||||
|
> count_chosen(choices: some_string, some_multiple_choice_value)
|
||||||
|
|
||||||
|
Coint the number of choices that are selected in a [[type:value#multiple_choice|multiple choice value]].
|
||||||
|
|
||||||
|
If the @choices@ parameter is given then only choices from that list are counted.
|
||||||
|
|
||||||
|
--Parameters--
|
||||||
|
! Parameter Type Description
|
||||||
|
| @input@ [[type:string]] Multiple choice value to look in.
|
||||||
|
| @choices@ optional [[type:string]] A comma separated list of choices to look for.
|
||||||
|
|
||||||
|
--Examples--
|
||||||
|
> count_chosen("") == 0
|
||||||
|
> count_chosen("red") == 1
|
||||||
|
> count_chosen("red, green") == 2
|
||||||
|
> count_chosen("red, green", choices: "red,blue") == 1
|
||||||
|
|
||||||
|
--See also--
|
||||||
|
| [[fun:chosen]] Is a given choice selected in a multiple choice value?
|
||||||
@@ -56,6 +56,7 @@ These functions are built into the program, other [[type:function]]s can be defi
|
|||||||
| [[fun:combined_editor]] Use one field to edit multiple others.
|
| [[fun:combined_editor]] Use one field to edit multiple others.
|
||||||
| [[fun:primary_choice]] Return the top level choice chosen from a choice field.
|
| [[fun:primary_choice]] Return the top level choice chosen from a choice field.
|
||||||
| [[fun:chosen]] Is the given choice selected in a multiple choice value?
|
| [[fun:chosen]] Is the given choice selected in a multiple choice value?
|
||||||
|
| [[fun:count_chosen]] Count then number of choices selected in a multiple choice value.
|
||||||
| [[fun:require_choice]] Require that at least one of the given choices is selected.
|
| [[fun:require_choice]] Require that at least one of the given choices is selected.
|
||||||
| [[fun:exclusive_choice]] Require that at most one of the given choices is selected.
|
| [[fun:exclusive_choice]] Require that at most one of the given choices is selected.
|
||||||
| [[fun:require_exclusive_choice]] Require that exactly one of the given choices is selected.
|
| [[fun:require_exclusive_choice]] Require that exactly one of the given choices is selected.
|
||||||
|
|||||||
@@ -10,18 +10,26 @@ If non of the choices is selected, selects the first one.
|
|||||||
--Parameters--
|
--Parameters--
|
||||||
! Parameter Type Description
|
! Parameter Type Description
|
||||||
| @input@ [[type:string]] Multiple choice value to look update.
|
| @input@ [[type:string]] Multiple choice value to look update.
|
||||||
| @choice@ [[type:string]] Choice to require.
|
| @choices@ [[type:string]] Comma separated list of choices of which one is required.
|
||||||
|
|
||||||
|
For backwards compatability the following form is also supported:
|
||||||
|
|
||||||
|
DOC_MSE_VERSION: until 0.3.6
|
||||||
|
|
||||||
|
! Parameter Type Description
|
||||||
|
| @input@ [[type:string]] Multiple choice value to look update.
|
||||||
|
| @choice@ [[type:string]] Single choice to require.
|
||||||
| @choice1@ [[type:string]] Require multiple choices.
|
| @choice1@ [[type:string]] Require multiple choices.
|
||||||
| @choice2@ [[type:string]] ''etc.''
|
| @choice2@ [[type:string]] ''etc.''
|
||||||
|
|
||||||
--Examples--
|
--Examples--
|
||||||
> require_choice(choice: "red", "red") == "red"
|
> require_choice(choices: "red", "red") == "red"
|
||||||
> require_choice(choice: "red", "blue") == "blue, red"
|
> require_choice(choices: "red", "blue") == "blue, red"
|
||||||
> require_choice(choice: "red", "red, blue") == "red, blue"
|
> require_choice(choices: "red", "red, blue") == "red, blue"
|
||||||
> require_choice(choice1: "red", choice2: "green", "red, blue") == "red, blue"
|
> require_choice(choices: "red,green", "red, blue") == "red, blue"
|
||||||
> require_choice(choice1: "red", choice2: "green", "red, green") == "red, blue"
|
> require_choice(choices: "red,green", "red, green") == "red, blue"
|
||||||
> require_choice(choice1: "red", choice2: "green", "green, blue") == "green, blue"
|
> require_choice(choices: "red,green", "green, blue") == "green, blue"
|
||||||
> require_choice(choice1: "red", choice2: "green", "black, blue") == "black, blue, red"
|
> require_choice(choices: "red,green", "black, blue") == "black, blue, red"
|
||||||
|
|
||||||
--See also--
|
--See also--
|
||||||
| [[fun:exclusive_choice]] Require that ''at most one'' of the given choices is selected.
|
| [[fun:exclusive_choice]] Require that ''at most one'' of the given choices is selected.
|
||||||
|
|||||||
@@ -3480,6 +3480,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath="..\doc\function\copy_file.txt">
|
RelativePath="..\doc\function\copy_file.txt">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\doc\function\count_chosen.txt">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\doc\function\crop.txt">
|
RelativePath="..\doc\function\crop.txt">
|
||||||
</File>
|
</File>
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
|
|||||||
instrQuaternary(i.instr4, a, b, c, d);
|
instrQuaternary(i.instr4, a, b, c, d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Duplicate stack
|
||||||
|
case I_DUP: {
|
||||||
|
stack.push_back(stack.at(stack.size() - i.data - 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -325,6 +325,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
|||||||
a = dependency_dummy;
|
a = dependency_dummy;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Duplicate stack
|
||||||
|
case I_DUP: {
|
||||||
|
stack.push_back(stack.at(stack.size() - i.data - 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,19 +203,23 @@ SCRIPT_FUNCTION(primary_choice) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Multiple choice values
|
// ----------------------------------------------------------------------------- : Multiple choice values
|
||||||
|
|
||||||
|
/// Iterate over a comma separated list
|
||||||
|
bool next_choice(size_t& start, size_t& end, const String& input) {
|
||||||
|
if (start >= input.size()) return false;
|
||||||
|
// ingore whitespace
|
||||||
|
while (start < input.size() && input.GetChar(start) == _(' ')) ++start;
|
||||||
|
// find end
|
||||||
|
end = input.find_first_of(_(','), start);
|
||||||
|
if (end == String::npos) end = input.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Is the given choice active?
|
/// Is the given choice active?
|
||||||
bool chosen(const String& choice, const String& input) {
|
bool chosen(const String& choice, const String& input) {
|
||||||
for (size_t pos = 0 ; pos < input.size() ; ) {
|
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end+1 ) {
|
||||||
if (input.GetChar(pos) == _(' ')) {
|
// does this choice match the one asked about?
|
||||||
++pos; // ingore whitespace
|
if (end - start == choice.size() && is_substr(input, start, choice)) {
|
||||||
} else {
|
return true;
|
||||||
// does this choice match the one asked about?
|
|
||||||
size_t end = input.find_first_of(_(','), pos);
|
|
||||||
if (end == String::npos) end = input.size();
|
|
||||||
if (end - pos == choice.size() && is_substr(input, pos, choice)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
pos = end + 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -236,29 +240,22 @@ String filter_choices(const String& input, const vector<String>& choices, int mi
|
|||||||
if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure
|
if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure
|
||||||
String ret;
|
String ret;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
vector<bool> seen(choices.size()); // which choices have we seen?
|
vector<bool> seen(choices.size()); // which choices have we seen in input?
|
||||||
for (size_t pos = 0 ; pos < input.size() ; ) {
|
// walk over the input
|
||||||
if (input.GetChar(pos) == _(' ')) {
|
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end +1) {
|
||||||
++pos; // ingore whitespace
|
// is this choice in choices
|
||||||
} else {
|
bool in_choices = false;
|
||||||
// does this choice match the one asked about?
|
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||||
size_t end = input.find_first_of(_(','), pos);
|
if (!seen[i] && is_substr(input, start, choices[i])) {
|
||||||
if (end == String::npos) end = input.size();
|
seen[i] = true; ++count;
|
||||||
// is this choice in choices
|
in_choices = true;
|
||||||
bool in_choices = false;
|
break;
|
||||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
|
||||||
if (!seen[i] && is_substr(input, pos, choices[i])) {
|
|
||||||
seen[i] = true; ++count;
|
|
||||||
in_choices = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// is this choice unaffected?
|
}
|
||||||
if (!in_choices) {
|
// is this choice unaffected?
|
||||||
if (!ret.empty()) ret += _(", ");
|
if (!in_choices) {
|
||||||
ret += input.substr(pos, end - pos);
|
if (!ret.empty()) ret += _(", ");
|
||||||
}
|
ret += input.substr(start, end - start);
|
||||||
pos = end + 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// keep more choices
|
// keep more choices
|
||||||
@@ -301,12 +298,23 @@ String filter_choices(const String& input, const vector<String>& choices, int mi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read 'choice#' arguments
|
// read 'choice#' arguments
|
||||||
void read_choices_param(Context& ctx, vector<String>& choices) {
|
void read_choices_param(Context& ctx, vector<String>& choices_out) {
|
||||||
for (int i = 0 ; ; ++i) {
|
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
|
||||||
String name = _("choice"); if (i > 0) name = name << i;
|
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
|
||||||
SCRIPT_OPTIONAL_PARAM_N(String, name, choice) {
|
choices_out.push_back(choices.substr(start,end-start));
|
||||||
choices.push_back(choice);
|
}
|
||||||
} else if (i > 0) break;
|
} else {
|
||||||
|
// old style: separate arguments
|
||||||
|
SCRIPT_OPTIONAL_PARAM_C(String,choice) {
|
||||||
|
choices_out.push_back(choice);
|
||||||
|
} else {
|
||||||
|
for (int i = 1 ; ; ++i) {
|
||||||
|
String name = _("choice");
|
||||||
|
SCRIPT_OPTIONAL_PARAM_N(String, name << i, choice) {
|
||||||
|
choices_out.push_back(choice);
|
||||||
|
} else break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,6 +353,28 @@ SCRIPT_FUNCTION(remove_choice) {
|
|||||||
SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _("")));
|
SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _("")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// count how many choices are active
|
||||||
|
SCRIPT_FUNCTION(count_chosen) {
|
||||||
|
SCRIPT_PARAM_C(String,input);
|
||||||
|
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
|
||||||
|
// only count specific choices
|
||||||
|
int count = 0;
|
||||||
|
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
|
||||||
|
if (chosen(choices.substr(start,end-start),input)) ++count;
|
||||||
|
}
|
||||||
|
SCRIPT_RETURN(count);
|
||||||
|
} else {
|
||||||
|
// count all choices => count comma's + 1
|
||||||
|
if (input.empty()) {
|
||||||
|
SCRIPT_RETURN(0);
|
||||||
|
} else {
|
||||||
|
int count = 1;
|
||||||
|
FOR_EACH(c, input) if (c == _(',')) ++count;
|
||||||
|
SCRIPT_RETURN(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Init
|
// ----------------------------------------------------------------------------- : Init
|
||||||
|
|
||||||
void init_script_editor_functions(Context& ctx) {
|
void init_script_editor_functions(Context& ctx) {
|
||||||
@@ -352,6 +382,7 @@ void init_script_editor_functions(Context& ctx) {
|
|||||||
ctx.setVariable(_("combined editor"), script_combined_editor);
|
ctx.setVariable(_("combined editor"), script_combined_editor);
|
||||||
ctx.setVariable(_("primary choice"), script_primary_choice);
|
ctx.setVariable(_("primary choice"), script_primary_choice);
|
||||||
ctx.setVariable(_("chosen"), script_chosen);
|
ctx.setVariable(_("chosen"), script_chosen);
|
||||||
|
ctx.setVariable(_("count chosen"), script_count_chosen);
|
||||||
ctx.setVariable(_("require choice"), script_require_choice);
|
ctx.setVariable(_("require choice"), script_require_choice);
|
||||||
ctx.setVariable(_("exclusive choice"), script_exclusive_choice);
|
ctx.setVariable(_("exclusive choice"), script_exclusive_choice);
|
||||||
ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice);
|
ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice);
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ void init_script_variables() {
|
|||||||
Var(order);
|
Var(order);
|
||||||
Var(filter);
|
Var(filter);
|
||||||
Var(choice);
|
Var(choice);
|
||||||
|
Var(choices);
|
||||||
Var(format);
|
Var(format);
|
||||||
Var(tag);
|
Var(tag);
|
||||||
Var(contents);
|
Var(contents);
|
||||||
@@ -199,13 +200,14 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
|
|||||||
case I_RGBA: ret += _("rgba"); break;
|
case I_RGBA: ret += _("rgba"); break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case I_DUP: ret += _("dup"); break;
|
||||||
}
|
}
|
||||||
// arg
|
// arg
|
||||||
switch (i.instr) {
|
switch (i.instr) {
|
||||||
case I_PUSH_CONST: case I_MEMBER_C: // const
|
case I_PUSH_CONST: case I_MEMBER_C: // const
|
||||||
ret += _("\t") + constants[i.data]->typeName();
|
ret += _("\t") + constants[i.data]->typeName();
|
||||||
break;
|
break;
|
||||||
case I_JUMP: case I_JUMP_IF_NOT: case I_LOOP: case I_MAKE_OBJECT: case I_CALL: case I_CLOSURE: // int
|
case I_JUMP: case I_JUMP_IF_NOT: case I_LOOP: case I_MAKE_OBJECT: case I_CALL: case I_CLOSURE: case I_DUP: // int
|
||||||
ret += String::Format(_("\t%d"), i.data);
|
ret += String::Format(_("\t%d"), i.data);
|
||||||
break;
|
break;
|
||||||
case I_GET_VAR: case I_SET_VAR: case I_NOP: // variable
|
case I_GET_VAR: case I_SET_VAR: case I_NOP: // variable
|
||||||
@@ -232,7 +234,7 @@ const Instruction* Script::backtraceSkip(const Instruction* instr, int to_skip)
|
|||||||
// skip an instruction
|
// skip an instruction
|
||||||
switch (instr->instr) {
|
switch (instr->instr) {
|
||||||
case I_PUSH_CONST:
|
case I_PUSH_CONST:
|
||||||
case I_GET_VAR:
|
case I_GET_VAR: case I_DUP:
|
||||||
to_skip -= 1; break; // nett stack effect +1
|
to_skip -= 1; break; // nett stack effect +1
|
||||||
case I_BINARY:
|
case I_BINARY:
|
||||||
to_skip += 1; break; // nett stack effect 1-2 == -1
|
to_skip += 1; break; // nett stack effect 1-2 == -1
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ enum InstructionType
|
|||||||
, I_BINARY = 12 ///< arg = 2ary instr : pop 2 values, apply a function, push the result
|
, I_BINARY = 12 ///< arg = 2ary instr : pop 2 values, apply a function, push the result
|
||||||
, I_TERNARY = 13 ///< arg = 3ary instr : pop 3 values, apply a function, push the result
|
, I_TERNARY = 13 ///< arg = 3ary instr : pop 3 values, apply a function, push the result
|
||||||
, I_QUATERNARY = 14 ///< arg = 4ary instr : pop 4 values, apply a function, push the result
|
, I_QUATERNARY = 14 ///< arg = 4ary instr : pop 4 values, apply a function, push the result
|
||||||
|
, I_DUP = 15 ///< arg = int : duplicate the k-from-top element of the stack
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Types of unary instructions (taking one argument from the stack)
|
/// Types of unary instructions (taking one argument from the stack)
|
||||||
@@ -117,6 +118,7 @@ enum Variable
|
|||||||
, SCRIPT_VAR_order
|
, SCRIPT_VAR_order
|
||||||
, SCRIPT_VAR_filter
|
, SCRIPT_VAR_filter
|
||||||
, SCRIPT_VAR_choice
|
, SCRIPT_VAR_choice
|
||||||
|
, SCRIPT_VAR_choices
|
||||||
, SCRIPT_VAR_format
|
, SCRIPT_VAR_format
|
||||||
, SCRIPT_VAR_tag
|
, SCRIPT_VAR_tag
|
||||||
, SCRIPT_VAR_contents
|
, SCRIPT_VAR_contents
|
||||||
@@ -204,3 +206,4 @@ class Script : public ScriptValue {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
| ||||||