The Battle for Wesnoth  1.17.4+dev
callable_objects.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2022
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "formula/callable_objects.hpp"
17 
18 #include "config.hpp"
19 #include "formula/function.hpp"
20 #include "map/map.hpp"
21 #include "display_context.hpp"
22 #include "team.hpp"
23 #include "units/attack_type.hpp"
25 #include "units/unit.hpp"
26 #include "units/types.hpp"
27 #include "log.hpp"
28 #include "recall_list_manager.hpp"
29 #include "deprecation.hpp"
30 #include "game_board.hpp"
31 #include "game_version.hpp"
32 #include "resources.hpp"
33 
34 static lg::log_domain log_scripting_formula("scripting/formula");
35 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
36 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
37 
38 namespace wfl
39 {
40 
41 variant location_callable::get_value(const std::string& key) const
42 {
43  if(key == "x") {
44  return variant(loc_.wml_x());
45  } else if(key == "y") {
46  return variant(loc_.wml_y());
47  }
48 
49  return variant();
50 }
51 
53 {
54  add_input(inputs, "x");
55  add_input(inputs, "y");
56 }
57 
59 {
60  const location_callable* loc_callable = dynamic_cast<const location_callable*>(callable);
61  if(loc_callable == nullptr) {
62  return formula_callable::do_compare(callable);
63  }
64 
65  const map_location& other_loc = loc_callable->loc();
66  return loc_.do_compare(other_loc);
67 }
68 
69 void location_callable::serialize_to_string(std::string& str) const
70 {
71  std::ostringstream s;
72  s << "loc(" << (loc_.wml_x()) << "," << (loc_.wml_y()) << ")";
73  str += s.str();
74 }
75 
76 attack_type_callable::attack_type_callable(const attack_type& attack) : att_(attack.shared_from_this())
77 {
79 }
80 
81 variant attack_type_callable::get_value(const std::string& key) const
82 {
83  if(key == "id" || key == "name") {
84  return variant(att_->id());
85  } else if(key == "description") {
86  return variant(att_->name());
87  } else if(key == "type") {
88  return variant(att_->type());
89  } else if(key == "icon") {
90  return variant(att_->icon());
91  } else if(key == "range") {
92  return variant(att_->range());
93  } else if(key == "damage") {
94  return variant(att_->damage());
95  } else if(key == "number_of_attacks" || key == "number" || key == "num_attacks" || key == "attacks") {
96  return variant(att_->num_attacks());
97  } else if(key == "attack_weight") {
98  return variant(att_->attack_weight(), variant::DECIMAL_VARIANT);
99  } else if(key == "defense_weight") {
100  return variant(att_->defense_weight(), variant::DECIMAL_VARIANT);
101  } else if(key == "accuracy") {
102  return variant(att_->accuracy());
103  } else if(key == "parry") {
104  return variant(att_->parry());
105  } else if(key == "movement_used") {
106  return variant(att_->movement_used());
107  } else if(key == "specials" || key == "special") {
108  std::vector<variant> res;
109 
110  for(const auto special : att_->specials().all_children_range()) {
111  if(!special.cfg["id"].empty()) {
112  res.emplace_back(special.cfg["id"].str());
113  }
114  }
115  return variant(res);
116  }
117 
118  return variant();
119 }
120 
122 {
123  add_input(inputs, "name");
124  add_input(inputs, "type");
125  add_input(inputs, "description");
126  add_input(inputs, "icon");
127  add_input(inputs, "range");
128  add_input(inputs, "damage");
129  add_input(inputs, "number");
130  add_input(inputs, "accuracy");
131  add_input(inputs, "parry");
132  add_input(inputs, "movement_used");
133  add_input(inputs, "attack_weight");
134  add_input(inputs, "defense_weight");
135  add_input(inputs, "specials");
136 }
137 
139 {
140  const attack_type_callable* att_callable = dynamic_cast<const attack_type_callable*>(callable);
141  if(att_callable == nullptr) {
142  return formula_callable::do_compare(callable);
143  }
144 
145  if(att_->damage() != att_callable->att_->damage()) {
146  return att_->damage() - att_callable->att_->damage();
147  }
148 
149  if(att_->num_attacks() != att_callable->att_->num_attacks()) {
150  return att_->num_attacks() - att_callable->att_->num_attacks();
151  }
152 
153  if(att_->id() != att_callable->att_->id()) {
154  return att_->id().compare(att_callable->att_->id());
155  }
156 
157  if(att_->type() != att_callable->att_->type()) {
158  return att_->type().compare(att_callable->att_->type());
159  }
160 
161  if(att_->range() != att_callable->att_->range()) {
162  return att_->range().compare(att_callable->att_->range());
163  }
164 
165  const auto self_specials = att_->specials().all_children_range();
166  const auto other_specials = att_callable->att_->specials().all_children_range();
167  if(self_specials.size() != other_specials.size()) {
168  return self_specials.size() < other_specials.size() ? -1 : 1;
169  }
170  for(std::size_t i = 0; i < self_specials.size(); ++i) {
171  const auto& s = self_specials[i].cfg["id"];
172  const auto& o = other_specials[i].cfg["id"];
173  if(s != o) {
174  return s.str().compare(o.str());
175  }
176  }
177 
178  return 0;
179 }
180 
182 {
183  type_ = UNIT_C;
184 }
185 
186 variant unit_callable::get_value(const std::string& key) const
187 {
188  if(key == "x") {
190  return variant();
191  }
192 
193  return variant(loc_.wml_x());
194  } else if(key == "y") {
196  return variant();
197  }
198 
199  return variant(loc_.wml_y());
200  } else if(key == "loc") {
202  return variant();
203  }
204 
205  return variant(std::make_shared<location_callable>(loc_));
206  } else if(key == "terrain") {
208  return variant();
209  }
210  return variant(std::make_shared<terrain_callable>(*resources::gameboard, loc_));
211  } else if(key == "id") {
212  return variant(u_.id());
213  } else if(key == "type") {
214  return variant(u_.type_id());
215  } else if(key == "name") {
216  return variant(u_.name());
217  } else if(key == "usage") {
218  return variant(u_.usage());
219  } else if(key == "leader" || key == "canrecruit") {
220  return variant(u_.can_recruit());
221  } else if(key == "undead") {
222  return variant(u_.get_state("not_living") ? 1 : 0);
223  } else if(key == "attacks") {
224  std::vector<variant> res;
225  for(const attack_type& att : u_.attacks()) {
226  res.emplace_back(std::make_shared<attack_type_callable>(att));
227  }
228 
229  return variant(res);
230  } else if(key == "abilities") {
232  } else if(key == "hitpoints") {
233  return variant(u_.hitpoints());
234  } else if(key == "max_hitpoints") {
235  return variant(u_.max_hitpoints());
236  } else if(key == "experience") {
237  return variant(u_.experience());
238  } else if(key == "max_experience") {
239  return variant(u_.max_experience());
240  } else if(key == "level" || key == "full") {
241  // This allows writing "upkeep == full"
242  return variant(u_.level());
243  } else if(key == "total_movement" || key == "max_moves") {
244  return variant(u_.total_movement());
245  } else if(key == "movement_left" || key == "moves") {
246  return variant(u_.movement_left());
247  } else if(key == "attacks_left") {
248  return variant(u_.attacks_left());
249  } else if(key == "max_attacks") {
250  return variant(u_.max_attacks());
251  } else if(key == "traits") {
253  } else if(key == "extra_recruit") {
255  } else if(key == "advances_to") {
257  } else if(key == "states" || key == "status") {
259  } else if(key == "side") {
260  deprecated_message("unit.side", DEP_LEVEL::FOR_REMOVAL, version_info("1.17"), "This returns 0 for side 1 etc and should not be used. Use side_number instead.");
261  return variant(u_.side()-1);
262  } else if(key == "side_number") {
263  return variant(u_.side());
264  } else if(key == "cost") {
265  return variant(u_.cost());
266  } else if(key == "upkeep") {
267  return variant(u_.upkeep());
268  } else if(key == "loyal") {
269  // So we can write "upkeep == loyal"
270  return variant(0);
271  } else if(key == "hidden") {
272  return variant(u_.get_hidden());
273  } else if(key == "petrified") {
274  return variant(u_.incapacitated());
275  } else if(key == "resting") {
276  return variant(u_.resting());
277  } else if(key == "role") {
278  return variant(u_.get_role());
279  } else if(key == "race") {
280  return variant(u_.race()->id());
281  } else if(key == "gender") {
282  return variant(gender_string(u_.gender()));
283  } else if(key == "variation") {
284  return variant(u_.variation());
285  } else if(key == "zoc") {
286  return variant(u_.get_emit_zoc());
287  } else if(key == "alignment") {
289  } else if(key == "facing") {
291  } else if(key == "resistance" || key == "movement_cost" || key == "vision_cost" || key == "jamming_cost" || key == "defense") {
292  const auto& mt = u_.movement_type();
293  config cfg;
294  bool needs_flip = false;
295  if(key == "resistance") {
296  mt.get_resistances().write(cfg);
297  needs_flip = true;
298  } else if(key == "movement_cost") {
299  mt.get_movement().write(cfg);
300  } else if(key == "vision_cost") {
301  mt.get_vision().write(cfg);
302  } else if(key == "jamming_cost") {
303  mt.get_vision().write(cfg);
304  } else if(key == "defense") {
305  mt.get_defense().write(cfg);
306  needs_flip = true;
307  }
308  std::map<variant, variant> res;
309  for(const auto& p : cfg.attribute_range()) {
310  int val = p.second;
311  if(needs_flip) {
312  val = 100 - val;
313  }
314  res.emplace(variant(p.first), variant(val));
315  }
316 
317  return variant(res);
318  } else if(key == "flying") {
319  return variant(u_.is_flying());
320  } else if(key == "vars") {
323  }
324 
325  return variant();
326  } else if(key == "wml_vars") {
327  return variant(std::make_shared<config_callable>(u_.variables()));
328  } else if(key == "n" || key == "s" || key == "ne" || key == "se" || key == "nw" || key == "sw" ||
329  key == "lawful" || key == "neutral" || key == "chaotic" || key == "liminal" ||
330  key == "male" || key == "female")
331  {
332  return variant(key);
333  }
334 
335  return variant();
336 }
337 
339 {
340  add_input(inputs, "x");
341  add_input(inputs, "y");
342  add_input(inputs, "loc");
343  add_input(inputs, "terrain");
344  add_input(inputs, "id");
345  add_input(inputs, "type");
346  add_input(inputs, "name");
347  add_input(inputs, "canrecruit");
348  add_input(inputs, "undead");
349  add_input(inputs, "traits");
350  add_input(inputs, "attacks");
351  add_input(inputs, "abilities");
352  add_input(inputs, "hitpoints");
353  add_input(inputs, "max_hitpoints");
354  add_input(inputs, "experience");
355  add_input(inputs, "max_experience");
356  add_input(inputs, "level");
357  add_input(inputs, "moves");
358  add_input(inputs, "max_moves");
359  add_input(inputs, "attacks_left");
360  add_input(inputs, "max_attacks");
361  add_input(inputs, "side_number");
362  add_input(inputs, "extra_recruit");
363  add_input(inputs, "advances_to");
364  add_input(inputs, "status");
365  add_input(inputs, "cost");
366  add_input(inputs, "usage");
367  add_input(inputs, "upkeep");
368  add_input(inputs, "hidden");
369  add_input(inputs, "petrified");
370  add_input(inputs, "resting");
371  add_input(inputs, "role");
372  add_input(inputs, "race");
373  add_input(inputs, "gender");
374  add_input(inputs, "variation");
375  add_input(inputs, "zoc");
376  add_input(inputs, "alignment");
377  add_input(inputs, "facing");
378  add_input(inputs, "resistance");
379  add_input(inputs, "movement_cost");
380  add_input(inputs, "vision_cost");
381  add_input(inputs, "jamming_cost");
382  add_input(inputs, "defense");
383  add_input(inputs, "flying");
384  add_input(inputs, "vars");
385  add_input(inputs, "wml_vars");
386 }
387 
388 int unit_callable::do_compare(const formula_callable* callable) const
389 {
390  const unit_callable* u_callable = dynamic_cast<const unit_callable*>(callable);
391  if(u_callable == nullptr) {
392  return formula_callable::do_compare(callable);
393  }
394 
395  return u_.underlying_id() - u_callable->u_.underlying_id();
396 }
397 
398 variant unit_type_callable::get_value(const std::string& key) const
399 {
400  if(key == "id") {
401  return variant(u_.id());
402  } else if(key == "type") {
403  return variant(u_.type_name());
404  } else if(key == "alignment") {
406  } else if(key == "race") {
407  return variant(u_.race_id());
408  } else if(key == "abilities") {
410  } else if(key == "traits") {
411  std::vector<variant> res;
412  for(const auto& config : u_.possible_traits()) {
413  res.emplace_back(config["id"].str());
414  }
415 
416  return variant(res);
417  } else if(key == "attacks") {
418  std::vector<variant> res;
419  for(const attack_type& att : u_.attacks()) {
420  res.emplace_back(std::make_shared<attack_type_callable>(att));
421  }
422 
423  return variant(res);
424  } else if(key == "hitpoints" || key == "max_hitpoints") {
425  return variant(u_.hitpoints());
426  } else if(key == "experience" || key == "max_experience") {
427  return variant(u_.experience_needed(true));
428  } else if(key == "level") {
429  return variant(u_.level());
430  } else if(key == "total_movement" || key == "max_moves" || key == "moves") {
431  return variant(u_.movement());
432  } else if(key == "unpoisonable") {
433  return variant(u_.musthave_status("unpoisonable"));
434  } else if(key == "unslowable") {
435  return variant(u_.musthave_status("unslowable"));
436  } else if(key == "unpetrifiable") {
437  return variant(u_.musthave_status("unpetrifiable"));
438  } else if(key == "undrainable") {
439  return variant(u_.musthave_status("undrainable"));
440  } else if(key == "unplagueable") {
441  return variant(u_.musthave_status("unplagueable"));
442  } else if(key == "cost") {
443  return variant(u_.cost());
444  } else if(key == "recall_cost") {
445  return variant(u_.recall_cost());
446  } else if(key == "usage") {
447  return variant(u_.usage());
448  }
449 
450  return variant();
451 }
452 
454 {
455  add_input(inputs, "id");
456  add_input(inputs, "type");
457  add_input(inputs, "race");
458  add_input(inputs, "alignment");
459  add_input(inputs, "abilities");
460  add_input(inputs, "traits");
461  add_input(inputs, "attacks");
462  add_input(inputs, "hitpoints");
463  add_input(inputs, "experience");
464  add_input(inputs, "level");
465  add_input(inputs, "total_movement");
466  add_input(inputs, "undead");
467  add_input(inputs, "cost");
468  add_input(inputs, "recall_cost");
469  add_input(inputs, "usage");
470 }
471 
473 {
474  const unit_type_callable* u_callable = dynamic_cast<const unit_type_callable*>(callable);
475  if(u_callable == nullptr) {
476  return formula_callable::do_compare(callable);
477  }
478 
479  return u_.id().compare(u_callable->u_.id());
480 }
481 
483 #ifdef USING_BOOST_VARIANT
484  : public boost::static_visitor<variant>
485 #endif
486 {
487  variant operator()(bool b) const { return variant(b ? 1 : 0); }
488  variant operator()(int i) const { return variant(i); }
489  variant operator()(unsigned long long i) const { return variant(i); }
490  variant operator()(double i) const { return variant(i * 1000, variant::DECIMAL_VARIANT); }
491  // TODO: Should comma-separated lists of stuff be returned as a list?
492  // The challenge is to distinguish them from ordinary strings that happen to contain a comma
493  // (or should we assume that such strings will be translatable?).
494  variant operator()(const std::string& s) const { return variant(s); }
495  variant operator()(const t_string& s) const { return variant(s.str()); }
496  variant operator()(utils::monostate) const { return variant(); }
497 };
498 
499 variant config_callable::get_value(const std::string& key) const
500 {
501  if(cfg_.has_attribute(key)) {
502  return cfg_[key].apply_visitor(fai_variant_visitor());
503  } else if(cfg_.has_child(key)) {
504  std::vector<variant> result;
505  for(const auto& child : cfg_.child_range(key)) {
506  result.emplace_back(std::make_shared<config_callable>(child));
507  }
508 
509  return variant(result);
510  } else if(key == "__all_children") {
511  std::vector<variant> result;
512  for(const auto child : cfg_.all_children_range()) {
513  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
514  const variant kv(std::make_shared<key_value_pair>(variant(child.key), cfg_child));
515  result.push_back(kv);
516  }
517 
518  return variant(result);
519  } else if(key == "__children") {
520  std::map<std::string, std::vector<variant>> build;
521  for(const auto child : cfg_.all_children_range()) {
522  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
523  build[child.key].push_back(cfg_child);
524  }
525 
526  std::map<variant,variant> result;
527  for(auto& p : build) {
528  result[variant(p.first)] = variant(p.second);
529  }
530 
531  return variant(result);
532  } else if(key == "__attributes") {
533  std::map<variant,variant> result;
534  for(const auto& val : cfg_.attribute_range()) {
535  result[variant(val.first)] = val.second.apply_visitor(fai_variant_visitor());
536  }
537 
538  return variant(result);
539  }
540 
541  return variant();
542 }
543 
545 {
546  add_input(inputs, "__all_children");
547  add_input(inputs, "__children");
548  add_input(inputs, "__attributes");
549 
550  for(const auto& val : cfg_.attribute_range()) {
551  if(val.first.find_first_not_of(formula::id_chars) != std::string::npos) {
552  add_input(inputs, val.first);
553  }
554  }
555 }
556 
558 {
559  const config_callable* cfg_callable = dynamic_cast<const config_callable*>(callable);
560  if(cfg_callable == nullptr) {
561  return formula_callable::do_compare(callable);
562  }
563 
564  if(cfg_ == cfg_callable->get_config()) {
565  return 0;
566  }
567 
568  return cfg_.hash().compare(cfg_callable->get_config().hash());
569 }
570 
571 terrain_callable::terrain_callable(const display_context& dc, const map_location& loc) : loc_(loc), t_(dc.map().get_terrain_info(loc)), owner_(dc.village_owner(loc))
572 {
573  type_ = TERRAIN_C;
574 }
575 
576 variant terrain_callable::get_value(const std::string& key) const
577 {
578  if(key == "x") {
579  return variant(loc_.wml_x());
580  } else if(key == "y") {
581  return variant(loc_.wml_y());
582  } else if(key == "loc") {
583  return variant(std::make_shared<location_callable>(loc_));
584  } else if(key == "id") {
585  return variant(std::string(t_.id()));
586  } else if(key == "name") {
587  return variant(t_.name());
588  } else if(key == "editor_name") {
589  return variant(t_.editor_name());
590  } else if(key == "description") {
591  return variant(t_.description());
592  } else if(key == "icon") {
593  return variant(t_.icon_image());
594  } else if(key == "light") {
595  return variant(t_.light_bonus(0));
596  } else if(key == "village") {
597  return variant(t_.is_village());
598  } else if(key == "castle") {
599  return variant(t_.is_castle());
600  } else if(key == "keep") {
601  return variant(t_.is_keep());
602  } else if(key == "healing") {
603  return variant(t_.gives_healing());
604  } else if(key == "owner") {
605  deprecated_message("terrain.owner", DEP_LEVEL::FOR_REMOVAL, version_info("1.17"), "This returns 0 for side 1 etc and should not be used. Use owner_side instead.");
606  return variant(owner_ - 1);
607  } else if(key == "owner_side") {
608  return variant(owner_);
609  }
610 
611  return variant();
612 }
613 
615 {
616  add_input(inputs, "x");
617  add_input(inputs, "y");
618  add_input(inputs, "loc");
619  add_input(inputs, "id");
620  add_input(inputs, "name");
621  add_input(inputs, "editor_name");
622  add_input(inputs, "description");
623  add_input(inputs, "icon");
624  add_input(inputs, "light");
625  add_input(inputs, "village");
626  add_input(inputs, "castle");
627  add_input(inputs, "keep");
628  add_input(inputs, "healing");
629  add_input(inputs, "owner_side");
630 }
631 
633 {
634  const terrain_callable* terr_callable = dynamic_cast<const terrain_callable*>(callable);
635  if(terr_callable == nullptr) {
636  return formula_callable::do_compare(callable);
637  }
638 
639  const map_location& other_loc = terr_callable->loc_;
640  return loc_.do_compare(other_loc);
641 }
642 
644  return board_.map();
645 }
646 
648 {
649  add_input(inputs, "w");
650  add_input(inputs, "h");
651 }
652 
653 variant gamemap_callable::get_value(const std::string& key) const
654 {
655  if(key == "terrain") {
656  int w = get_gamemap().w();
657  int h = get_gamemap().h();
658 
659  std::vector<variant> vars;
660  for(int i = 0; i < w; i++) {
661  for(int j = 0; j < h; j++) {
662  const map_location loc(i, j);
663  vars.emplace_back(std::make_shared<terrain_callable>(board_, loc));
664  }
665  }
666 
667  return variant(vars);
668  } else if(key == "gamemap") {
669  int w = get_gamemap().w();
670  int h = get_gamemap().h();
671 
672  std::map<variant, variant> vars;
673  for(int i = 0; i < w; i++) {
674  for(int j = 0; j < h; j++) {
675  const map_location loc(i, j);
676  vars.emplace(std::make_shared<location_callable>(loc), std::make_shared<terrain_callable>(board_, loc));
677  }
678  }
679 
680  return variant(vars);
681  } else if(key == "w") {
682  return variant(get_gamemap().w());
683  } else if(key == "h") {
684  return variant(get_gamemap().h());
685  } else {
686  return variant();
687  }
688 }
689 
691 {
692  add_input(inputs, "side_number");
693  add_input(inputs, "id");
694  add_input(inputs, "gold");
695  add_input(inputs, "start_gold");
696  add_input(inputs, "base_income");
697  add_input(inputs, "total_income");
698  add_input(inputs, "village_gold");
699  add_input(inputs, "village_support");
700  add_input(inputs, "recall_cost");
701  add_input(inputs, "name");
702  add_input(inputs, "is_human");
703  add_input(inputs, "is_ai");
704  add_input(inputs, "is_network");
705  add_input(inputs, "fog");
706  add_input(inputs, "shroud");
707  add_input(inputs, "hidden");
708  add_input(inputs, "flag");
709  add_input(inputs, "flag_icon");
710  add_input(inputs, "team_name");
711  add_input(inputs, "faction");
712  add_input(inputs, "faction_name");
713  add_input(inputs, "color");
714  add_input(inputs, "share_vision");
715  add_input(inputs, "carryover_bonus");
716  add_input(inputs, "carryover_percentage");
717  add_input(inputs, "carryover_add");
718  add_input(inputs, "recruit");
719  add_input(inputs, "wml_vars");
720 }
721 
722 variant team_callable::get_value(const std::string& key) const
723 {
724  if(key == "side") {
725  deprecated_message("team.side", DEP_LEVEL::INDEFINITE, version_info("1.17"), "Use side_number instead.");
726  return variant(team_.side());
727  } else if(key == "side_number") {
728  return variant(team_.side());
729  } else if(key == "id") {
730  return variant(team_.save_id());
731  } else if(key == "save_id") {
732  return variant(team_.save_id());
733  } else if(key == "gold") {
734  return variant(team_.gold());
735  } else if(key == "start_gold") {
736  return variant(team_.start_gold());
737  } else if(key == "base_income") {
738  return variant(team_.base_income());
739  } else if(key == "total_income") {
740  return variant(team_.total_income());
741  } else if(key == "village_gold") {
742  return variant(team_.village_gold());
743  } else if(key == "village_support") {
744  return variant(team_.village_support());
745  } else if(key == "recall_cost") {
746  return variant(team_.recall_cost());
747  } else if(key == "is_human") {
748  return variant(team_.is_local_human());
749  } else if(key == "is_ai") {
750  return variant(team_.is_local_ai());
751  } else if(key == "is_network") {
752  return variant(team_.is_network());
753  } else if(key == "fog") {
754  return variant(team_.uses_fog());
755  } else if(key == "shroud") {
756  return variant(team_.uses_shroud());
757  } else if(key == "hidden") {
758  return variant(team_.hidden());
759  } else if(key == "flag") {
760  return variant(team_.flag());
761  } else if(key == "flag_icon") {
762  return variant(team_.flag_icon());
763  } else if(key == "team_name") {
764  return variant(team_.team_name());
765  } else if(key == "color") {
766  return variant(team_.color());
767  } else if(key == "share_vision") {
768  return variant(team_shared_vision::get_string(team_.share_vision()));
769  } else if(key == "carryover_bonus") {
770  return variant(team_.carryover_bonus(), variant::DECIMAL_VARIANT);
771  } else if(key == "carryover_percentage") {
772  return variant(team_.carryover_percentage());
773  } else if(key == "carryover_add") {
774  return variant(team_.carryover_add());
775  } else if(key == "recruit") {
776  std::vector<variant> result;
777  for(const auto& recruit : team_.recruits()) {
778  result.emplace_back(recruit);
779  }
780  return variant(result);
781  } else if(key == "recall") {
782  std::vector<variant> result;
783  for(const auto& u : team_.recall_list()) {
784  result.push_back(std::make_shared<unit_callable>(*u));
785  }
786  return variant(result);
787  } else if(key == "wml_vars") {
788  return variant(std::make_shared<config_callable>(team_.variables()));
789  }
790 
791  return variant();
792 }
793 
794 variant set_var_callable::get_value(const std::string& key) const
795 {
796  if(key == "key") {
797  return variant(key_);
798  } else if(key == "value") {
799  return value_;
800  }
801 
802  return variant();
803 }
804 
806 {
807  add_input(inputs, "key");
808  add_input(inputs, "value");
809 }
810 
812 {
813  //if(infinite_loop_guardian_.set_var_check()) {
814  if(auto obj = ctxt.try_convert<formula_callable>()) {
815  LOG_SF << "Setting variable: " << key_ << " -> " << value_.to_debug_string() << "\n";
816  obj->mutate_value(key_, value_);
817  return variant(true);
818  }
819  //}
820  //too many calls in a row - possible infinite loop
821  ERR_SF << "ERROR #" << 5001 << " while executing 'set_var' formula function" << std::endl;
822 
823  return variant(std::make_shared<safe_call_result>(fake_ptr(), 5001));
824 }
825 
826 variant safe_call_callable::get_value(const std::string& key) const
827 {
828  if(key == "main") {
829  return variant(main_);
830  } else if(key == "backup") {
831  return variant(backup_);
832  }
833 
834  return variant();
835 }
836 
838 {
839  add_input(inputs, "main");
840  add_input(inputs, "backup");
841 }
842 
844 {
845  variant res;
846  if(auto action = main_.try_convert<action_callable>()) {
847  res = action->execute_self(ctxt);
848  }
849 
850  if(res.try_convert<safe_call_result>()) {
851  /* If we have safe_call formula and either an error occurred, or the current action
852  * was not recognized, then evaluate backup formula from safe_call and execute it
853  * during the next loop
854  */
855 
856  map_formula_callable callable(ctxt.as_callable());
857  callable.add("error", res);
858 
859  /* Store the result in safe_call_callable in case we would like to display it to the user,
860  * for example if this formula was executed from the commandline.
861  */
862  backup_ = get_backup()->evaluate(callable);
863  ctxt.execute_variant(backup_);
864  }
865  return variant(true);
866 }
867 
868 variant safe_call_result::get_value(const std::string& key) const
869 {
870  if(key == "status") {
871  return variant(status_);
872  } else if(key == "object") {
873  if(failed_callable_) {
874  return variant(failed_callable_);
875  }
876 
877  return variant();
878  } else if(key == "current_loc" && current_unit_location_ != map_location()) {
879  return variant(std::make_shared<location_callable>(current_unit_location_));
880  }
881 
882  return variant();
883 }
884 
886 {
887  add_input(inputs, "status");
888  add_input(inputs, "object");
889 
890  if(current_unit_location_ != map_location()) {
891  add_input(inputs, "current_loc");
892  }
893 }
894 
895 } // namespace wfl
const map_location & loc() const
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:656
variant get_value(const std::string &key) const override
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:982
bool is_castle() const
Definition: terrain.hpp:142
void get_inputs(formula_input_vector &inputs) const override
const t_string & description() const
Definition: terrain.hpp:50
void get_inputs(formula_input_vector &inputs) const override
This class represents a single unit of a specific type.
Definition: unit.hpp:120
const std::string & type_id() const
The id of this unit&#39;s type.
Definition: unit.cpp:1804
variant get_value(const std::string &key) const override
Interfaces for manipulating version numbers of engine, add-ons, etc.
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1454
const std::string & id() const
Definition: race.hpp:35
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1314
variant get_value(const std::string &key) const override
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:455
const movetype & movement_type() const
Get the unit&#39;s movement type.
Definition: unit.hpp:1418
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:489
config & variables()
Gets any user-defined variables this unit &#39;owns&#39;.
Definition: unit.hpp:693
const wfl::map_formula_callable_ptr & formula_vars() const
int do_compare(const map_location &a) const
three-way comparator
Definition: location.hpp:105
const std::string & variation() const
The ID of the variation of this unit&#39;s type.
Definition: unit.hpp:562
int wml_x() const
Definition: location.hpp:153
std::vector< formula_input > formula_input_vector
map_location::DIRECTION facing() const
The current direction this unit is facing within its hex.
Definition: unit.hpp:1361
void get_inputs(formula_input_vector &inputs) const override
static variant convert_set(const std::set< T > &input_set)
Definition: callable.hpp:115
#define h
#define ERR_SF
void get_inputs(formula_input_vector &inputs) const override
bool resting() const
Checks whether this unit is &#39;resting&#39;.
Definition: unit.hpp:1314
void get_inputs(formula_input_vector &inputs) const override
bool get_emit_zoc() const
Gets the raw zone-of-control flag, disregarding incapacitated.
Definition: unit.hpp:1332
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition: unit.hpp:710
Definitions for the interface to Wesnoth Markup Language (WML).
int cost() const
How much gold is required to recruit this unit.
Definition: unit.hpp:623
const_attr_itors attribute_range() const
Definition: config.cpp:858
static lg::log_domain log_scripting_formula("scripting/formula")
variant operator()(const t_string &s) const
map_location loc_
#define b
bool is_village() const
Definition: terrain.hpp:141
variant operator()(int i) const
variant get_value(const std::string &key) const override
int light_bonus(int base) const
Returns the light (lawful) bonus for this terrain when the time of day gives a base bonus...
Definition: terrain.hpp:132
void get_inputs(formula_input_vector &inputs) const override
variant execute_self(variant ctxt) override
const t_string & editor_name() const
Definition: terrain.hpp:49
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:370
int do_compare(const formula_callable *callable) const override
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:30
const config & get_config() const
attack_type_callable(const attack_type &attack)
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
int wml_y() const
Definition: location.hpp:154
int do_compare(const formula_callable *callable) const override
game_board * gameboard
Definition: resources.cpp:21
Encapsulates the map of the game.
Definition: map.hpp:171
int do_compare(const formula_callable *callable) const override
const t_string & name() const
Gets this unit&#39;s translatable display name.
Definition: unit.hpp:393
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
Definition: unit.cpp:1593
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:519
int level() const
The current level of this unit.
Definition: unit.hpp:549
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:144
void serialize_to_string(std::string &str) const override
const t_string & type_name() const
Gets the translatable name of this unit&#39;s type.
Definition: unit.hpp:359
int gives_healing() const
Definition: terrain.hpp:140
variant get_value(const std::string &key) const override
unit_alignments::type alignment() const
The alignment of this unit.
Definition: unit.hpp:465
void get_inputs(formula_input_vector &inputs) const override
const map_location & loc_
variant get_value(const std::string &key) const override
const std::string & gender_string(unit_race::GENDER gender)
Definition: race.cpp:142
void get_inputs(formula_input_vector &inputs) const override
bool is_keep() const
Definition: terrain.hpp:143
#define LOG_SF
Encapsulates the map of the game.
Definition: location.hpp:38
const_formula_callable_ptr as_callable() const
Definition: variant.hpp:83
const gamemap & get_gamemap() const
variant operator()(bool b) const
std::size_t i
Definition: function.cpp:967
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:495
const std::string & get_role() const
Gets this unit&#39;s role.
Definition: unit.hpp:659
variant operator()(double i) const
mock_party p
static std::string get_location(const std::string &loc)
int do_compare(const formula_callable *callable) const override
static map_location::DIRECTION s
void get_inputs(formula_input_vector &inputs) const override
static std::string get_string(typename T::type key)
Uses the int value of the provided enum to get the associated index of the values array in the implem...
Definition: enum_base.hpp:41
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
const map_location loc_
variant operator()(const std::string &s) const
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:602
std::string usage() const
Gets this unit&#39;s usage.
Definition: unit.hpp:676
variant get_value(const std::string &key) const override
attack_itors attacks()
Gets an iterator over this unit&#39;s attacks.
Definition: unit.hpp:915
unit_callable(const map_location &loc, const unit &u)
variant operator()(utils::monostate) const
const terrain_type & t_
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
Definition: unit.cpp:859
int w
const unit_race * race() const
Gets this unit&#39;s race.
Definition: unit.hpp:483
variant get_value(const std::string &key) const override
formula_input_vector inputs() const
Definition: callable.hpp:63
Represents version numbers.
const t_string & name() const
Definition: terrain.hpp:48
const std::vector< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
Definition: unit.hpp:614
static const char *const id_chars
Definition: formula.hpp:75
unit_formula_manager & formula_manager() const
Get the unit formula manager.
Definition: unit.hpp:1801
std::shared_ptr< T > try_convert() const
Definition: variant.hpp:90
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:513
Definition: contexts.hpp:44
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
Standard logging facilities (interface).
const std::string & id() const
Definition: terrain.hpp:52
static variant convert_vector(const std::vector< T > &input_vector)
Definition: callable.hpp:126
variant execute_self(variant ctxt) override
static const map_location & null_location()
Definition: location.hpp:81
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:893
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1254
terrain_callable(const display_context &m, const map_location &loc)
int side() const
The side this unit belongs to.
Definition: unit.hpp:333
std::unique_ptr< window > build(const builder_window::window_resolution &definition)
Builds a window.
std::vector< std::string > get_ability_list() const
Get a list of all abilities by ID.
Definition: abilities.cpp:243
void get_inputs(formula_input_vector &inputs) const override
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
virtual int do_compare(const formula_callable *callable) const
Definition: callable.hpp:146
const std::string & str() const
Definition: tstring.hpp:191
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
Definition: unit.cpp:1297
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
Definition: unit.hpp:234
int recall_cost() const
How much gold it costs to recall this unit, or -1 if the side&#39;s default recall cost is used...
Definition: unit.hpp:630
static std::string write_direction(DIRECTION dir)
Definition: location.cpp:141
std::string hash() const
Definition: config.cpp:1392
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1270
std::size_t underlying_id() const
This unit&#39;s unique internal ID.
Definition: unit.hpp:382
variant operator()(unsigned long long i) const
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
Definition: unit.hpp:966
static void add_input(formula_input_vector &inputs, const std::string &key, formula_access access_type=formula_access::read_only)
Definition: callable.hpp:136
const std::string & icon_image() const
Definition: terrain.hpp:44