The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
function.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2017 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "formula/function.hpp"
16 
17 #include "color.hpp"
18 #include "formula/callable_objects.hpp"
19 #include "formula/debugger.hpp"
20 #include "game_config.hpp"
21 #include "game_display.hpp"
22 #include "log.hpp"
23 
24 #include <boost/math/constants/constants.hpp>
25 #include <cctype>
26 #include <deque>
27 
28 using namespace boost::math::constants;
29 
30 static lg::log_domain log_engine("engine");
31 #define DBG_NG LOG_STREAM(debug, log_engine)
32 static lg::log_domain log_scripting_formula("scripting/formula");
33 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
34 #define WRN_SF LOG_STREAM(warn, log_scripting_formula)
35 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
36 
37 namespace wfl
38 {
39 static std::deque<std::string> call_stack;
40 
41 call_stack_manager::call_stack_manager(const std::string& str)
42 {
43  call_stack.push_back(str);
44 }
45 
46 call_stack_manager::~call_stack_manager()
47 {
48  call_stack.pop_back();
49 }
50 
52 {
53  std::ostringstream res;
54  for(const auto& frame : call_stack) {
55  if(!frame.empty()) {
56  res << " " << frame << "\n";
57  }
58  }
59 
60  return res.str();
61 }
62 
63 std::string function_expression::str() const
64 {
65  std::stringstream s;
66  s << get_name();
67  s << '(';
68  bool first_arg = true;
69  for(expression_ptr a : args()) {
70  if(!first_arg) {
71  s << ',';
72  } else {
73  first_arg = false;
74  }
75  s << a->str();
76  }
77  s << ')';
78  return s.str();
79 }
80 
81 namespace builtins
82 {
84 {
85  std::shared_ptr<formula_debugger> fdbp;
86  bool need_wrapper = false;
87 
88  if(fdb == nullptr) {
89  fdbp.reset(new formula_debugger());
90  fdb = fdbp.get();
91  need_wrapper = true;
92  }
93 
94  if(args().size() == 1) {
95  if(!need_wrapper) {
96  return args()[0]->evaluate(variables, fdb);
97  } else {
98  return wrapper_formula(args()[0]).evaluate(variables, fdb);
99  }
100  }
101 
102  return wrapper_formula().evaluate(variables, fdb);
103 }
104 
106 {
107  variant var = args()[0]->evaluate(variables, fdb);
108 
109  auto callable = var.as_callable();
110  formula_input_vector inputs = callable->inputs();
111 
112  std::vector<variant> res;
113  for(size_t i = 0; i < inputs.size(); ++i) {
114  const formula_input& input = inputs[i];
115  res.emplace_back(input.name);
116  }
117 
118  return variant(res);
119 }
120 
122 {
123  for(size_t n = 0; n < args().size() - 1; n += 2) {
124  if(args()[n]->evaluate(variables, fdb).as_bool()) {
125  return args()[n + 1]->evaluate(variables, fdb);
126  }
127  }
128 
129  if((args().size() % 2) != 0) {
130  return args().back()->evaluate(variables, fdb);
131  } else {
132  return variant();
133  }
134 }
135 
136 DEFINE_WFL_FUNCTION(switch, 3, -1)
137 {
138  variant var = args()[0]->evaluate(variables, fdb);
139 
140  for(size_t n = 1; n < args().size() - 1; n += 2) {
141  variant val = args()[n]->evaluate(variables, fdb);
142 
143  if(val == var) {
144  return args()[n + 1]->evaluate(variables, fdb);
145  }
146  }
147 
148  if((args().size() % 2) == 0) {
149  return args().back()->evaluate(variables, fdb);
150  } else {
151  return variant();
152  }
153 }
154 
156 {
157  const variant input = args()[0]->evaluate(variables, fdb);
158  if(input.is_decimal()) {
159  const int n = input.as_decimal();
160  return variant(n >= 0 ? n : -n, variant::DECIMAL_VARIANT);
161  } else {
162  const int n = input.as_int();
163  return variant(n >= 0 ? n : -n);
164  }
165 }
166 
168 {
169  variant res = args()[0]->evaluate(variables, fdb);
170  if(res.is_list()) {
171  if(res.is_empty()) {
172  throw formula_error("min(list): list is empty", "", "", 0);
173  }
174 
175  res = *std::min_element(res.begin(), res.end());
176  }
177 
178  for(size_t n = 1; n < args().size(); ++n) {
179  variant v = args()[n]->evaluate(variables, fdb);
180 
181  if(v.is_list()) {
182  if(v.is_empty()) {
183  continue;
184  }
185 
186  v = *std::min_element(v.begin(), v.end());
187  }
188 
189  if(res.is_null() || v < res) {
190  res = v;
191  }
192  }
193 
194  return res;
195 }
196 
198 {
199  variant res = args()[0]->evaluate(variables, fdb);
200  if(res.is_list()) {
201  if(res.is_empty()) {
202  throw formula_error("max(list): list is empty", "", "", 0);
203  }
204 
205  res = *std::max_element(res.begin(), res.end());
206  }
207 
208  for(size_t n = 1; n < args().size(); ++n) {
209  variant v = args()[n]->evaluate(variables, fdb);
210 
211  if(v.is_list()) {
212  if(v.is_empty()) {
213  continue;
214  }
215 
216  v = *std::max_element(v.begin(), v.end());
217  }
218 
219  if(res.is_null() || v > res) {
220  res = v;
221  }
222  }
223 
224  return res;
225 }
226 
227 namespace
228 {
229 void display_float(const map_location& location, const std::string& text)
230 {
231  game_display::get_singleton()->float_label(location, text, color_t(255, 0, 0));
232 }
233 } // end anon namespace
234 
235 DEFINE_WFL_FUNCTION(debug_float, 2, 3)
236 {
237  const args_list& arguments = args();
238  const variant var0 = arguments[0]->evaluate(variables, fdb);
239  const variant var1 = arguments[1]->evaluate(variables, fdb);
240 
241  const map_location location = var0.convert_to<location_callable>()->loc();
242  std::string text;
243 
244  if(arguments.size() == 2) {
245  text = var1.to_debug_string();
246  display_float(location, text);
247  return var1;
248  } else {
249  const variant var2 = arguments[2]->evaluate(variables, fdb);
250  text = var1.string_cast() + var2.to_debug_string();
251  display_float(location, text);
252  return var2;
253  }
254 }
255 
256 DEFINE_WFL_FUNCTION(debug_print, 1, 2)
257 {
258  const variant var1 = args()[0]->evaluate(variables, fdb);
259 
260  std::string str1, str2;
261 
262  if(args().size() == 1) {
263  str1 = var1.to_debug_string(true);
264 
265  LOG_SF << str1 << std::endl;
266 
267  if(game_config::debug) {
269  time(nullptr), "WFL", 0, str1, events::chat_handler::MESSAGE_PUBLIC, false);
270  }
271 
272  return var1;
273  } else {
274  str1 = var1.string_cast();
275 
276  const variant var2 = args()[1]->evaluate(variables, fdb);
277  str2 = var2.to_debug_string(true);
278 
279  LOG_SF << str1 << ": " << str2 << std::endl;
280 
283  time(nullptr), str1, 0, str2, events::chat_handler::MESSAGE_PUBLIC, false);
284  }
285 
286  return var2;
287  }
288 }
289 
290 DEFINE_WFL_FUNCTION(debug_profile, 1, 2)
291 {
292  std::string speaker = "WFL";
293  int i_value = 0;
294 
295  if(args().size() == 2) {
296  speaker = args()[0]->evaluate(variables, fdb).string_cast();
297  i_value = 1;
298  }
299 
300  const variant value = args()[i_value]->evaluate(variables, fdb);
301  long run_time = 0;
302 
303  for(int i = 1; i < 1000; i++) {
304  const long start = SDL_GetTicks();
305  args()[i_value]->evaluate(variables, fdb);
306  run_time += SDL_GetTicks() - start;
307  }
308 
309  std::ostringstream str;
310  str << "Evaluated in " << (run_time / 1000.0) << " ms on average";
311 
312  LOG_SF << speaker << ": " << str.str() << std::endl;
313 
316  time(nullptr), speaker, 0, str.str(), events::chat_handler::MESSAGE_PUBLIC, false);
317  }
318 
319  return value;
320 }
321 
323 {
324  const variant map = args()[0]->evaluate(variables, fdb);
325  return map.get_keys();
326 }
327 
328 DEFINE_WFL_FUNCTION(values, 1, 1)
329 {
330  const variant map = args()[0]->evaluate(variables, fdb);
331  return map.get_values();
332 }
333 
334 DEFINE_WFL_FUNCTION(tolist, 1, 1)
335 {
336  const variant var = args()[0]->evaluate(variables, fdb);
337 
338  std::vector<variant> tmp;
339  for(variant_iterator it = var.begin(); it != var.end(); ++it) {
340  tmp.push_back(*it);
341  }
342 
343  return variant(tmp);
344 }
345 
347 {
348  const variant var_1 = args()[0]->evaluate(variables, fdb);
349 
350  std::map<variant, variant> tmp;
351 
352  if(args().size() == 2) {
353  const variant var_2 = args()[1]->evaluate(variables, fdb);
354  if(var_1.num_elements() != var_2.num_elements()) {
355  return variant();
356  }
357 
358  for(size_t i = 0; i < var_1.num_elements(); ++i) {
359  tmp[var_1[i]] = var_2[i];
360  }
361  } else {
362  for(variant_iterator it = var_1.begin(); it != var_1.end(); ++it) {
363  if(auto kv = (*it).try_convert<key_value_pair>()) {
364  tmp[kv->query_value("key")] = kv->query_value("value");
365  } else {
366  auto map_it = tmp.find(*it);
367 
368  if(map_it == tmp.end()) {
369  tmp[*it] = variant(1);
370  } else {
371  map_it->second = variant(map_it->second.as_int() + 1);
372  }
373  }
374  }
375  }
376 
377  return variant(tmp);
378 }
379 
380 DEFINE_WFL_FUNCTION(substring, 2, 3)
381 {
382  std::string result = args()[0]->evaluate(variables, fdb).as_string();
383 
384  int offset = args()[1]->evaluate(variables, fdb).as_int();
385  if(offset < 0) {
386  offset += result.size();
387 
388  if(offset < 0) {
389  offset = 0;
390  }
391  } else {
392  if(static_cast<size_t>(offset) >= result.size()) {
393  return variant(std::string());
394  }
395  }
396 
397  if(args().size() > 2) {
398  int size = args()[2]->evaluate(variables, fdb).as_int();
399 
400  if(size < 0) {
401  size = -size;
402  offset = std::max(0, offset - size + 1);
403  }
404 
405  return variant(result.substr(offset, size));
406  }
407 
408  return variant(result.substr(offset));
409 }
410 
411 DEFINE_WFL_FUNCTION(replace, 3, 4)
412 {
413  std::string result = args()[0]->evaluate(variables, fdb).as_string();
414  std::string replacement = args().back()->evaluate(variables, fdb).as_string();
415 
416  int offset = args()[1]->evaluate(variables, fdb).as_int();
417  if(offset < 0) {
418  offset += result.size();
419 
420  if(offset < 0) {
421  offset = 0;
422  }
423  } else {
424  if(static_cast<size_t>(offset) >= result.size()) {
425  return variant(result);
426  }
427  }
428 
429  if(args().size() > 3) {
430  int size = args()[2]->evaluate(variables, fdb).as_int();
431 
432  if(size < 0) {
433  size = -size;
434  offset = std::max(0, offset - size + 1);
435  }
436 
437  return variant(result.replace(offset, size, replacement));
438  }
439 
440  return variant(result.replace(offset, std::string::npos, replacement));
441 }
442 
444 {
445  std::string result = args()[0]->evaluate(variables, fdb).as_string();
446  std::string insert = args().back()->evaluate(variables, fdb).as_string();
447 
448  int offset = args()[1]->evaluate(variables, fdb).as_int();
449  if(offset < 0) {
450  offset += result.size();
451 
452  if(offset < 0) {
453  offset = 0;
454  }
455  } else if(static_cast<size_t>(offset) >= result.size()) {
456  return variant(result + insert);
457  }
458 
459  return variant(result.insert(offset, insert));
460 }
461 
462 DEFINE_WFL_FUNCTION(length, 1, 1)
463 {
464  return variant(args()[0]->evaluate(variables, fdb).as_string().length());
465 }
466 
467 DEFINE_WFL_FUNCTION(concatenate, 1, -1)
468 {
469  std::string result;
470  for(expression_ptr arg : args()) {
471  result += arg->evaluate(variables, fdb).string_cast();
472  }
473 
474  return variant(result);
475 }
476 
478 {
479  std::string str = args()[0]->evaluate(variables, fdb).as_string();
480  std::transform(str.begin(), str.end(), str.begin(), static_cast<int (*)(int)>(std::toupper));
481  return variant(str);
482 }
483 
485 {
486  std::string str = args()[0]->evaluate(variables, fdb).as_string();
487  std::transform(str.begin(), str.end(), str.begin(), static_cast<int (*)(int)>(std::tolower));
488  return variant(str);
489 }
490 
492 {
493  const double angle = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
494  const double result = sin(angle * pi<double>() / 180.0);
495  return variant(result, variant::DECIMAL_VARIANT);
496 }
497 
499 {
500  const double angle = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
501  const double result = cos(angle * pi<double>() / 180.0);
502  return variant(result, variant::DECIMAL_VARIANT);
503 }
504 
506 {
507  const double angle = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
508  const double result = tan(angle * pi<double>() / 180.0);
509  if(std::isnan(result) || result <= INT_MIN || result >= INT_MAX) {
510  return variant();
511  }
512 
513  return variant(result, variant::DECIMAL_VARIANT);
514 }
515 
517 {
518  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
519  const double result = asin(num) * 180.0 / pi<double>();
520  if(std::isnan(result)) {
521  return variant();
522  }
523 
524  return variant(result, variant::DECIMAL_VARIANT);
525 }
526 
528 {
529  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
530  const double result = acos(num) * 180.0 / pi<double>();
531  if(std::isnan(result)) {
532  return variant();
533  }
534 
535  return variant(result, variant::DECIMAL_VARIANT);
536 }
537 
539 {
540  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
541  const double result = atan(num) * 180.0 / pi<double>();
542  return variant(result, variant::DECIMAL_VARIANT);
543 }
544 
546 {
547  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
548  const double result = sqrt(num);
549  if(std::isnan(result)) {
550  return variant();
551  }
552 
553  return variant(result, variant::DECIMAL_VARIANT);
554 }
555 
557 {
558  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
559  const double result = num < 0 ? -pow(-num, 1.0 / 3.0) : pow(num, 1.0 / 3.0);
560  return variant(result, variant::DECIMAL_VARIANT);
561 }
562 
564 {
565  const double base = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
566  const double root = args()[1]->evaluate(variables, fdb).as_decimal() / 1000.0;
567  const double result = base < 0 && fmod(root, 2) == 1 ? -pow(-base, 1.0 / root) : pow(base, 1.0 / root);
568  if(std::isnan(result)) {
569  return variant();
570  }
571 
572  return variant(result, variant::DECIMAL_VARIANT);
573 }
574 
576 {
577  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
578  if(args().size() == 1) {
579  const double result = log(num);
580  if(std::isnan(result)) {
581  return variant();
582  }
583 
584  return variant(result, variant::DECIMAL_VARIANT);
585  }
586 
587  const double base = args()[1]->evaluate(variables, fdb).as_decimal() / 1000.0;
588  const double result = log(num) / log(base);
589  if(std::isnan(result)) {
590  return variant();
591  }
592 
593  return variant(result, variant::DECIMAL_VARIANT);
594 }
595 
597 {
598  const double num = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
599  const double result = exp(num);
600  if(result == 0 || result >= INT_MAX) {
601  // These are range errors rather than NaNs,
602  // but I figure it's better than returning INT_MIN.
603  return variant();
604  }
605 
606  return variant(result, variant::DECIMAL_VARIANT);
607 }
608 
610 {
611  (void)variables;
612  (void)fdb;
613  return variant(pi<double>(), variant::DECIMAL_VARIANT);
614 }
615 
617 {
618  const double x = args()[0]->evaluate(variables, fdb).as_decimal() / 1000.0;
619  const double y = args()[1]->evaluate(variables, fdb).as_decimal() / 1000.0;
620  return variant(hypot(x, y), variant::DECIMAL_VARIANT);
621 }
622 
623 DEFINE_WFL_FUNCTION(index_of, 2, 2)
624 {
625  const variant value = args()[0]->evaluate(variables, fdb);
626  const variant list = args()[1]->evaluate(variables, fdb);
627 
628  for(size_t i = 0; i < list.num_elements(); ++i) {
629  if(list[i] == value) {
630  return variant(i);
631  }
632  }
633 
634  return variant(-1);
635 }
636 
637 DEFINE_WFL_FUNCTION(choose, 2, 3)
638 {
639  const variant items = args()[0]->evaluate(variables, fdb);
640  variant max_value;
641  variant_iterator max;
642 
643  if(args().size() == 2) {
644  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
645  const variant val = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
646 
647  if(max == variant_iterator() || val > max_value) {
648  max = it;
649  max_value = val;
650  }
651  }
652  } else {
653  map_formula_callable self_callable;
654  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
655 
656  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
657  self_callable.add(self, *it);
658 
659  const variant val = args().back()->evaluate(
660  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
661 
662  if(max == variant_iterator() || val > max_value) {
663  max = it;
664  max_value = val;
665  }
666  }
667  }
668 
669  if(max == variant_iterator()) {
670  return variant();
671  }
672 
673  return *max;
674 }
675 
677 {
678  const int value = args()[0]->evaluate(variables, fdb).as_int() % 1000;
679  const double angle = 2.0 * pi<double>() * (static_cast<double>(value) / 1000.0);
680  return variant(static_cast<int>(sin(angle) * 1000.0));
681 }
682 
683 namespace
684 {
685 class variant_comparator : public formula_callable
686 {
687 public:
688  variant_comparator(const expression_ptr& expr, const formula_callable& fallback)
689  : expr_(expr)
690  , fallback_(&fallback)
691  , a_()
692  , b_()
693  {
694  }
695 
696  bool operator()(const variant& a, const variant& b) const
697  {
698  a_ = a;
699  b_ = b;
700  return expr_->evaluate(*this).as_bool();
701  }
702 
703 private:
704  variant get_value(const std::string& key) const
705  {
706  if(key == "a") {
707  return a_;
708  } else if(key == "b") {
709  return b_;
710  } else {
711  return fallback_->query_value(key);
712  }
713  }
714 
715  void get_inputs(formula_input_vector& inputs) const
716  {
717  fallback_->get_inputs(inputs);
718  }
719 
721  const formula_callable* fallback_;
722  mutable variant a_, b_;
723 };
724 } // end anon namespace
725 
727 {
728  variant list = args()[0]->evaluate(variables, fdb);
729 
730  std::vector<variant> vars;
731  vars.reserve(list.num_elements());
732 
733  for(size_t n = 0; n != list.num_elements(); ++n) {
734  vars.push_back(list[n]);
735  }
736 
737  if(args().size() == 1) {
738  std::sort(vars.begin(), vars.end());
739  } else {
740  std::sort(vars.begin(), vars.end(), variant_comparator(args()[1], variables));
741  }
742 
743  return variant(vars);
744 }
745 
747 {
748  const variant& arg = args()[0]->evaluate(variables, fdb);
749 
750  if(arg.is_string()) {
751  std::string str = args()[0]->evaluate(variables, fdb).as_string();
752  std::reverse(str.begin(), str.end());
753 
754  return variant(str);
755  } else if(arg.is_list()) {
756  std::vector<variant> list = args()[0]->evaluate(variables, fdb).as_list();
757  std::reverse(list.begin(), list.end());
758 
759  return variant(list);
760  }
761 
762  return variant();
763 }
764 
765 DEFINE_WFL_FUNCTION(contains_string, 2, 2)
766 {
767  std::string str = args()[0]->evaluate(variables, fdb).as_string();
768  std::string key = args()[1]->evaluate(variables, fdb).as_string();
769 
770  return variant(str.find(key) != std::string::npos);
771 }
772 
773 DEFINE_WFL_FUNCTION(find_string, 2, 2)
774 {
775  const std::string str = args()[0]->evaluate(variables, fdb).as_string();
776  const std::string key = args()[1]->evaluate(variables, fdb).as_string();
777 
778  size_t pos = str.find(key);
779  return variant(static_cast<int>(pos));
780 }
781 
782 DEFINE_WFL_FUNCTION(filter, 2, 3)
783 {
784  std::vector<variant> list_vars;
785  std::map<variant, variant> map_vars;
786 
787  const variant items = args()[0]->evaluate(variables, fdb);
788 
789  if(args().size() == 2) {
790  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
791  const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
792 
793  if(val.as_bool()) {
794  if(items.is_map()) {
795  map_vars[(*it).get_member("key")] = (*it).get_member("value");
796  } else {
797  list_vars.push_back(*it);
798  }
799  }
800  }
801  } else {
802  map_formula_callable self_callable;
803  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
804 
805  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
806  self_callable.add(self, *it);
807 
808  const variant val = args()[2]->evaluate(
809  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
810 
811  if(val.as_bool()) {
812  if(items.is_map()) {
813  map_vars[(*it).get_member("key")] = (*it).get_member("value");
814  } else {
815  list_vars.push_back(*it);
816  }
817  }
818  }
819  }
820 
821  if(items.is_map()) {
822  return variant(map_vars);
823  }
824 
825  return variant(list_vars);
826 }
827 
829 {
830  const variant items = args()[0]->evaluate(variables, fdb);
831 
832  if(args().size() == 2) {
833  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
834  const variant val = args()[1]->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
835  if(val.as_bool()) {
836  return *it;
837  }
838  }
839  } else {
840  map_formula_callable self_callable;
841  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
842 
843  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
844  self_callable.add(self, *it);
845 
846  const variant val = args().back()->evaluate(
847  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
848 
849  if(val.as_bool()) {
850  return *it;
851  }
852  }
853  }
854 
855  return variant();
856 }
857 
859 {
860  std::vector<variant> list_vars;
861  std::map<variant, variant> map_vars;
862  const variant items = args()[0]->evaluate(variables, fdb);
863 
864  if(args().size() == 2) {
865  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
866  const variant val = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
867  if(items.is_map()) {
868  map_vars[(*it).get_member("key")] = val;
869  } else {
870  list_vars.push_back(val);
871  }
872  }
873  } else {
874  map_formula_callable self_callable;
875  const std::string self = args()[1]->evaluate(variables, fdb).as_string();
876 
877  for(variant_iterator it = items.begin(); it != items.end(); ++it) {
878  self_callable.add(self, *it);
879 
880  const variant val = args().back()->evaluate(
881  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
882 
883  if(items.is_map()) {
884  map_vars[(*it).get_member("key")] = val;
885  } else {
886  list_vars.push_back(val);
887  }
888  }
889  }
890 
891  if(items.is_map()) {
892  return variant(map_vars);
893  }
894 
895  return variant(list_vars);
896 }
897 
898 DEFINE_WFL_FUNCTION(take_while, 2, 2)
899 {
900  const variant& items = args()[0]->evaluate(variables, fdb);
901 
902  variant_iterator it = items.begin();
903  for(; it != items.end(); ++it) {
904  const variant matches = args().back()->evaluate(formula_variant_callable_with_backup(*it, variables), fdb);
905 
906  if(!matches.as_bool()) {
907  break;
908  }
909  }
910 
911  std::vector<variant> result(items.begin(), it);
912  return variant(result);
913 }
914 
915 namespace
916 {
917 struct indexer
918 {
919  explicit indexer(size_t i)
920  : i(i)
921  {
922  }
923 
924  variant operator()(const variant& v) const
925  {
926  if(i >= v.num_elements()) {
927  return variant();
928  } else {
929  return v[i];
930  }
931  }
932 
933  size_t i;
934 };
935 
936 /** @todo: replace with lambda? */
937 struct comparator
938 {
939  bool operator()(const variant& a, const variant& b) const
940  {
941  return a.num_elements() < b.num_elements();
942  }
943 };
944 
945 std::vector<variant> get_input(
946  const function_expression::args_list& args,
947  const formula_callable& variables,
948  formula_debugger* fdb)
949 {
950  if(args.size() == 1) {
951  const variant list = args[0]->evaluate(variables, fdb);
952  return std::vector<variant>(list.begin(), list.end());
953  } else {
954  std::vector<variant> input;
955  input.reserve(args.size());
956 
957  for(expression_ptr expr : args) {
958  input.push_back(expr->evaluate(variables, fdb));
959  }
960 
961  return input;
962  }
963 }
964 } // end anon namespace
965 
967 {
968  const std::vector<variant> input = get_input(args(), variables, fdb);
969  std::vector<variant> output;
970 
971  // So basically this does [[a,b,c],[d,e,f],[x,y,z]] -> [[a,d,x],[b,e,y],[c,f,z]]
972  // Or [[a,b,c,d],[x,y,z]] -> [[a,x],[b,y],[c,z],[d,null()]]
973  size_t max_i = std::max_element(input.begin(), input.end(), comparator())->num_elements();
974  output.reserve(max_i);
975 
976  for(size_t i = 0; i < max_i; i++) {
977  std::vector<variant> elem(input.size());
978  std::transform(input.begin(), input.end(), elem.begin(), indexer(i));
979  output.emplace_back(elem);
980  }
981 
982  return variant(output);
983 }
984 
985 DEFINE_WFL_FUNCTION(reduce, 2, 3)
986 {
987  const variant items = args()[0]->evaluate(variables, fdb);
988  const variant initial = args().size() == 2 ? variant() : args()[1]->evaluate(variables, fdb);
989 
990  if(items.num_elements() == 0) {
991  return initial;
992  }
993 
994  variant_iterator it = items.begin();
995  variant res(initial.is_null() ? *it : initial);
996  if(res != initial) {
997  ++it;
998  }
999 
1000  map_formula_callable self_callable;
1001  for(; it != items.end(); ++it) {
1002  self_callable.add("a", res);
1003  self_callable.add("b", *it);
1004  res = args().back()->evaluate(
1005  formula_callable_with_backup(self_callable, formula_variant_callable_with_backup(*it, variables)), fdb);
1006  }
1007 
1008  return res;
1009 }
1010 
1012 {
1013  variant res(0);
1014  const variant items = args()[0]->evaluate(variables, fdb);
1015  if(items.num_elements() > 0) {
1016  if(items[0].is_list()) {
1017  std::vector<variant> tmp;
1018  res = variant(tmp);
1019  if(args().size() >= 2) {
1020  res = args()[1]->evaluate(variables, fdb);
1021  if(!res.is_list())
1022  return variant();
1023  }
1024  } else if(items[0].is_map()) {
1025  std::map<variant, variant> tmp;
1026  res = variant(tmp);
1027  if(args().size() >= 2) {
1028  res = args()[1]->evaluate(variables, fdb);
1029  if(!res.is_map())
1030  return variant();
1031  }
1032  } else {
1033  if(args().size() >= 2) {
1034  res = args()[1]->evaluate(variables, fdb);
1035  }
1036  }
1037  }
1038 
1039  for(size_t n = 0; n != items.num_elements(); ++n) {
1040  res = res + items[n];
1041  }
1042 
1043  return res;
1044 }
1045 
1047 {
1048  const variant items = args()[0]->evaluate(variables, fdb);
1049  variant_iterator it = items.begin();
1050  if(it == items.end()) {
1051  return variant();
1052  }
1053 
1054  if(args().size() == 1) {
1055  return *it;
1056  }
1057 
1058  const int n = items.num_elements(), req = args()[1]->evaluate(variables, fdb).as_int();
1059  const int count = req < 0 ? n - std::min(-req, n) : std::min(req, n);
1060 
1061  variant_iterator end = it;
1062  std::advance(end, count);
1063 
1064  std::vector<variant> res;
1065  std::copy(it, end, std::back_inserter(res));
1066  return variant(res);
1067 }
1068 
1070 {
1071  const variant items = args()[0]->evaluate(variables, fdb);
1072  variant_iterator it = items.end();
1073  if(it == items.begin()) {
1074  return variant();
1075  }
1076 
1077  if(args().size() == 1) {
1078  return *--it;
1079  }
1080 
1081  const int n = items.num_elements(), req = args()[1]->evaluate(variables, fdb).as_int();
1082  const int count = req < 0 ? n - std::min(-req, n) : std::min(req, n);
1083 
1084  std::advance(it, -count);
1085  std::vector<variant> res;
1086 
1087  std::copy(it, items.end(), std::back_inserter(res));
1088  return variant(res);
1089 }
1090 
1092 {
1093  const variant items = args()[0]->evaluate(variables, fdb);
1094  return variant(static_cast<int>(items.num_elements()));
1095 }
1096 
1098 {
1099  if(!args().empty()) {
1100  for(size_t i = 0; i < args().size(); ++i) {
1101  args()[i]->evaluate(variables, fdb);
1102  }
1103  }
1104 
1105  return variant();
1106 }
1107 
1109 {
1110  variant decimal = args()[0]->evaluate(variables, fdb);
1111  int d = decimal.as_decimal();
1112 
1113  if((d >= 0) && (d % 1000 != 0)) {
1114  d /= 1000;
1115  return variant(++d);
1116  } else {
1117  d /= 1000;
1118  return variant(d);
1119  }
1120 }
1121 
1123 {
1124  variant decimal = args()[0]->evaluate(variables, fdb);
1125  int d = decimal.as_decimal();
1126  int f = d % 1000;
1127 
1128  if(f >= 500) {
1129  d /= 1000;
1130  return variant(++d);
1131  } else if(f <= -500) {
1132  d /= 1000;
1133  return variant(--d);
1134  } else {
1135  d /= 1000;
1136  return variant(d);
1137  }
1138 }
1139 
1141 {
1142  variant decimal = args()[0]->evaluate(variables, fdb);
1143  int d = decimal.as_decimal();
1144 
1145  if((d < 0) && (d % 1000 != 0)) {
1146  d /= 1000;
1147  return variant(--d);
1148  } else {
1149  d /= 1000;
1150  return variant(d);
1151  }
1152 }
1153 
1155 {
1156  variant decimal = args()[0]->evaluate(variables, fdb);
1157  int d = decimal.as_int();
1158 
1159  return variant(d);
1160 }
1161 
1163 {
1164  variant decimal = args()[0]->evaluate(variables, fdb);
1165  int d = decimal.as_decimal();
1166 
1167  d %= 1000;
1168  return variant(d, variant::DECIMAL_VARIANT);
1169 }
1170 
1172 {
1173  variant decimal = args()[0]->evaluate(variables, fdb);
1174  int d = decimal.as_decimal();
1175 
1176  if(d != 0) {
1177  d = d > 0 ? 1 : -1;
1178  }
1179 
1180  return variant(d);
1181 }
1182 
1183 DEFINE_WFL_FUNCTION(as_decimal, 1, 1)
1184 {
1185  variant decimal = args()[0]->evaluate(variables, fdb);
1186  int d = decimal.as_decimal();
1187 
1188  return variant(d, variant::DECIMAL_VARIANT);
1189 }
1190 
1192 {
1193  return variant(std::make_shared<location_callable>(map_location(
1194  args()[0]->evaluate(variables, add_debug_info(fdb, 0, "loc:x")).as_int(),
1195  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "loc:y")).as_int(), wml_loc()
1196  )));
1197 }
1198 
1200 {
1201  return variant(std::make_shared<key_value_pair>(
1202  args()[0]->evaluate(variables, add_debug_info(fdb, 0, "pair:key")),
1203  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "pair_value"))
1204  ));
1205 }
1206 
1208 {
1209  const map_location loc1 = args()[0]
1210  ->evaluate(variables, add_debug_info(fdb, 0, "distance_between:location_A"))
1211  .convert_to<location_callable>()
1212  ->loc();
1213 
1214  const map_location loc2 = args()[1]
1215  ->evaluate(variables, add_debug_info(fdb, 1, "distance_between:location_B"))
1216  .convert_to<location_callable>()
1217  ->loc();
1218 
1219  return variant(distance_between(loc1, loc2));
1220 }
1221 
1222 DEFINE_WFL_FUNCTION(adjacent_locs, 1, 1)
1223 {
1224  const map_location loc = args()[0]
1225  ->evaluate(variables, add_debug_info(fdb, 0, "adjacent_locs:location"))
1226  .convert_to<location_callable>()
1227  ->loc();
1228 
1229  map_location adj[6];
1230  get_adjacent_tiles(loc, adj);
1231 
1232  std::vector<variant> v;
1233  for(int n = 0; n != 6; ++n) {
1234  v.emplace_back(std::make_shared<location_callable>(adj[n]));
1235  }
1236 
1237  return variant(v);
1238 }
1239 
1240 DEFINE_WFL_FUNCTION(are_adjacent, 2, 2)
1241 {
1242  const map_location loc1 = args()[0]
1243  ->evaluate(variables, add_debug_info(fdb, 0, "are_adjacent:location_A"))
1244  .convert_to<location_callable>()
1245  ->loc();
1246 
1247  const map_location loc2 = args()[1]
1248  ->evaluate(variables, add_debug_info(fdb, 1, "are_adjacent:location_B"))
1249  .convert_to<location_callable>()
1250  ->loc();
1251 
1252  return variant(tiles_adjacent(loc1, loc2) ? 1 : 0);
1253 }
1254 
1255 DEFINE_WFL_FUNCTION(relative_dir, 2, 2)
1256 {
1257  const map_location loc1 = args()[0]
1258  ->evaluate(variables, add_debug_info(fdb, 0, "relative_dir:location_A"))
1259  .convert_to<location_callable>()
1260  ->loc();
1261 
1262  const map_location loc2 = args()[1]
1263  ->evaluate(variables, add_debug_info(fdb, 1, "relative_dir:location_B"))
1264  .convert_to<location_callable>()
1265  ->loc();
1266 
1268 }
1269 
1270 DEFINE_WFL_FUNCTION(direction_from, 2, 3)
1271 {
1272  const map_location loc = args()[0]
1273  ->evaluate(variables, add_debug_info(fdb, 0, "direction_from:location"))
1274  .convert_to<location_callable>()
1275  ->loc();
1276 
1277  const std::string dir_str =
1278  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "direction_from:dir")).as_string();
1279 
1280  int n = args().size() == 3
1281  ? args()[2]->evaluate(variables, add_debug_info(fdb, 2, "direction_from:count")).as_int()
1282  : 1;
1283 
1284  return variant(std::make_shared<location_callable>(loc.get_direction(map_location::parse_direction(dir_str), n)));
1285 }
1286 
1287 DEFINE_WFL_FUNCTION(rotate_loc_around, 2, 3)
1288 {
1289  const map_location center = args()[0]
1290  ->evaluate(variables, add_debug_info(fdb, 0, "direction_from:center"))
1291  .convert_to<location_callable>()
1292  ->loc();
1293 
1294  const map_location loc = args()[0]
1295  ->evaluate(variables, add_debug_info(fdb, 1, "direction_from:location"))
1296  .convert_to<location_callable>()
1297  ->loc();
1298 
1299  int n = args().size() == 3
1300  ? args()[2]->evaluate(variables, add_debug_info(fdb, 2, "direction_from:count")).as_int()
1301  : 1;
1302 
1303  return variant(std::make_shared<location_callable>(loc.rotate_right_around_center(center, n)));
1304 }
1305 
1307 {
1308  const variant& v = args()[0]->evaluate(variables, fdb);
1309  return variant(v.type_string());
1310 }
1311 
1312 } // namespace builtins
1313 
1314 namespace actions
1315 {
1316 DEFINE_WFL_FUNCTION(safe_call, 2, 2)
1317 {
1318  const variant main = args()[0]->evaluate(variables, fdb);
1319  const expression_ptr backup_formula = args()[1];
1320 
1321  return variant(std::make_shared<safe_call_callable>(main, backup_formula));
1322 }
1323 
1324 DEFINE_WFL_FUNCTION(set_var, 2, 2)
1325 {
1326  return variant(std::make_shared<set_var_callable>(
1327  args()[0]->evaluate(variables, add_debug_info(fdb, 0, "set_var:key")).as_string(),
1328  args()[1]->evaluate(variables, add_debug_info(fdb, 1, "set_var:value"))));
1329 }
1330 
1331 } // namespace actions
1332 
1333 variant key_value_pair::get_value(const std::string& key) const
1334 {
1335  if(key == "key") {
1336  return key_;
1337  } else if(key == "value") {
1338  return value_;
1339  }
1340 
1341  return variant();
1342 }
1343 
1344 void key_value_pair::get_inputs(formula_input_vector& inputs) const
1345 {
1346  add_input(inputs, "key");
1347  add_input(inputs, "value");
1348 }
1349 
1350 void key_value_pair::serialize_to_string(std::string& str) const
1351 {
1352  str += "pair(";
1353  str += key_.serialize_to_string();
1354  str += ",";
1355  str += value_.serialize_to_string();
1356  str += ")";
1357 }
1358 
1359 formula_function_expression::formula_function_expression(const std::string& name,
1360  const args_list& args,
1362  const_formula_ptr precondition,
1363  const std::vector<std::string>& arg_names)
1364  : function_expression(name, args, arg_names.size(), arg_names.size())
1365  , formula_(formula)
1366  , precondition_(precondition)
1367  , arg_names_(arg_names)
1368  , star_arg_(-1)
1369 {
1370  for(size_t n = 0; n != arg_names_.size(); ++n) {
1371  if(arg_names_.empty() == false && arg_names_[n][arg_names_[n].size() - 1] == '*') {
1372  arg_names_[n].resize(arg_names_[n].size() - 1);
1373  star_arg_ = n;
1374  break;
1375  }
1376  }
1377 }
1378 
1380 {
1381  static std::string indent;
1382  indent += " ";
1383 
1384  DBG_NG << indent << "executing '" << formula_->str() << "'\n";
1385 
1386  const int begin_time = SDL_GetTicks();
1387  map_formula_callable callable;
1388 
1389  for(size_t n = 0; n != arg_names_.size(); ++n) {
1390  variant var = args()[n]->evaluate(variables, fdb);
1391  callable.add(arg_names_[n], var);
1392 
1393  if(static_cast<int>(n) == star_arg_) {
1394  callable.set_fallback(var.as_callable());
1395  }
1396  }
1397 
1398  if(precondition_) {
1399  if(!precondition_->evaluate(callable, fdb).as_bool()) {
1400  DBG_NG << "FAILED function precondition for function '" << formula_->str() << "' with arguments: ";
1401 
1402  for(size_t n = 0; n != arg_names_.size(); ++n) {
1403  DBG_NG << " arg " << (n + 1) << ": " << args()[n]->evaluate(variables, fdb).to_debug_string() << "\n";
1404  }
1405  }
1406  }
1407 
1408  variant res = formula_->evaluate(callable, fdb);
1409 
1410  const int taken = SDL_GetTicks() - begin_time;
1411  DBG_NG << indent << "returning: " << taken << "\n";
1412 
1413  indent.resize(indent.size() - 2);
1414 
1415  return res;
1416 }
1417 
1419  const std::vector<expression_ptr>& args) const
1420 {
1421  return std::make_shared<formula_function_expression>(name_, args, formula_, precondition_, args_);
1422 }
1423 
1424 function_symbol_table::function_symbol_table(std::shared_ptr<function_symbol_table> parent)
1425  : parent(parent ? parent : get_builtins())
1426 {
1427 }
1428 
1430 {
1431  custom_formulas_.emplace(name, std::move(fcn));
1432 }
1433 
1435  const std::string& fn, const std::vector<expression_ptr>& args) const
1436 {
1437  const auto i = custom_formulas_.find(fn);
1438  if(i != custom_formulas_.end()) {
1439  return i->second->generate_function_expression(args);
1440  }
1441 
1442  if(parent) {
1443  expression_ptr res(parent->create_function(fn, args));
1444  if(res) {
1445  return res;
1446  }
1447  }
1448 
1449  throw formula_error("Unknown function: " + fn, "", "", 0);
1450 }
1451 
1452 std::set<std::string> function_symbol_table::get_function_names() const
1453 {
1454  std::set<std::string> res;
1455  if(parent) {
1456  res = parent->get_function_names();
1457  }
1458 
1459  for(const auto& formula : custom_formulas_) {
1460  res.insert(formula.first);
1461  }
1462 
1463  return res;
1464 }
1465 
1466 std::shared_ptr<function_symbol_table> function_symbol_table::get_builtins()
1467 {
1468  static function_symbol_table functions_table(builtins_tag);
1469 
1470  if(functions_table.empty()) {
1471  functions_table.parent = nullptr;
1472 
1473  using namespace builtins;
1475  DECLARE_WFL_FUNCTION(dir);
1477  DECLARE_WFL_FUNCTION(switch);
1478  DECLARE_WFL_FUNCTION(abs);
1479  DECLARE_WFL_FUNCTION(min);
1480  DECLARE_WFL_FUNCTION(max);
1481  DECLARE_WFL_FUNCTION(choose);
1482  DECLARE_WFL_FUNCTION(debug_float);
1483  DECLARE_WFL_FUNCTION(debug_print);
1484  DECLARE_WFL_FUNCTION(debug_profile);
1485  DECLARE_WFL_FUNCTION(wave);
1487  DECLARE_WFL_FUNCTION(contains_string);
1488  DECLARE_WFL_FUNCTION(find_string);
1490  DECLARE_WFL_FUNCTION(filter);
1492  DECLARE_WFL_FUNCTION(map);
1493  DECLARE_WFL_FUNCTION(zip);
1494  DECLARE_WFL_FUNCTION(take_while);
1495  DECLARE_WFL_FUNCTION(reduce);
1496  DECLARE_WFL_FUNCTION(sum);
1497  DECLARE_WFL_FUNCTION(head);
1498  DECLARE_WFL_FUNCTION(tail);
1500  DECLARE_WFL_FUNCTION(null);
1501  DECLARE_WFL_FUNCTION(ceil);
1502  DECLARE_WFL_FUNCTION(floor);
1503  DECLARE_WFL_FUNCTION(trunc);
1504  DECLARE_WFL_FUNCTION(frac);
1505  DECLARE_WFL_FUNCTION(sgn);
1506  DECLARE_WFL_FUNCTION(round);
1507  DECLARE_WFL_FUNCTION(as_decimal);
1508  DECLARE_WFL_FUNCTION(pair);
1509  DECLARE_WFL_FUNCTION(loc);
1511  DECLARE_WFL_FUNCTION(adjacent_locs);
1512  DECLARE_WFL_FUNCTION(are_adjacent);
1513  DECLARE_WFL_FUNCTION(relative_dir);
1514  DECLARE_WFL_FUNCTION(direction_from);
1515  DECLARE_WFL_FUNCTION(rotate_loc_around);
1516  DECLARE_WFL_FUNCTION(index_of);
1517  DECLARE_WFL_FUNCTION(keys);
1518  DECLARE_WFL_FUNCTION(values);
1519  DECLARE_WFL_FUNCTION(tolist);
1520  DECLARE_WFL_FUNCTION(tomap);
1521  DECLARE_WFL_FUNCTION(substring);
1522  DECLARE_WFL_FUNCTION(replace);
1523  DECLARE_WFL_FUNCTION(length);
1524  DECLARE_WFL_FUNCTION(concatenate);
1525  DECLARE_WFL_FUNCTION(sin);
1526  DECLARE_WFL_FUNCTION(cos);
1527  DECLARE_WFL_FUNCTION(tan);
1528  DECLARE_WFL_FUNCTION(asin);
1529  DECLARE_WFL_FUNCTION(acos);
1530  DECLARE_WFL_FUNCTION(atan);
1531  DECLARE_WFL_FUNCTION(sqrt);
1532  DECLARE_WFL_FUNCTION(cbrt);
1533  DECLARE_WFL_FUNCTION(root);
1534  DECLARE_WFL_FUNCTION(log);
1535  DECLARE_WFL_FUNCTION(exp);
1537  DECLARE_WFL_FUNCTION(hypot);
1539  }
1540 
1541  return std::shared_ptr<function_symbol_table>(&functions_table, [](function_symbol_table*) {});
1542 }
1543 
1545  : function_symbol_table(parent)
1546 {
1547  using namespace actions;
1548  function_symbol_table& functions_table = *this;
1549  DECLARE_WFL_FUNCTION(safe_call);
1550  DECLARE_WFL_FUNCTION(set_var);
1551 }
1552 }
const_formula_ptr formula_
Definition: function.hpp:204
const_formula_callable_ptr as_callable() const
Definition: variant.hpp:79
static DIRECTION parse_direction(const std::string &str)
Definition: location.cpp:64
static lg::log_domain log_engine("engine")
std::vector< char_t > string
std::vector< expression_ptr > args_list
Definition: function.hpp:100
variant b_
Definition: function.cpp:722
std::set< std::string > get_function_names() const
Definition: function.cpp:1452
#define DBG_NG
Definition: function.cpp:31
void set_fallback(const_formula_callable_ptr fallback)
Definition: callable.hpp:258
map_location rotate_right_around_center(const map_location &center, int k) const
Definition: location.cpp:305
Formula AI debugger.
#define a
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.hpp:299
int as_int() const
Definition: variant.cpp:298
formula_debugger * add_debug_info(formula_debugger *fdb, int arg_number, const std::string &f_name)
expression_ptr create_function(const std::string &fn, const std::vector< expression_ptr > &args) const
Definition: function.cpp:1434
#define LOG_SF
Definition: function.cpp:33
static lg::log_domain log_scripting_formula("scripting/formula")
std::vector< formula_input > formula_input_vector
variant_iterator end() const
Definition: variant.cpp:266
std::shared_ptr< formula_function > formula_function_ptr
Definition: function.hpp:224
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:225
const std::vector< std::string > items
#define d
std::shared_ptr< formula_expression > expression_ptr
Definition: formula.hpp:28
#define b
static std::ostream & output()
Definition: log.cpp:52
static int str_lower(lua_State *L)
Definition: lstrlib.cpp:96
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.hpp:339
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:252
bool as_bool() const
Returns a boolean state of the variant value.
Definition: variant.cpp:320
size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.hpp:382
std::shared_ptr< function_expression > function_expression_ptr
Definition: function.hpp:167
static std::shared_ptr< function_symbol_table > get_builtins()
Definition: function.cpp:1466
static int indent
Definition: log.cpp:45
Encapsulates the map of the game.
Definition: location.hpp:40
const_formula_ptr precondition_
Definition: function.hpp:205
void float_label(const map_location &loc, const std::string &text, const color_t &color)
Function to float a label above a tile.
size_t size(const utf8::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
std::shared_ptr< function_symbol_table > parent
Definition: function.hpp:246
function_symbol_table(std::shared_ptr< function_symbol_table > parent=nullptr)
Definition: function.cpp:1424
std::string string_cast() const
Definition: variant.cpp:644
bool is_empty() const
Definition: variant.cpp:271
function_expression_ptr generate_function_expression(const std::vector< expression_ptr > &args) const
Definition: function.cpp:1418
int as_decimal() const
Returns variant's internal representation of decimal number: ie, 1.234 is represented as 1234...
Definition: variant.cpp:307
variant get_keys() const
Definition: variant.cpp:237
action_function_symbol_table(std::shared_ptr< function_symbol_table > parent=nullptr)
Definition: function.cpp:1544
EXIT_STATUS start(const config &game_conf, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:28
int main()
static void expr(LexState *ls, expdesc *v)
Definition: lparser.cpp:1078
const args_list & args() const
Definition: function.hpp:118
static map_location::DIRECTION s
size_t i
Definition: function.cpp:933
CURSOR_TYPE get()
Definition: cursor.cpp:194
const_formula_ptr precondition_
Definition: function.hpp:160
#define debug(x)
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:23
static int sort(lua_State *L)
Definition: ltablib.cpp:411
variant a_
Definition: function.cpp:722
static int str_upper(lua_State *L)
Definition: lstrlib.cpp:109
std::vector< std::string > arg_names_
Definition: function.hpp:162
bool is_list() const
Definition: variant.hpp:62
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:58
#define DECLARE_WFL_FUNCTION(name)
Declares a function name in the local function table functions_table.
Definition: function.hpp:47
variant evaluate(const formula_callable &variables, formula_debugger *fdb=nullptr) const
Definition: function.hpp:70
const formula_callable * fallback_
Definition: function.cpp:721
display_chat_manager & get_chat_manager()
std::string type_string() const
Gets string name of the current value type.
Definition: variant.hpp:144
bool is_map() const
Definition: variant.hpp:64
#define f
Definition: contexts.hpp:42
bool find(E event, F functor)
Tests whether an event handler is available.
size_t num_elements() const
Definition: variant.cpp:276
#define DEFINE_WFL_FUNCTION(name, min_args, max_args)
Helper macro to declare an associated class for a WFL function.
Definition: function.hpp:27
Standard logging facilities (interface).
bool is_string() const
Definition: variant.hpp:63
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:649
void add_function(const std::string &name, formula_function_ptr &&fcn)
Definition: function.cpp:1429
bool is_decimal() const
Definition: variant.hpp:60
map_location get_direction(DIRECTION d, unsigned int n=1u) const
Definition: location.hpp:257
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
variant_iterator begin() const
Definition: variant.cpp:261
utf8::string & insert(utf8::string &str, const size_t pos, const utf8::string &insert)
Insert a UTF-8 string at the specified position.
Definition: unicode.cpp:99
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
std::shared_ptr< T > convert_to() const
Definition: variant.hpp:96
Iterator class for the variant.
Definition: variant.hpp:182
variant get_values() const
Definition: variant.cpp:249
void add_chat_message(const time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
variant execute(const formula_callable &variables, formula_debugger *fdb) const
Definition: function.cpp:1379
functions_map custom_formulas_
Definition: function.hpp:247
static map_location::DIRECTION n
static std::string write_direction(DIRECTION dir)
Definition: location.cpp:139
static std::deque< std::string > call_stack
Definition: function.cpp:39
expression_ptr expr_
Definition: function.cpp:720
static game_display * get_singleton()
std::vector< std::string > args_
Definition: function.hpp:206