The Battle for Wesnoth  1.17.10+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 #include "tod_manager.hpp"
34 #include "play_controller.hpp"
35 #include "game_events/pump.hpp"
36 
37 static lg::log_domain log_scripting_formula("scripting/formula");
38 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
39 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
40 
41 namespace wfl
42 {
43 
44 variant location_callable::get_value(const std::string& key) const
45 {
46  if(key == "x") {
47  return variant(loc_.wml_x());
48  } else if(key == "y") {
49  return variant(loc_.wml_y());
50  }
51 
52  return variant();
53 }
54 
56 {
57  add_input(inputs, "x");
58  add_input(inputs, "y");
59 }
60 
62 {
63  const location_callable* loc_callable = dynamic_cast<const location_callable*>(callable);
64  if(loc_callable == nullptr) {
65  return formula_callable::do_compare(callable);
66  }
67 
68  const map_location& other_loc = loc_callable->loc();
69  return loc_.do_compare(other_loc);
70 }
71 
72 void location_callable::serialize_to_string(std::string& str) const
73 {
74  std::ostringstream s;
75  s << "loc(" << (loc_.wml_x()) << "," << (loc_.wml_y()) << ")";
76  str += s.str();
77 }
78 
79 attack_type_callable::attack_type_callable(const attack_type& attack) : att_(attack.shared_from_this())
80 {
82 }
83 
84 variant attack_type_callable::get_value(const std::string& key) const
85 {
86  if(key == "id" || key == "name") {
87  return variant(att_->id());
88  } else if(key == "description") {
89  return variant(att_->name());
90  } else if(key == "type") {
91  return variant(att_->type());
92  } else if(key == "icon") {
93  return variant(att_->icon());
94  } else if(key == "range") {
95  return variant(att_->range());
96  } else if(key == "damage") {
97  return variant(att_->damage());
98  } else if(key == "number_of_attacks" || key == "number" || key == "num_attacks" || key == "attacks") {
99  return variant(att_->num_attacks());
100  } else if(key == "attack_weight") {
101  return variant(att_->attack_weight(), variant::DECIMAL_VARIANT);
102  } else if(key == "defense_weight") {
103  return variant(att_->defense_weight(), variant::DECIMAL_VARIANT);
104  } else if(key == "accuracy") {
105  return variant(att_->accuracy());
106  } else if(key == "parry") {
107  return variant(att_->parry());
108  } else if(key == "movement_used") {
109  return variant(att_->movement_used());
110  } else if(key == "specials" || key == "special") {
111  std::vector<variant> res;
112 
113  for(const auto special : att_->specials().all_children_range()) {
114  if(!special.cfg["id"].empty()) {
115  res.emplace_back(special.cfg["id"].str());
116  }
117  }
118  return variant(res);
119  }
120 
121  return variant();
122 }
123 
125 {
126  add_input(inputs, "name");
127  add_input(inputs, "type");
128  add_input(inputs, "description");
129  add_input(inputs, "icon");
130  add_input(inputs, "range");
131  add_input(inputs, "damage");
132  add_input(inputs, "number");
133  add_input(inputs, "accuracy");
134  add_input(inputs, "parry");
135  add_input(inputs, "movement_used");
136  add_input(inputs, "attack_weight");
137  add_input(inputs, "defense_weight");
138  add_input(inputs, "specials");
139 }
140 
142 {
143  const attack_type_callable* att_callable = dynamic_cast<const attack_type_callable*>(callable);
144  if(att_callable == nullptr) {
145  return formula_callable::do_compare(callable);
146  }
147 
148  if(att_->damage() != att_callable->att_->damage()) {
149  return att_->damage() - att_callable->att_->damage();
150  }
151 
152  if(att_->num_attacks() != att_callable->att_->num_attacks()) {
153  return att_->num_attacks() - att_callable->att_->num_attacks();
154  }
155 
156  if(att_->id() != att_callable->att_->id()) {
157  return att_->id().compare(att_callable->att_->id());
158  }
159 
160  if(att_->type() != att_callable->att_->type()) {
161  return att_->type().compare(att_callable->att_->type());
162  }
163 
164  if(att_->range() != att_callable->att_->range()) {
165  return att_->range().compare(att_callable->att_->range());
166  }
167 
168  const auto self_specials = att_->specials().all_children_range();
169  const auto other_specials = att_callable->att_->specials().all_children_range();
170  if(self_specials.size() != other_specials.size()) {
171  return self_specials.size() < other_specials.size() ? -1 : 1;
172  }
173  for(std::size_t i = 0; i < self_specials.size(); ++i) {
174  const auto& s = self_specials[i].cfg["id"];
175  const auto& o = other_specials[i].cfg["id"];
176  if(s != o) {
177  return s.str().compare(o.str());
178  }
179  }
180 
181  return 0;
182 }
183 
185 {
186  type_ = UNIT_C;
187 }
188 
189 variant unit_callable::get_value(const std::string& key) const
190 {
191  if(key == "x") {
193  return variant();
194  }
195 
196  return variant(loc_.wml_x());
197  } else if(key == "y") {
199  return variant();
200  }
201 
202  return variant(loc_.wml_y());
203  } else if(key == "loc") {
205  return variant();
206  }
207 
208  return variant(std::make_shared<location_callable>(loc_));
209  } else if(key == "terrain") {
211  return variant();
212  }
213  return variant(std::make_shared<terrain_callable>(*resources::gameboard, loc_));
214  } else if(key == "id") {
215  return variant(u_.id());
216  } else if(key == "type") {
217  return variant(u_.type_id());
218  } else if(key == "name") {
219  return variant(u_.name());
220  } else if(key == "usage") {
221  return variant(u_.usage());
222  } else if(key == "leader" || key == "canrecruit") {
223  return variant(u_.can_recruit());
224  } else if(key == "undead") {
225  return variant(u_.get_state("not_living") ? 1 : 0);
226  } else if(key == "attacks") {
227  std::vector<variant> res;
228  for(const attack_type& att : u_.attacks()) {
229  res.emplace_back(std::make_shared<attack_type_callable>(att));
230  }
231 
232  return variant(res);
233  } else if(key == "abilities") {
235  } else if(key == "hitpoints") {
236  return variant(u_.hitpoints());
237  } else if(key == "max_hitpoints") {
238  return variant(u_.max_hitpoints());
239  } else if(key == "experience") {
240  return variant(u_.experience());
241  } else if(key == "max_experience") {
242  return variant(u_.max_experience());
243  } else if(key == "level" || key == "full") {
244  // This allows writing "upkeep == full"
245  return variant(u_.level());
246  } else if(key == "total_movement" || key == "max_moves") {
247  return variant(u_.total_movement());
248  } else if(key == "movement_left" || key == "moves") {
249  return variant(u_.movement_left());
250  } else if(key == "attacks_left") {
251  return variant(u_.attacks_left());
252  } else if(key == "max_attacks") {
253  return variant(u_.max_attacks());
254  } else if(key == "traits") {
256  } else if(key == "extra_recruit") {
258  } else if(key == "advances_to") {
260  } else if(key == "states" || key == "status") {
262  } else if(key == "side") {
263  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.");
264  return variant(u_.side()-1);
265  } else if(key == "side_number") {
266  return variant(u_.side());
267  } else if(key == "cost") {
268  return variant(u_.cost());
269  } else if(key == "upkeep") {
270  return variant(u_.upkeep());
271  } else if(key == "loyal") {
272  // So we can write "upkeep == loyal"
273  return variant(0);
274  } else if(key == "hidden") {
275  return variant(u_.get_hidden());
276  } else if(key == "petrified") {
277  return variant(u_.incapacitated());
278  } else if(key == "resting") {
279  return variant(u_.resting());
280  } else if(key == "role") {
281  return variant(u_.get_role());
282  } else if(key == "race") {
283  return variant(u_.race()->id());
284  } else if(key == "gender") {
285  return variant(gender_string(u_.gender()));
286  } else if(key == "variation") {
287  return variant(u_.variation());
288  } else if(key == "zoc") {
289  return variant(u_.get_emit_zoc());
290  } else if(key == "alignment") {
292  } else if(key == "facing") {
294  } else if(key == "resistance" || key == "movement_cost" || key == "vision_cost" || key == "jamming_cost" || key == "defense") {
295  const auto& mt = u_.movement_type();
296  config cfg;
297  bool needs_flip = false;
298  if(key == "resistance") {
299  mt.get_resistances().write(cfg);
300  needs_flip = true;
301  } else if(key == "movement_cost") {
302  mt.get_movement().write(cfg);
303  } else if(key == "vision_cost") {
304  mt.get_vision().write(cfg);
305  } else if(key == "jamming_cost") {
306  mt.get_vision().write(cfg);
307  } else if(key == "defense") {
308  mt.get_defense().write(cfg);
309  needs_flip = true;
310  }
311  std::map<variant, variant> res;
312  for(const auto& p : cfg.attribute_range()) {
313  int val = p.second;
314  if(needs_flip) {
315  val = 100 - val;
316  }
317  res.emplace(variant(p.first), variant(val));
318  }
319 
320  return variant(res);
321  } else if(key == "flying") {
322  return variant(u_.is_flying());
323  } else if(key == "vars") {
326  }
327 
328  return variant();
329  } else if(key == "wml_vars") {
330  return variant(std::make_shared<config_callable>(u_.variables()));
331  } else if(key == "n" || key == "s" || key == "ne" || key == "se" || key == "nw" || key == "sw" ||
332  key == "lawful" || key == "neutral" || key == "chaotic" || key == "liminal" ||
333  key == "male" || key == "female")
334  {
335  return variant(key);
336  }
337 
338  return variant();
339 }
340 
342 {
343  add_input(inputs, "x");
344  add_input(inputs, "y");
345  add_input(inputs, "loc");
346  add_input(inputs, "terrain");
347  add_input(inputs, "id");
348  add_input(inputs, "type");
349  add_input(inputs, "name");
350  add_input(inputs, "canrecruit");
351  add_input(inputs, "undead");
352  add_input(inputs, "traits");
353  add_input(inputs, "attacks");
354  add_input(inputs, "abilities");
355  add_input(inputs, "hitpoints");
356  add_input(inputs, "max_hitpoints");
357  add_input(inputs, "experience");
358  add_input(inputs, "max_experience");
359  add_input(inputs, "level");
360  add_input(inputs, "moves");
361  add_input(inputs, "max_moves");
362  add_input(inputs, "attacks_left");
363  add_input(inputs, "max_attacks");
364  add_input(inputs, "side_number");
365  add_input(inputs, "extra_recruit");
366  add_input(inputs, "advances_to");
367  add_input(inputs, "status");
368  add_input(inputs, "cost");
369  add_input(inputs, "usage");
370  add_input(inputs, "upkeep");
371  add_input(inputs, "hidden");
372  add_input(inputs, "petrified");
373  add_input(inputs, "resting");
374  add_input(inputs, "role");
375  add_input(inputs, "race");
376  add_input(inputs, "gender");
377  add_input(inputs, "variation");
378  add_input(inputs, "zoc");
379  add_input(inputs, "alignment");
380  add_input(inputs, "facing");
381  add_input(inputs, "resistance");
382  add_input(inputs, "movement_cost");
383  add_input(inputs, "vision_cost");
384  add_input(inputs, "jamming_cost");
385  add_input(inputs, "defense");
386  add_input(inputs, "flying");
387  add_input(inputs, "vars");
388  add_input(inputs, "wml_vars");
389 }
390 
391 int unit_callable::do_compare(const formula_callable* callable) const
392 {
393  const unit_callable* u_callable = dynamic_cast<const unit_callable*>(callable);
394  if(u_callable == nullptr) {
395  return formula_callable::do_compare(callable);
396  }
397 
398  return u_.underlying_id() - u_callable->u_.underlying_id();
399 }
400 
401 variant unit_type_callable::get_value(const std::string& key) const
402 {
403  if(key == "id") {
404  return variant(u_.id());
405  } else if(key == "type") {
406  return variant(u_.type_name());
407  } else if(key == "alignment") {
409  } else if(key == "race") {
410  return variant(u_.race_id());
411  } else if(key == "abilities") {
413  } else if(key == "traits") {
414  std::vector<variant> res;
415  for(const auto& config : u_.possible_traits()) {
416  res.emplace_back(config["id"].str());
417  }
418 
419  return variant(res);
420  } else if(key == "attacks") {
421  std::vector<variant> res;
422  for(const attack_type& att : u_.attacks()) {
423  res.emplace_back(std::make_shared<attack_type_callable>(att));
424  }
425 
426  return variant(res);
427  } else if(key == "hitpoints" || key == "max_hitpoints") {
428  return variant(u_.hitpoints());
429  } else if(key == "experience" || key == "max_experience") {
430  return variant(u_.experience_needed(true));
431  } else if(key == "level") {
432  return variant(u_.level());
433  } else if(key == "total_movement" || key == "max_moves" || key == "moves") {
434  return variant(u_.movement());
435  } else if(key == "unpoisonable") {
436  return variant(u_.musthave_status("unpoisonable"));
437  } else if(key == "unslowable") {
438  return variant(u_.musthave_status("unslowable"));
439  } else if(key == "unpetrifiable") {
440  return variant(u_.musthave_status("unpetrifiable"));
441  } else if(key == "undrainable") {
442  return variant(u_.musthave_status("undrainable"));
443  } else if(key == "unplagueable") {
444  return variant(u_.musthave_status("unplagueable"));
445  } else if(key == "cost") {
446  return variant(u_.cost());
447  } else if(key == "recall_cost") {
448  return variant(u_.recall_cost());
449  } else if(key == "usage") {
450  return variant(u_.usage());
451  }
452 
453  return variant();
454 }
455 
457 {
458  add_input(inputs, "id");
459  add_input(inputs, "type");
460  add_input(inputs, "race");
461  add_input(inputs, "alignment");
462  add_input(inputs, "abilities");
463  add_input(inputs, "traits");
464  add_input(inputs, "attacks");
465  add_input(inputs, "hitpoints");
466  add_input(inputs, "experience");
467  add_input(inputs, "level");
468  add_input(inputs, "total_movement");
469  add_input(inputs, "undead");
470  add_input(inputs, "cost");
471  add_input(inputs, "recall_cost");
472  add_input(inputs, "usage");
473 }
474 
476 {
477  const unit_type_callable* u_callable = dynamic_cast<const unit_type_callable*>(callable);
478  if(u_callable == nullptr) {
479  return formula_callable::do_compare(callable);
480  }
481 
482  return u_.id().compare(u_callable->u_.id());
483 }
484 
486 #ifdef USING_BOOST_VARIANT
487  : public boost::static_visitor<variant>
488 #endif
489 {
490  variant operator()(bool b) const { return variant(b ? 1 : 0); }
491  variant operator()(int i) const { return variant(i); }
492  variant operator()(unsigned long long i) const { return variant(i); }
493  variant operator()(double i) const { return variant(i * 1000, variant::DECIMAL_VARIANT); }
494  // TODO: Should comma-separated lists of stuff be returned as a list?
495  // The challenge is to distinguish them from ordinary strings that happen to contain a comma
496  // (or should we assume that such strings will be translatable?).
497  variant operator()(const std::string& s) const { return variant(s); }
498  variant operator()(const t_string& s) const { return variant(s.str()); }
499  variant operator()(utils::monostate) const { return variant(); }
500 };
501 
502 variant config_callable::get_value(const std::string& key) const
503 {
504  if(cfg_.has_attribute(key)) {
505  return cfg_[key].apply_visitor(fai_variant_visitor());
506  } else if(cfg_.has_child(key)) {
507  std::vector<variant> result;
508  for(const auto& child : cfg_.child_range(key)) {
509  result.emplace_back(std::make_shared<config_callable>(child));
510  }
511 
512  return variant(result);
513  } else if(key == "__all_children") {
514  std::vector<variant> result;
515  for(const auto child : cfg_.all_children_range()) {
516  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
517  const variant kv(std::make_shared<key_value_pair>(variant(child.key), cfg_child));
518  result.push_back(kv);
519  }
520 
521  return variant(result);
522  } else if(key == "__children") {
523  std::map<std::string, std::vector<variant>> build;
524  for(const auto child : cfg_.all_children_range()) {
525  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
526  build[child.key].push_back(cfg_child);
527  }
528 
529  std::map<variant,variant> result;
530  for(auto& p : build) {
531  result[variant(p.first)] = variant(p.second);
532  }
533 
534  return variant(result);
535  } else if(key == "__attributes") {
536  std::map<variant,variant> result;
537  for(const auto& val : cfg_.attribute_range()) {
538  result[variant(val.first)] = val.second.apply_visitor(fai_variant_visitor());
539  }
540 
541  return variant(result);
542  }
543 
544  return variant();
545 }
546 
548 {
549  add_input(inputs, "__all_children");
550  add_input(inputs, "__children");
551  add_input(inputs, "__attributes");
552 
553  for(const auto& val : cfg_.attribute_range()) {
554  if(val.first.find_first_not_of(formula::id_chars) != std::string::npos) {
555  add_input(inputs, val.first);
556  }
557  }
558 }
559 
561 {
562  const config_callable* cfg_callable = dynamic_cast<const config_callable*>(callable);
563  if(cfg_callable == nullptr) {
564  return formula_callable::do_compare(callable);
565  }
566 
567  if(cfg_ == cfg_callable->get_config()) {
568  return 0;
569  }
570 
571  return cfg_.hash().compare(cfg_callable->get_config().hash());
572 }
573 
574 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))
575 {
576  type_ = TERRAIN_C;
577 }
578 
579 variant terrain_callable::get_value(const std::string& key) const
580 {
581  if(key == "x") {
582  return variant(loc_.wml_x());
583  } else if(key == "y") {
584  return variant(loc_.wml_y());
585  } else if(key == "loc") {
586  return variant(std::make_shared<location_callable>(loc_));
587  } else if(key == "id") {
588  return variant(std::string(t_.id()));
589  } else if(key == "name") {
590  return variant(t_.name());
591  } else if(key == "editor_name") {
592  return variant(t_.editor_name());
593  } else if(key == "description") {
594  return variant(t_.description());
595  } else if(key == "icon") {
596  return variant(t_.icon_image());
597  } else if(key == "light") {
598  return variant(t_.light_bonus(0));
599  } else if(key == "village") {
600  return variant(t_.is_village());
601  } else if(key == "castle") {
602  return variant(t_.is_castle());
603  } else if(key == "keep") {
604  return variant(t_.is_keep());
605  } else if(key == "healing") {
606  return variant(t_.gives_healing());
607  } else if(key == "owner") {
608  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.");
609  return variant(owner_ - 1);
610  } else if(key == "owner_side") {
611  return variant(owner_);
612  }
613 
614  return variant();
615 }
616 
618 {
619  add_input(inputs, "x");
620  add_input(inputs, "y");
621  add_input(inputs, "loc");
622  add_input(inputs, "id");
623  add_input(inputs, "name");
624  add_input(inputs, "editor_name");
625  add_input(inputs, "description");
626  add_input(inputs, "icon");
627  add_input(inputs, "light");
628  add_input(inputs, "village");
629  add_input(inputs, "castle");
630  add_input(inputs, "keep");
631  add_input(inputs, "healing");
632  add_input(inputs, "owner_side");
633 }
634 
636 {
637  const terrain_callable* terr_callable = dynamic_cast<const terrain_callable*>(callable);
638  if(terr_callable == nullptr) {
639  return formula_callable::do_compare(callable);
640  }
641 
642  const map_location& other_loc = terr_callable->loc_;
643  return loc_.do_compare(other_loc);
644 }
645 
647  return board_.map();
648 }
649 
651 {
652  add_input(inputs, "w");
653  add_input(inputs, "h");
654 }
655 
656 variant gamemap_callable::get_value(const std::string& key) const
657 {
658  if(key == "terrain") {
659  int w = get_gamemap().w();
660  int h = get_gamemap().h();
661 
662  std::vector<variant> vars;
663  for(int i = 0; i < w; i++) {
664  for(int j = 0; j < h; j++) {
665  const map_location loc(i, j);
666  vars.emplace_back(std::make_shared<terrain_callable>(board_, loc));
667  }
668  }
669 
670  return variant(vars);
671  } else if(key == "gamemap") {
672  int w = get_gamemap().w();
673  int h = get_gamemap().h();
674 
675  std::map<variant, variant> vars;
676  for(int i = 0; i < w; i++) {
677  for(int j = 0; j < h; j++) {
678  const map_location loc(i, j);
679  vars.emplace(std::make_shared<location_callable>(loc), std::make_shared<terrain_callable>(board_, loc));
680  }
681  }
682 
683  return variant(vars);
684  } else if(key == "w") {
685  return variant(get_gamemap().w());
686  } else if(key == "h") {
687  return variant(get_gamemap().h());
688  } else {
689  return variant();
690  }
691 }
692 
694 {
695  add_input(inputs, "side_number");
696  add_input(inputs, "id");
697  add_input(inputs, "gold");
698  add_input(inputs, "start_gold");
699  add_input(inputs, "base_income");
700  add_input(inputs, "total_income");
701  add_input(inputs, "village_gold");
702  add_input(inputs, "village_support");
703  add_input(inputs, "recall_cost");
704  add_input(inputs, "name");
705  add_input(inputs, "is_human");
706  add_input(inputs, "is_ai");
707  add_input(inputs, "is_network");
708  add_input(inputs, "fog");
709  add_input(inputs, "shroud");
710  add_input(inputs, "hidden");
711  add_input(inputs, "flag");
712  add_input(inputs, "flag_icon");
713  add_input(inputs, "team_name");
714  add_input(inputs, "faction");
715  add_input(inputs, "faction_name");
716  add_input(inputs, "color");
717  add_input(inputs, "share_vision");
718  add_input(inputs, "carryover_bonus");
719  add_input(inputs, "carryover_percentage");
720  add_input(inputs, "carryover_add");
721  add_input(inputs, "recruit");
722  add_input(inputs, "wml_vars");
723 }
724 
725 variant team_callable::get_value(const std::string& key) const
726 {
727  if(key == "side") {
728  deprecated_message("team.side", DEP_LEVEL::INDEFINITE, version_info("1.17"), "Use side_number instead.");
729  return variant(team_.side());
730  } else if(key == "side_number") {
731  return variant(team_.side());
732  } else if(key == "id") {
733  return variant(team_.save_id());
734  } else if(key == "save_id") {
735  return variant(team_.save_id());
736  } else if(key == "gold") {
737  return variant(team_.gold());
738  } else if(key == "start_gold") {
739  return variant(team_.start_gold());
740  } else if(key == "base_income") {
741  return variant(team_.base_income());
742  } else if(key == "total_income") {
743  return variant(team_.total_income());
744  } else if(key == "village_gold") {
745  return variant(team_.village_gold());
746  } else if(key == "village_support") {
747  return variant(team_.village_support());
748  } else if(key == "recall_cost") {
749  return variant(team_.recall_cost());
750  } else if(key == "is_human") {
751  return variant(team_.is_local_human());
752  } else if(key == "is_ai") {
753  return variant(team_.is_local_ai());
754  } else if(key == "is_network") {
755  return variant(team_.is_network());
756  } else if(key == "fog") {
757  return variant(team_.uses_fog());
758  } else if(key == "shroud") {
759  return variant(team_.uses_shroud());
760  } else if(key == "hidden") {
761  return variant(team_.hidden());
762  } else if(key == "flag") {
763  return variant(team_.flag());
764  } else if(key == "flag_icon") {
765  return variant(team_.flag_icon());
766  } else if(key == "team_name") {
767  return variant(team_.team_name());
768  } else if(key == "color") {
769  return variant(team_.color());
770  } else if(key == "share_vision") {
771  return variant(team_shared_vision::get_string(team_.share_vision()));
772  } else if(key == "carryover_bonus") {
773  return variant(team_.carryover_bonus(), variant::DECIMAL_VARIANT);
774  } else if(key == "carryover_percentage") {
775  return variant(team_.carryover_percentage());
776  } else if(key == "carryover_add") {
777  return variant(team_.carryover_add());
778  } else if(key == "recruit") {
779  std::vector<variant> result;
780  for(const auto& recruit : team_.recruits()) {
781  result.emplace_back(recruit);
782  }
783  return variant(result);
784  } else if(key == "recall") {
785  std::vector<variant> result;
786  for(const auto& u : team_.recall_list()) {
787  result.push_back(std::make_shared<unit_callable>(*u));
788  }
789  return variant(result);
790  } else if(key == "wml_vars") {
791  return variant(std::make_shared<config_callable>(team_.variables()));
792  }
793 
794  return variant();
795 }
796 
797 variant set_var_callable::get_value(const std::string& key) const
798 {
799  if(key == "key") {
800  return variant(key_);
801  } else if(key == "value") {
802  return value_;
803  }
804 
805  return variant();
806 }
807 
809 {
810  add_input(inputs, "key");
811  add_input(inputs, "value");
812 }
813 
815 {
816  //if(infinite_loop_guardian_.set_var_check()) {
817  if(auto obj = ctxt.try_convert<formula_callable>()) {
818  LOG_SF << "Setting variable: " << key_ << " -> " << value_.to_debug_string();
819  obj->mutate_value(key_, value_);
820  return variant(true);
821  }
822  //}
823  //too many calls in a row - possible infinite loop
824  ERR_SF << "ERROR #" << 5001 << " while executing 'set_var' formula function";
825 
826  return variant(std::make_shared<safe_call_result>(fake_ptr(), 5001));
827 }
828 
829 variant safe_call_callable::get_value(const std::string& key) const
830 {
831  if(key == "main") {
832  return variant(main_);
833  } else if(key == "backup") {
834  return variant(backup_);
835  }
836 
837  return variant();
838 }
839 
841 {
842  add_input(inputs, "main");
843  add_input(inputs, "backup");
844 }
845 
847 {
848  variant res;
849  if(auto action = main_.try_convert<action_callable>()) {
850  res = action->execute_self(ctxt);
851  }
852 
853  if(res.try_convert<safe_call_result>()) {
854  /* If we have safe_call formula and either an error occurred, or the current action
855  * was not recognized, then evaluate backup formula from safe_call and execute it
856  * during the next loop
857  */
858 
859  map_formula_callable callable(ctxt.as_callable());
860  callable.add("error", res);
861 
862  /* Store the result in safe_call_callable in case we would like to display it to the user,
863  * for example if this formula was executed from the commandline.
864  */
865  backup_ = get_backup()->evaluate(callable);
866  ctxt.execute_variant(backup_);
867  }
868  return variant(true);
869 }
870 
871 variant safe_call_result::get_value(const std::string& key) const
872 {
873  if(key == "status") {
874  return variant(status_);
875  } else if(key == "object") {
876  if(failed_callable_) {
877  return variant(failed_callable_);
878  }
879 
880  return variant();
881  } else if(key == "current_loc" && current_unit_location_ != map_location()) {
882  return variant(std::make_shared<location_callable>(current_unit_location_));
883  }
884 
885  return variant();
886 }
887 
889 {
890  add_input(inputs, "status");
891  add_input(inputs, "object");
892 
893  if(current_unit_location_ != map_location()) {
894  add_input(inputs, "current_loc");
895  }
896 }
897 
899 {
900  add_input(inputs, "turn_number");
901  add_input(inputs, "time_of_day");
902  add_input(inputs, "side_number");
903  add_input(inputs, "sides");
904  add_input(inputs, "units");
905  add_input(inputs, "map");
906 }
907 
908 variant gamestate_callable::get_value(const std::string &key) const
909 {
910  if(key == "turn_number") {
911  return variant(resources::tod_manager->turn());
912  } else if(key == "time_of_day") {
913  return variant(resources::tod_manager->get_time_of_day().id);
914  } else if(key == "side_number") {
915  return variant(resources::controller->current_side());
916  } else if(key == "sides") {
917  std::vector<variant> vars;
918  for(const auto& team : resources::gameboard->teams()) {
919  vars.emplace_back(std::make_shared<team_callable>(team));
920  }
921  return variant(vars);
922  } else if(key == "units") {
923  std::vector<variant> vars;
924  for(const auto& unit : resources::gameboard->units()) {
925  vars.emplace_back(std::make_shared<unit_callable>(unit));
926  }
927  return variant(vars);
928  } else if(key == "map") {
929  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
930  }
931 
932  return variant();
933 }
934 
936 {
937  add_input(inputs, "event");
938  add_input(inputs, "event_id");
939  add_input(inputs, "event_data");
940  add_input(inputs, "loc");
941  add_input(inputs, "unit");
942  add_input(inputs, "weapon");
943  add_input(inputs, "second_loc");
944  add_input(inputs, "second_unit");
945  add_input(inputs, "second_weapon");
946 }
947 
948 variant event_callable::get_value(const std::string &key) const
949 {
950  if(key == "event") {
951  return variant(event_info.name);
952  } else if(key == "event_id") {
953  return variant(event_info.id);
954  } else if(key == "loc") {
955  return variant(std::make_shared<location_callable>(event_info.loc1));
956  } else if(key == "second_loc") {
957  return variant(std::make_shared<location_callable>(event_info.loc2));
958  } else if(key == "event_data") {
959  return variant(std::make_shared<config_callable>(event_info.data));
960  } else if(key == "unit") {
961  if(auto u1 = event_info.loc1.get_unit()) {
962  return variant(std::make_shared<unit_callable>(*u1));
963  }
964  } else if(key == "second_unit") {
965  if(auto u2 = event_info.loc2.get_unit()) {
966  return variant(std::make_shared<unit_callable>(*u2));
967  }
968  } else if(key == "weapon") {
969  if(event_info.data.has_child("first")) {
970  return variant(std::make_shared<attack_type_callable>(attack_type(event_info.data.child("first"))));
971  }
972  } else if(key == "second_weapon") {
973  if(event_info.data.has_child("second")) {
974  return variant(std::make_shared<attack_type_callable>(attack_type(event_info.data.child("second"))));
975  }
976  }
977 
978  return variant();
979 }
980 
981 } // namespace wfl
const map_location & loc() const
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:656
play_controller * controller
Definition: resources.cpp:22
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:995
::tod_manager * tod_manager
Definition: resources.cpp:30
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:133
const std::string & type_id() const
The id of this unit&#39;s type.
Definition: unit.cpp:1802
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:1467
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:1316
variant get_value(const std::string &key) const override
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:468
const movetype & movement_type() const
Get the unit&#39;s movement type.
Definition: unit.hpp:1431
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:502
config & variables()
Gets any user-defined variables this unit &#39;owns&#39;.
Definition: unit.hpp:706
variant get_value(const std::string &key) const override
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:575
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:1374
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:1327
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:1345
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition: unit.hpp:723
Definitions for the interface to Wesnoth Markup Language (WML).
int cost() const
How much gold is required to recruit this unit.
Definition: unit.hpp:636
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_
variant get_value(const std::string &key) const override
#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
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:75
const t_string & editor_name() const
Definition: terrain.hpp:49
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:383
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:406
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
Definition: unit.cpp:1595
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:532
int level() const
The current level of this unit.
Definition: unit.hpp:562
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:372
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:478
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:508
const std::string & get_role() const
Gets this unit&#39;s role.
Definition: unit.hpp:672
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
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:615
std::string usage() const
Gets this unit&#39;s usage.
Definition: unit.hpp:689
variant get_value(const std::string &key) const override
Define the game&#39;s event mechanism.
attack_itors attacks()
Gets an iterator over this unit&#39;s attacks.
Definition: unit.hpp:928
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:861
int w
const unit_race * race() const
Gets this unit&#39;s race.
Definition: unit.hpp:496
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:627
static const char *const id_chars
Definition: formula.hpp:75
unit_formula_manager & formula_manager() const
Get the unit formula manager.
Definition: unit.hpp:1814
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:526
Definition: contexts.hpp:44
int do_compare(const formula_callable *callable) const override
void get_inputs(formula_input_vector &inputs) 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:906
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1267
terrain_callable(const display_context &m, const map_location &loc)
int side() const
The side this unit belongs to.
Definition: unit.hpp:346
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:239
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:1299
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
Definition: unit.hpp:247
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:643
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:1283
std::size_t underlying_id() const
This unit&#39;s unique internal ID.
Definition: unit.hpp:395
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:979
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
void get_inputs(formula_input_vector &inputs) const override
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46