diff --git a/doc/type/statistics_dimension.txt b/doc/type/statistics_dimension.txt
index 47ffa00a..61d017b9 100644
--- a/doc/type/statistics_dimension.txt
+++ b/doc/type/statistics_dimension.txt
@@ -16,7 +16,8 @@ Categories are also automatically generated from dimensions.
| @description@ [[type:localized string]] @""@ A description of the dimension, currently not used.
| @position hint@ [[type:string]] @0@ Hint for ordering dimensions.
| @icon@ [[type:filename]] Filename of an icon for this dimension.
-| @script@ [[type:script]] ''required'' Script that generates a value for each card in the set.
+| @script@ [[type:script]] ''required'' Script that generates a value for each card in the set. Ran once for each card, then all the results are tallied.
+| @global_script@ [[type:script]] ''nil'' Script that is ran once at the start. Its result is stored in the 'global_value' variable, which is accessible to the regular script.
| @numeric@ [[type:boolean]] @false@ Is the value always a number?
| @bin size@ [[type:double]] ''none'' For numeric dimensions: group numbers together into bins this large.
For example with @bin size: 5@, values @1@ and @3@ both get put under @"1-5"@.
diff --git a/src/data/statistics.cpp b/src/data/statistics.cpp
index 0de300ad..a406d8ad 100644
--- a/src/data/statistics.cpp
+++ b/src/data/statistics.cpp
@@ -68,6 +68,7 @@ IMPLEMENT_REFLECTION_NO_GET_MEMBER(StatsDimension) {
REFLECT(position_hint);
REFLECT_N("icon", icon_filename);
REFLECT(script);
+ REFLECT(global_script);
REFLECT(numeric);
REFLECT(bin_size);
REFLECT(show_empty);
diff --git a/src/data/statistics.hpp b/src/data/statistics.hpp
index 55948e5a..56050200 100644
--- a/src/data/statistics.hpp
+++ b/src/data/statistics.hpp
@@ -27,19 +27,20 @@ public:
StatsDimension();
StatsDimension(const Field&);
- const bool automatic; ///< Based on a card field?
- String name; ///< Name of this dimension
- LocalizedString description; ///< Description, used in status bar
- int position_hint; ///< Hint for the ordering
- String icon_filename; ///< Icon for lists
- Bitmap icon; ///< The loaded icon (optional of course)
- OptionalScript script; ///< Script that determines the value(s)
- bool numeric; ///< Are the values numeric? If so, they require special sorting
+ const bool automatic; ///< Based on a card field?
+ String name; ///< Name of this dimension
+ LocalizedString description; ///< Description, used in status bar
+ int position_hint; ///< Hint for the ordering
+ String icon_filename; ///< Icon for lists
+ Bitmap icon; ///< The loaded icon (optional of course)
+ OptionalScript script; ///< Script that determines the value(s), ran on each card
+ OptionalScript global_script; ///< Script that determines the value(s), ran only once at the start
+ bool numeric; ///< Are the values numeric? If so, they require special sorting
double bin_size; ///< Bin adjecent numbers?
bool show_empty; ///< Should "" be shown?
bool split_list; ///< Split values into multiple ones separated by commas
- map colors; ///< Colors for the categories
- vector groups; ///< Order of the items
+ map colors; ///< Colors for the categories
+ vector groups; ///< Order of the items
DECLARE_REFLECTION();
};
diff --git a/src/gui/set/stats_panel.cpp b/src/gui/set/stats_panel.cpp
index 5f1fd51d..c579e7c7 100644
--- a/src/gui/set/stats_panel.cpp
+++ b/src/gui/set/stats_panel.cpp
@@ -472,13 +472,29 @@ void StatsPanel::showCategory(const GraphType* prefer_layout) {
dim->groups.empty() ? nullptr : &dim->groups
)
);
+ }
+ // find global_script values
+ vector global_values;
+ Context& global_ctx = set->getContext();
+ ScriptValueP global_ctx_value = global_ctx.getVariableOpt("global_value");
+ for (size_t d = 0 ; d < dims.size() ; ++d) {
+ auto& dim = dims[d];
+ try {
+ ScriptValueP global_value = dim->global_script.invoke(global_ctx);
+ global_values.push_back(global_value);
+ } catch (ScriptError const& e) {
+ handle_error(ScriptError(e.what() + _("\n in global script for statistics dimension '") + dim->name + _("'")));
+ global_values.push_back(script_nil);
+ }
}
- // find values for each card
+ // find script values for each card
for (size_t i = 0 ; i < set->cards.size() ; ++i) {
Context& ctx = set->getContext(set->cards[i]);
GraphElementP e = make_intrusive(i);
bool show = true;
- FOR_EACH(dim, dims) {
+ for (size_t d = 0 ; d < dims.size() ; ++d) {
+ auto& dim = dims[d];
+ ctx.setVariable("global_value", global_values[d]);
try {
String value = untag(dim->script.invoke(ctx)->toString());
e->values.push_back(value);
@@ -497,7 +513,9 @@ void StatsPanel::showCategory(const GraphType* prefer_layout) {
assert(e->values.size() == dims.size());
d.elements.push_back(e);
}
- }
+ }
+ // restore old global value if any
+ if (global_ctx_value) global_ctx.setVariable("global_value", global_ctx_value);
// split lists
size_t dim_id = 0;
FOR_EACH(dim, dims) {