The Battle for Wesnoth  1.19.13+dev
callable_objects.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2025
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 
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"
24 #include "units/unit.hpp"
25 #include "units/types.hpp"
26 #include "log.hpp"
27 #include "recall_list_manager.hpp"
28 #include "deprecation.hpp"
29 #include "game_board.hpp"
30 #include "game_version.hpp"
31 #include "resources.hpp"
32 #include "tod_manager.hpp"
33 #include "play_controller.hpp"
34 #include "game_events/pump.hpp"
35 
36 static lg::log_domain log_scripting_formula("scripting/formula");
37 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
38 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
39 
40 namespace wfl
41 {
42 
43 variant location_callable::get_value(const std::string& key) const
44 {
45  if(key == "x") {
46  return variant(loc_.wml_x());
47  } else if(key == "y") {
48  return variant(loc_.wml_y());
49  }
50 
51  return variant();
52 }
53 
55 {
56  add_input(inputs, "x");
57  add_input(inputs, "y");
58 }
59 
61 {
62  const location_callable* loc_callable = dynamic_cast<const location_callable*>(callable);
63  if(loc_callable == nullptr) {
64  return formula_callable::do_compare(callable);
65  }
66 
67  const map_location& other_loc = loc_callable->loc();
68  return loc_.do_compare(other_loc);
69 }
70 
71 void location_callable::serialize_to_string(std::string& str) const
72 {
73  std::ostringstream s;
74  s << "loc(" << (loc_.wml_x()) << "," << (loc_.wml_y()) << ")";
75  str += s.str();
76 }
77 
78 attack_type_callable::attack_type_callable(const attack_type& attack) : att_(attack.shared_from_this())
79 {
81 }
82 
83 variant attack_type_callable::get_value(const std::string& key) const
84 {
85  if(key == "id" || key == "name") {
86  return variant(att_->id());
87  } else if(key == "description") {
88  return variant(att_->name());
89  } else if(key == "base_type") {
90  return variant(att_->type());
91  } else if(key == "type") {
92  return variant(att_->effective_damage_type().first);
93  } else if(key == "icon") {
94  return variant(att_->icon());
95  } else if(key == "range") {
96  return variant(att_->range());
97  } else if(key == "alignment") {
98  return variant(att_->alignment_str());
99  } else if(key == "damage") {
100  return variant(att_->damage());
101  } else if(key == "number_of_attacks" || key == "number" || key == "num_attacks" || key == "attacks") {
102  return variant(att_->num_attacks());
103  } else if(key == "attack_weight") {
104  return variant(att_->attack_weight(), variant::DECIMAL_VARIANT);
105  } else if(key == "defense_weight") {
106  return variant(att_->defense_weight(), variant::DECIMAL_VARIANT);
107  } else if(key == "accuracy") {
108  return variant(att_->accuracy());
109  } else if(key == "parry") {
110  return variant(att_->parry());
111  } else if(key == "movement_used") {
112  return variant(att_->movement_used());
113  } else if(key == "attacks_used") {
114  return variant(att_->attacks_used());
115  } else if(key == "min_range") {
116  return variant(att_->min_range());
117  } else if(key == "max_range") {
118  return variant(att_->max_range());
119  } else if(key == "specials" || key == "special") {
120  std::vector<variant> res;
121 
122  for(const auto [_, special_cfg] : att_->specials().all_children_view()) {
123  if(!special_cfg["id"].empty()) {
124  res.emplace_back(special_cfg["id"].str());
125  }
126  }
127  return variant(res);
128  }
129 
130  return variant();
131 }
132 
134 {
135  add_input(inputs, "name");
136  add_input(inputs, "type");
137  add_input(inputs, "base_type");
138  add_input(inputs, "description");
139  add_input(inputs, "icon");
140  add_input(inputs, "range");
141  add_input(inputs, "alignment");
142  add_input(inputs, "damage");
143  add_input(inputs, "number");
144  add_input(inputs, "accuracy");
145  add_input(inputs, "parry");
146  add_input(inputs, "movement_used");
147  add_input(inputs, "attacks_used");
148  add_input(inputs, "attack_weight");
149  add_input(inputs, "defense_weight");
150  add_input(inputs, "min_range");
151  add_input(inputs, "max_range");
152  add_input(inputs, "specials");
153 }
154 
156 {
157  const attack_type_callable* att_callable = dynamic_cast<const attack_type_callable*>(callable);
158  if(att_callable == nullptr) {
159  return formula_callable::do_compare(callable);
160  }
161 
162  if(att_->damage() != att_callable->att_->damage()) {
163  return att_->damage() - att_callable->att_->damage();
164  }
165 
166  if(att_->num_attacks() != att_callable->att_->num_attacks()) {
167  return att_->num_attacks() - att_callable->att_->num_attacks();
168  }
169 
170  if(att_->id() != att_callable->att_->id()) {
171  return att_->id().compare(att_callable->att_->id());
172  }
173 
174  if(att_->type() != att_callable->att_->type()) {
175  return att_->type().compare(att_callable->att_->type());
176  }
177 
178  if(att_->range() != att_callable->att_->range()) {
179  return att_->range().compare(att_callable->att_->range());
180  }
181 
182  if(att_->alignment_str() != att_callable->att_->alignment_str()) {
183  return att_->alignment_str().compare(att_callable->att_->alignment_str());
184  }
185 
186  const auto self_specials = att_->specials().all_children_range();
187  const auto other_specials = att_callable->att_->specials().all_children_range();
188  if(self_specials.size() != other_specials.size()) {
189  return self_specials.size() < other_specials.size() ? -1 : 1;
190  }
191  for(std::size_t i = 0; i < self_specials.size(); ++i) {
192  const auto& s = self_specials[i].cfg["id"];
193  const auto& o = other_specials[i].cfg["id"];
194  if(s != o) {
195  return s.str().compare(o.str());
196  }
197  }
198 
199  return 0;
200 }
201 
202 unit_callable::unit_callable(const unit& u) : loc_(u.get_location()), u_(u)
203 {
204  type_ = UNIT_C;
205 }
206 
207 variant unit_callable::get_value(const std::string& key) const
208 {
209 
210  if(key == "x") {
212  return variant();
213  }
214 
215  return variant(loc_.wml_x());
216  } else if(key == "y") {
218  return variant();
219  }
220 
221  return variant(loc_.wml_y());
222  } else if(key == "loc") {
224  return variant();
225  }
226 
227  return variant(std::make_shared<location_callable>(loc_));
228  } else if(key == "terrain") {
230  return variant();
231  }
232  return variant(std::make_shared<terrain_callable>(*resources::gameboard, loc_));
233  } else if(key == "id") {
234  return variant(u_.id());
235  } else if(key == "type") {
236  return variant(u_.type_id());
237  } else if(key == "name") {
238  return variant(u_.name());
239  } else if(key == "usage") {
240  return variant(u_.usage());
241  } else if(key == "leader" || key == "canrecruit") {
242  return variant(u_.can_recruit());
243  } else if(key == "undead") {
244  return variant(u_.get_state("not_living") ? 1 : 0);
245  } else if(key == "attacks") {
246  std::vector<variant> res;
247  for(const attack_type& att : u_.attacks()) {
248  res.emplace_back(std::make_shared<attack_type_callable>(att));
249  }
250 
251  return variant(res);
252  } else if(key == "abilities") {
254  } else if(key == "hitpoints") {
255  return variant(u_.hitpoints());
256  } else if(key == "max_hitpoints") {
257  return variant(u_.max_hitpoints());
258  } else if(key == "experience") {
259  return variant(u_.experience());
260  } else if(key == "max_experience") {
261  return variant(u_.max_experience());
262  } else if(key == "level" || key == "full") {
263  // This allows writing "upkeep == full"
264  return variant(u_.level());
265  } else if(key == "total_movement" || key == "max_moves") {
266  return variant(u_.total_movement());
267  } else if(key == "movement_left" || key == "moves") {
268  return variant(u_.movement_left());
269  } else if(key == "attacks_left") {
270  return variant(u_.attacks_left());
271  } else if(key == "max_attacks") {
272  return variant(u_.max_attacks());
273  } else if(key == "traits") {
275  } else if(key == "advancements_taken") {
277  } else if(key == "objects") {
279  } else if(key == "traits_count") {
280  return variant(u_.traits_count());
281  } else if(key == "advancements_taken_count") {
282  return variant(u_.advancements_count());
283  } else if(key == "objects_count") {
284  return variant(u_.objects_count());
285  } else if(key == "extra_recruit") {
287  } else if(key == "advances_to") {
289  } else if(key == "states" || key == "status") {
291  } else if(key == "side_number") {
292  return variant(u_.side());
293  } else if(key == "cost") {
294  return variant(u_.cost());
295  } else if(key == "upkeep") {
296  return variant(u_.upkeep());
297  } else if(key == "loyal") {
298  // So we can write "upkeep == loyal"
299  return variant(0);
300  } else if(key == "hidden") {
301  return variant(u_.get_hidden());
302  } else if(key == "petrified") {
303  return variant(u_.incapacitated());
304  } else if(key == "resting") {
305  return variant(u_.resting());
306  } else if(key == "role") {
307  return variant(u_.get_role());
308  } else if(key == "race") {
309  return variant(u_.race()->id());
310  } else if(key == "gender") {
311  return variant(gender_string(u_.gender()));
312  } else if(key == "variation") {
313  return variant(u_.variation());
314  } else if(key == "zoc") {
315  return variant(u_.get_emit_zoc());
316  } else if(key == "alignment") {
318  } else if(key == "facing") {
320  } else if(key == "resistance" || key == "movement_cost" || key == "vision_cost" || key == "jamming_cost" || key == "defense") {
321  const auto& mt = u_.movement_type();
322  config cfg;
323  bool needs_flip = false;
324  if(key == "resistance") {
325  mt.get_resistances().write(cfg);
326  needs_flip = true;
327  } else if(key == "movement_cost") {
328  mt.get_movement().write(cfg);
329  } else if(key == "vision_cost") {
330  mt.get_vision().write(cfg);
331  } else if(key == "jamming_cost") {
332  mt.get_jamming().write(cfg);
333  } else if(key == "defense") {
334  mt.get_defense().write(cfg);
335  needs_flip = true;
336  }
337  std::map<variant, variant> res;
338  for(const auto& [key, value] : cfg.attribute_range()) {
339  int val = value.to_int();
340  if(needs_flip) {
341  val = 100 - val;
342  }
343  res.emplace(variant(key), variant(val));
344  }
345 
346  return variant(res);
347  } else if(key == "flying") {
348  return variant(u_.is_flying());
349  } else if(key == "fearless") {
350  return variant(u_.is_fearless());
351  } else if(key == "healthy") {
352  return variant(u_.is_healthy());
353  } else if(key == "wml_vars") {
354  return variant(std::make_shared<config_callable>(u_.variables()));
355  } else if(key == "n" || key == "s" || key == "ne" || key == "se" || key == "nw" || key == "sw" ||
356  key == "lawful" || key == "neutral" || key == "chaotic" || key == "liminal" ||
357  key == "male" || key == "female")
358  {
359  return variant(key);
360  }
361 
362  return variant();
363 }
364 
366 {
367  add_input(inputs, "x");
368  add_input(inputs, "y");
369  add_input(inputs, "loc");
370  add_input(inputs, "terrain");
371  add_input(inputs, "id");
372  add_input(inputs, "type");
373  add_input(inputs, "name");
374  add_input(inputs, "canrecruit");
375  add_input(inputs, "undead");
376  add_input(inputs, "traits");
377  add_input(inputs, "advancements_taken");
378  add_input(inputs, "objects");
379  add_input(inputs, "traits_count");
380  add_input(inputs, "advancements_taken_count");
381  add_input(inputs, "objects_count");
382  add_input(inputs, "attacks");
383  add_input(inputs, "abilities");
384  add_input(inputs, "hitpoints");
385  add_input(inputs, "max_hitpoints");
386  add_input(inputs, "experience");
387  add_input(inputs, "max_experience");
388  add_input(inputs, "level");
389  add_input(inputs, "moves");
390  add_input(inputs, "max_moves");
391  add_input(inputs, "attacks_left");
392  add_input(inputs, "max_attacks");
393  add_input(inputs, "side_number");
394  add_input(inputs, "extra_recruit");
395  add_input(inputs, "advances_to");
396  add_input(inputs, "status");
397  add_input(inputs, "cost");
398  add_input(inputs, "usage");
399  add_input(inputs, "upkeep");
400  add_input(inputs, "hidden");
401  add_input(inputs, "petrified");
402  add_input(inputs, "resting");
403  add_input(inputs, "role");
404  add_input(inputs, "race");
405  add_input(inputs, "gender");
406  add_input(inputs, "variation");
407  add_input(inputs, "zoc");
408  add_input(inputs, "alignment");
409  add_input(inputs, "facing");
410  add_input(inputs, "resistance");
411  add_input(inputs, "movement_cost");
412  add_input(inputs, "vision_cost");
413  add_input(inputs, "jamming_cost");
414  add_input(inputs, "defense");
415  add_input(inputs, "flying");
416  add_input(inputs, "fearless");
417  add_input(inputs, "healthy");
418  add_input(inputs, "vars");
419  add_input(inputs, "wml_vars");
420 }
421 
422 int unit_callable::do_compare(const formula_callable* callable) const
423 {
424  const unit_callable* u_callable = dynamic_cast<const unit_callable*>(callable);
425  if(u_callable == nullptr) {
426  return formula_callable::do_compare(callable);
427  }
428 
429  return u_.underlying_id() - u_callable->u_.underlying_id();
430 }
431 
432 variant unit_type_callable::get_value(const std::string& key) const
433 {
434  if(key == "id") {
435  return variant(u_.id());
436  } else if(key == "type") {
437  return variant(u_.type_name());
438  } else if(key == "alignment") {
440  } else if(key == "race") {
441  return variant(u_.race_id());
442  } else if(key == "abilities") {
444  } else if(key == "traits") {
445  std::vector<variant> res;
446  for(const auto& config : u_.possible_traits()) {
447  res.emplace_back(config["id"].str());
448  }
449 
450  return variant(res);
451  } else if(key == "attacks") {
452  std::vector<variant> res;
453  for(const attack_type& att : u_.attacks()) {
454  res.emplace_back(std::make_shared<attack_type_callable>(att));
455  }
456 
457  return variant(res);
458  } else if(key == "hitpoints" || key == "max_hitpoints") {
459  return variant(u_.hitpoints());
460  } else if(key == "experience" || key == "max_experience") {
461  return variant(u_.experience_needed(true));
462  } else if(key == "level") {
463  return variant(u_.level());
464  } else if(key == "total_movement" || key == "max_moves" || key == "moves") {
465  return variant(u_.movement());
466  } else if(key == "undead") {
467  return variant(u_.musthave_status("unpoisonable") && u_.musthave_status("undrainable") && u_.musthave_status("unplagueable"));
468  } else if(key == "unpoisonable") {
469  return variant(u_.musthave_status("unpoisonable"));
470  } else if(key == "unslowable") {
471  return variant(u_.musthave_status("unslowable"));
472  } else if(key == "unpetrifiable") {
473  return variant(u_.musthave_status("unpetrifiable"));
474  } else if(key == "undrainable") {
475  return variant(u_.musthave_status("undrainable"));
476  } else if(key == "unplagueable") {
477  return variant(u_.musthave_status("unplagueable"));
478  } else if(key == "cost") {
479  return variant(u_.cost());
480  } else if(key == "recall_cost") {
481  return variant(u_.recall_cost());
482  } else if(key == "usage") {
483  return variant(u_.usage());
484  }
485 
486  return variant();
487 }
488 
490 {
491  add_input(inputs, "id");
492  add_input(inputs, "type");
493  add_input(inputs, "race");
494  add_input(inputs, "alignment");
495  add_input(inputs, "abilities");
496  add_input(inputs, "traits");
497  add_input(inputs, "attacks");
498  add_input(inputs, "hitpoints");
499  add_input(inputs, "experience");
500  add_input(inputs, "level");
501  add_input(inputs, "total_movement");
502  add_input(inputs, "undead");
503  add_input(inputs, "cost");
504  add_input(inputs, "recall_cost");
505  add_input(inputs, "usage");
506 }
507 
509 {
510  const unit_type_callable* u_callable = dynamic_cast<const unit_type_callable*>(callable);
511  if(u_callable == nullptr) {
512  return formula_callable::do_compare(callable);
513  }
514 
515  return u_.id().compare(u_callable->u_.id());
516 }
517 
519 #ifdef USING_BOOST_VARIANT
520  : public boost::static_visitor<variant>
521 #endif
522 {
523  variant operator()(bool b) const { return variant(b ? 1 : 0); }
524  variant operator()(int i) const { return variant(i); }
525  variant operator()(unsigned long long i) const { return variant(i); }
526  variant operator()(double i) const { return variant(i * 1000, variant::DECIMAL_VARIANT); }
527  // TODO: Should comma-separated lists of stuff be returned as a list?
528  // The challenge is to distinguish them from ordinary strings that happen to contain a comma
529  // (or should we assume that such strings will be translatable?).
530  variant operator()(const std::string& s) const { return variant(s); }
531  variant operator()(const t_string& s) const { return variant(s.str()); }
532  variant operator()(utils::monostate) const { return variant(); }
533 };
534 
535 variant config_callable::get_value(const std::string& key) const
536 {
537  if(cfg_.has_attribute(key)) {
538  return cfg_[key].apply_visitor(fai_variant_visitor());
539  } else if(cfg_.has_child(key)) {
540  std::vector<variant> result;
541  for(const auto& child : cfg_.child_range(key)) {
542  result.emplace_back(std::make_shared<config_callable>(child));
543  }
544 
545  return variant(result);
546  } else if(key == "__all_children") {
547  std::vector<variant> result;
548  for(const auto [child_key, child_cfg] : cfg_.all_children_view()) {
549  const variant cfg_child(std::make_shared<config_callable>(child_cfg));
550  const variant kv(std::make_shared<key_value_pair>(variant(child_key), cfg_child));
551  result.push_back(kv);
552  }
553 
554  return variant(result);
555  } else if(key == "__children") {
556  std::map<std::string, std::vector<variant>> build;
557  for(const auto [child_key, child_cfg] : cfg_.all_children_view()) {
558  const variant cfg_child(std::make_shared<config_callable>(child_cfg));
559  build[child_key].push_back(cfg_child);
560  }
561 
562  std::map<variant,variant> result;
563  for(auto& p : build) {
564  result[variant(p.first)] = variant(p.second);
565  }
566 
567  return variant(result);
568  } else if(key == "__attributes") {
569  std::map<variant,variant> result;
570  for(const auto& [key, value] : cfg_.attribute_range()) {
571  result[variant(key)] = value.apply_visitor(fai_variant_visitor());
572  }
573 
574  return variant(result);
575  }
576 
577  return variant();
578 }
579 
581 {
582  add_input(inputs, "__all_children");
583  add_input(inputs, "__children");
584  add_input(inputs, "__attributes");
585 
586  for(const auto& [key, _] : cfg_.attribute_range()) {
587  if(key.find_first_not_of(formula::id_chars) != std::string::npos) {
588  add_input(inputs, key);
589  }
590  }
591 }
592 
594 {
595  const config_callable* cfg_callable = dynamic_cast<const config_callable*>(callable);
596  if(cfg_callable == nullptr) {
597  return formula_callable::do_compare(callable);
598  }
599 
600  if(cfg_ == cfg_callable->get_config()) {
601  return 0;
602  }
603 
604  return cfg_.hash().compare(cfg_callable->get_config().hash());
605 }
606 
607 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))
608 {
609  type_ = TERRAIN_C;
610 }
611 
612 variant terrain_callable::get_value(const std::string& key) const
613 {
614  if(key == "x") {
615  return variant(loc_.wml_x());
616  } else if(key == "y") {
617  return variant(loc_.wml_y());
618  } else if(key == "loc") {
619  return variant(std::make_shared<location_callable>(loc_));
620  } else if(key == "id") {
621  return variant(std::string(t_.id()));
622  } else if(key == "name") {
623  return variant(t_.name());
624  } else if(key == "editor_name") {
625  return variant(t_.editor_name());
626  } else if(key == "description") {
627  return variant(t_.description());
628  } else if(key == "icon") {
629  return variant(t_.icon_image());
630  } else if(key == "light") {
631  return variant(t_.light_bonus(0));
632  } else if(key == "village") {
633  return variant(t_.is_village());
634  } else if(key == "castle") {
635  return variant(t_.is_castle());
636  } else if(key == "keep") {
637  return variant(t_.is_keep());
638  } else if(key == "healing") {
639  return variant(t_.gives_healing());
640  } else if(key == "owner_side") {
641  return variant(owner_);
642  }
643 
644  return variant();
645 }
646 
648 {
649  add_input(inputs, "x");
650  add_input(inputs, "y");
651  add_input(inputs, "loc");
652  add_input(inputs, "id");
653  add_input(inputs, "name");
654  add_input(inputs, "editor_name");
655  add_input(inputs, "description");
656  add_input(inputs, "icon");
657  add_input(inputs, "light");
658  add_input(inputs, "village");
659  add_input(inputs, "castle");
660  add_input(inputs, "keep");
661  add_input(inputs, "healing");
662  add_input(inputs, "owner_side");
663 }
664 
666 {
667  const terrain_callable* terr_callable = dynamic_cast<const terrain_callable*>(callable);
668  if(terr_callable == nullptr) {
669  return formula_callable::do_compare(callable);
670  }
671 
672  const map_location& other_loc = terr_callable->loc_;
673  return loc_.do_compare(other_loc);
674 }
675 
677  return board_.map();
678 }
679 
681 {
682  add_input(inputs, "w");
683  add_input(inputs, "h");
684 }
685 
686 variant gamemap_callable::get_value(const std::string& key) const
687 {
688  if(key == "terrain") {
689  int w = get_gamemap().w();
690  int h = get_gamemap().h();
691 
692  std::vector<variant> vars;
693  for(int i = 0; i < w; i++) {
694  for(int j = 0; j < h; j++) {
695  const map_location loc(i, j);
696  vars.emplace_back(std::make_shared<terrain_callable>(board_, loc));
697  }
698  }
699 
700  return variant(vars);
701  } else if(key == "gamemap") {
702  int w = get_gamemap().w();
703  int h = get_gamemap().h();
704 
705  std::map<variant, variant> vars;
706  for(int i = 0; i < w; i++) {
707  for(int j = 0; j < h; j++) {
708  const map_location loc(i, j);
709  vars.emplace(std::make_shared<location_callable>(loc), std::make_shared<terrain_callable>(board_, loc));
710  }
711  }
712 
713  return variant(vars);
714  } else if(key == "w") {
715  return variant(get_gamemap().w());
716  } else if(key == "h") {
717  return variant(get_gamemap().h());
718  } else {
719  return variant();
720  }
721 }
722 
724 {
725  add_input(inputs, "side_number");
726  add_input(inputs, "id");
727  add_input(inputs, "gold");
728  add_input(inputs, "start_gold");
729  add_input(inputs, "base_income");
730  add_input(inputs, "total_income");
731  add_input(inputs, "village_gold");
732  add_input(inputs, "village_support");
733  add_input(inputs, "recall_cost");
734  add_input(inputs, "is_human");
735  add_input(inputs, "is_ai");
736  add_input(inputs, "is_network");
737  add_input(inputs, "fog");
738  add_input(inputs, "shroud");
739  add_input(inputs, "hidden");
740  add_input(inputs, "flag");
741  add_input(inputs, "flag_icon");
742  add_input(inputs, "team_name");
743  add_input(inputs, "faction");
744  add_input(inputs, "faction_name");
745  add_input(inputs, "color");
746  add_input(inputs, "share_vision");
747  add_input(inputs, "carryover_bonus");
748  add_input(inputs, "carryover_percentage");
749  add_input(inputs, "carryover_add");
750  add_input(inputs, "recruit");
751  add_input(inputs, "wml_vars");
752 }
753 
754 variant team_callable::get_value(const std::string& key) const
755 {
756  if(key == "side") {
757  deprecated_message("team.side", DEP_LEVEL::INDEFINITE, version_info("1.17"), "Use side_number instead.");
758  return variant(team_.side());
759  } else if(key == "side_number") {
760  return variant(team_.side());
761  } else if(key == "id") {
762  return variant(team_.save_id());
763  } else if(key == "save_id") {
764  return variant(team_.save_id());
765  } else if(key == "gold") {
766  return variant(team_.gold());
767  } else if(key == "start_gold") {
768  return variant(team_.start_gold());
769  } else if(key == "base_income") {
770  return variant(team_.base_income());
771  } else if(key == "total_income") {
772  return variant(team_.total_income());
773  } else if(key == "village_gold") {
774  return variant(team_.village_gold());
775  } else if(key == "village_support") {
776  return variant(team_.village_support());
777  } else if(key == "recall_cost") {
778  return variant(team_.recall_cost());
779  } else if(key == "is_human") {
780  return variant(team_.is_local_human());
781  } else if(key == "is_ai") {
782  return variant(team_.is_local_ai());
783  } else if(key == "is_network") {
784  return variant(team_.is_network());
785  } else if(key == "fog") {
786  return variant(team_.uses_fog());
787  } else if(key == "shroud") {
788  return variant(team_.uses_shroud());
789  } else if(key == "hidden") {
790  return variant(team_.hidden());
791  } else if(key == "flag") {
792  return variant(team_.flag());
793  } else if(key == "flag_icon") {
794  return variant(team_.flag_icon());
795  } else if(key == "team_name") {
796  return variant(team_.team_name());
797  } else if(key == "faction") {
798  return variant(team_.faction());
799  } else if(key == "faction_name") {
800  return variant(team_.faction_name());
801  } else if(key == "color") {
802  return variant(team_.color());
803  } else if(key == "share_vision") {
805  } else if(key == "carryover_bonus") {
807  } else if(key == "carryover_percentage") {
809  } else if(key == "carryover_add") {
810  return variant(team_.carryover_add());
811  } else if(key == "recruit") {
812  std::vector<variant> result;
813  for(const auto& recruit : team_.recruits()) {
814  result.emplace_back(recruit);
815  }
816  return variant(result);
817  } else if(key == "recall") {
818  std::vector<variant> result;
819  for(const auto& u : team_.recall_list()) {
820  result.push_back(std::make_shared<unit_callable>(*u));
821  }
822  return variant(result);
823  } else if(key == "wml_vars") {
824  return variant(std::make_shared<config_callable>(team_.variables()));
825  }
826 
827  return variant();
828 }
829 
830 variant set_var_callable::get_value(const std::string& key) const
831 {
832  if(key == "key") {
833  return variant(key_);
834  } else if(key == "value") {
835  return value_;
836  }
837 
838  return variant();
839 }
840 
842 {
843  add_input(inputs, "key");
844  add_input(inputs, "value");
845 }
846 
848 {
849  //if(infinite_loop_guardian_.set_var_check()) {
850  if(auto obj = ctxt.try_convert<formula_callable>()) {
851  LOG_SF << "Setting variable: " << key_ << " -> " << value_.to_debug_string();
852  obj->mutate_value(key_, value_);
853  return variant(true);
854  }
855  //}
856  //too many calls in a row - possible infinite loop
857  ERR_SF << "ERROR #" << 5001 << " while executing 'set_var' formula function";
858 
859  return variant(std::make_shared<safe_call_result>(fake_ptr(), 5001));
860 }
861 
862 variant safe_call_callable::get_value(const std::string& key) const
863 {
864  if(key == "main") {
865  return variant(main_);
866  } else if(key == "backup") {
867  return variant(backup_);
868  }
869 
870  return variant();
871 }
872 
874 {
875  add_input(inputs, "main");
876  add_input(inputs, "backup");
877 }
878 
880 {
881  variant res;
882  if(auto action = main_.try_convert<action_callable>()) {
883  res = action->execute_self(ctxt);
884  }
885 
886  if(res.try_convert<safe_call_result>()) {
887  /* If we have safe_call formula and either an error occurred, or the current action
888  * was not recognized, then evaluate backup formula from safe_call and execute it
889  * during the next loop
890  */
891 
892  map_formula_callable callable(ctxt.as_callable());
893  callable.add("error", res);
894 
895  /* Store the result in safe_call_callable in case we would like to display it to the user,
896  * for example if this formula was executed from the commandline.
897  */
898  backup_ = get_backup()->evaluate(callable);
899  ctxt.execute_variant(backup_);
900  }
901  return variant(true);
902 }
903 
904 variant safe_call_result::get_value(const std::string& key) const
905 {
906  if(key == "status") {
907  return variant(status_);
908  } else if(key == "object") {
909  if(failed_callable_) {
910  return variant(failed_callable_);
911  }
912 
913  return variant();
914  } else if(key == "current_loc" && current_unit_location_ != map_location()) {
915  return variant(std::make_shared<location_callable>(current_unit_location_));
916  }
917 
918  return variant();
919 }
920 
922 {
923  add_input(inputs, "status");
924  add_input(inputs, "object");
925 
927  add_input(inputs, "current_loc");
928  }
929 }
930 
932 {
933  add_input(inputs, "turn_number");
934  add_input(inputs, "time_of_day");
935  add_input(inputs, "side_number");
936  add_input(inputs, "sides");
937  add_input(inputs, "units");
938  add_input(inputs, "map");
939 }
940 
941 variant gamestate_callable::get_value(const std::string &key) const
942 {
943  if(key == "turn_number") {
944  return variant(resources::tod_manager->turn());
945  } else if(key == "time_of_day") {
946  return variant(resources::tod_manager->get_time_of_day().id);
947  } else if(key == "side_number") {
948  return variant(resources::controller->current_side());
949  } else if(key == "sides") {
950  std::vector<variant> vars;
951  for(const auto& team : resources::gameboard->teams()) {
952  vars.emplace_back(std::make_shared<team_callable>(team));
953  }
954  return variant(vars);
955  } else if(key == "units") {
956  std::vector<variant> vars;
957  for(const auto& unit : resources::gameboard->units()) {
958  vars.emplace_back(std::make_shared<unit_callable>(unit));
959  }
960  return variant(vars);
961  } else if(key == "map") {
962  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
963  }
964 
965  return variant();
966 }
967 
969 {
970  add_input(inputs, "event");
971  add_input(inputs, "event_id");
972  add_input(inputs, "event_data");
973  add_input(inputs, "loc");
974  add_input(inputs, "unit");
975  add_input(inputs, "weapon");
976  add_input(inputs, "second_loc");
977  add_input(inputs, "second_unit");
978  add_input(inputs, "second_weapon");
979 }
980 
981 variant event_callable::get_value(const std::string &key) const
982 {
983  if(key == "event") {
984  return variant(event_info.name);
985  } else if(key == "event_id") {
986  return variant(event_info.id);
987  } else if(key == "loc") {
988  return variant(std::make_shared<location_callable>(event_info.loc1));
989  } else if(key == "second_loc") {
990  return variant(std::make_shared<location_callable>(event_info.loc2));
991  } else if(key == "event_data") {
992  return variant(std::make_shared<config_callable>(event_info.data));
993  } else if(key == "unit") {
994  if(auto u1 = event_info.loc1.get_unit()) {
995  return variant(std::make_shared<unit_callable>(*u1));
996  }
997  } else if(key == "second_unit") {
998  if(auto u2 = event_info.loc2.get_unit()) {
999  return variant(std::make_shared<unit_callable>(*u2));
1000  }
1001  } else if(key == "weapon") {
1002  if(event_info.data.has_child("first")) {
1003  first_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("first"));
1004  return variant(std::make_shared<attack_type_callable>(*first_weapon));
1005  }
1006  } else if(key == "second_weapon") {
1007  if(event_info.data.has_child("second")) {
1008  second_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("second"));
1009  return variant(std::make_shared<attack_type_callable>(*second_weapon));
1010  }
1011  }
1012 
1013  return variant();
1014 }
1015 
1017 {
1018  add_input(inputs, "red");
1019  add_input(inputs, "green");
1020  add_input(inputs, "blue");
1021  add_input(inputs, "alpha");
1022 }
1023 
1024 variant color_callable::get_value(const std::string& key) const
1025 {
1026  if(key == "red") {
1027  return variant(clr_.r);
1028  } else if(key == "green") {
1029  return variant(clr_.g);
1030  } else if(key == "blue") {
1031  return variant(clr_.b);
1032  } else if(key == "alpha") {
1033  return variant(clr_.a);
1034  }
1035 
1036  return variant();
1037 }
1038 
1039 } // namespace wfl
map_location loc
Definition: move.cpp:172
#define LOG_SF
static lg::log_domain log_scripting_formula("scripting/formula")
#define ERR_SF
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition: config.cpp:362
const_attr_itors attribute_range() const
Definition: config.cpp:756
auto all_children_view() const
In-order iteration over all children.
Definition: config.hpp:796
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:312
bool has_attribute(config_key_type key) const
Definition: config.cpp:157
child_itors child_range(config_key_type key)
Definition: config.cpp:268
std::string hash() const
Definition: config.cpp:1279
Abstract class for exposing game data that doesn't depend on the GUI, however which for historical re...
virtual const gamemap & map() const =0
int w() const
Effective map width.
Definition: map.hpp:50
int h() const
Effective map height.
Definition: map.hpp:53
Encapsulates the map of the game.
Definition: map.hpp:172
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:74
bool uses_shroud() const
Definition: team.hpp:340
const std::string & color() const
Definition: team.hpp:279
config & variables()
Definition: team.hpp:385
int side() const
Definition: team.hpp:179
const std::string & faction() const
Definition: team.hpp:333
int village_support() const
Definition: team.hpp:204
int recall_cost() const
Definition: team.hpp:195
const std::string & team_name() const
Definition: team.hpp:319
bool is_local_human() const
Definition: team.hpp:290
int village_gold() const
Definition: team.hpp:194
team_shared_vision::type share_vision() const
Definition: team.hpp:414
int gold() const
Definition: team.hpp:180
const t_string & faction_name() const
Definition: team.hpp:334
bool carryover_add() const
Definition: team.hpp:380
int carryover_percentage() const
Definition: team.hpp:378
bool is_network() const
Definition: team.hpp:285
int total_income() const
Definition: team.hpp:198
const std::string & save_id() const
Definition: team.hpp:254
bool is_local_ai() const
Definition: team.hpp:291
double carryover_bonus() const
Definition: team.hpp:382
int start_gold() const
Definition: team.hpp:181
const std::string & flag_icon() const
Definition: team.hpp:324
int base_income() const
Definition: team.cpp:402
bool uses_fog() const
Definition: team.hpp:341
const std::string & flag() const
Definition: team.hpp:323
bool hidden() const
Definition: team.hpp:370
recall_list_manager & recall_list()
Definition: team.hpp:238
const std::set< std::string > & recruits() const
Definition: team.hpp:246
const std::string & icon_image() const
Definition: terrain.hpp:44
const t_string & name() const
Definition: terrain.hpp:48
bool is_keep() const
Definition: terrain.hpp:146
bool is_castle() const
Definition: terrain.hpp:145
const std::string & id() const
Definition: terrain.hpp:52
const t_string & description() const
Definition: terrain.hpp:50
bool is_village() const
Definition: terrain.hpp:144
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:135
const t_string & editor_name() const
Definition: terrain.hpp:49
int gives_healing() const
Definition: terrain.hpp:143
const std::string & id() const
Definition: race.hpp:35
std::string race_id() const
Returns the ID of this type's race without the need to build the type.
Definition: types.hpp:275
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:144
int hitpoints() const
Definition: types.hpp:164
const_attack_itors attacks() const
Definition: types.cpp:500
const std::string & usage() const
Definition: types.hpp:178
int movement() const
Definition: types.hpp:169
int cost() const
Definition: types.hpp:175
int experience_needed(bool with_acceleration=true) const
Definition: types.cpp:534
bool musthave_status(const std::string &status) const
Definition: types.cpp:629
std::vector< std::string > get_ability_list() const
Definition: types.cpp:561
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:141
config::const_child_itors possible_traits() const
Definition: types.hpp:234
int level() const
Definition: types.hpp:167
unit_alignments::type alignment() const
Definition: types.hpp:196
int recall_cost() const
Definition: types.hpp:168
This class represents a single unit of a specific type.
Definition: unit.hpp:132
Represents version numbers.
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
attack_type_callable(const attack_type &attack)
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
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
int do_compare(const formula_callable *callable) const override
const config & get_config() const
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
std::shared_ptr< attack_type > second_weapon
const game_events::queued_event & event_info
std::shared_ptr< attack_type > first_weapon
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
formula_input_vector inputs() const
Definition: callable.hpp:63
static void add_input(formula_input_vector &inputs, const std::string &key, formula_access access_type=formula_access::read_only)
Definition: callable.hpp:136
virtual int do_compare(const formula_callable *callable) const
Definition: callable.hpp:146
static variant convert_vector(const std::vector< T > &input_vector)
Definition: callable.hpp:126
static variant convert_set(const std::set< T > &input_set)
Definition: callable.hpp:115
static const char *const id_chars
Definition: formula.hpp:83
const display_context & board_
const gamemap & get_gamemap() const
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
variant get_value(const std::string &key) const override
void get_inputs(formula_input_vector &inputs) const override
const map_location & loc() const
void serialize_to_string(std::string &str) const override
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
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
const expression_ptr & get_backup() const
variant execute_self(variant ctxt) override
variant get_value(const std::string &key) const override
void get_inputs(formula_input_vector &inputs) const override
const map_location current_unit_location_
void get_inputs(formula_input_vector &inputs) const override
const_formula_callable_ptr failed_callable_
variant get_value(const std::string &key) const override
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
const std::string & key() const
variant execute_self(variant ctxt) override
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
variant get_value(const std::string &key) const override
const terrain_type & t_
terrain_callable(const display_context &m, const map_location &loc)
void get_inputs(formula_input_vector &inputs) const override
const map_location loc_
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
const map_location & loc_
void get_inputs(formula_input_vector &inputs) const override
unit_callable(const map_location &loc, const unit &u)
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
int do_compare(const formula_callable *callable) const override
void get_inputs(formula_input_vector &inputs) const override
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:653
std::shared_ptr< T > try_convert() const
Definition: variant.hpp:97
const_formula_callable_ptr as_callable() const
Definition: variant.hpp:90
@ DECIMAL_VARIANT
Definition: variant.hpp:31
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:643
Definitions for the interface to Wesnoth Markup Language (WML).
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:29
const config * cfg
std::size_t i
Definition: function.cpp:1032
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
Definition: gettext.hpp:97
std::vector< std::string > get_ability_list() const
Get a list of all abilities by ID.
Definition: abilities.cpp:294
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:520
unit_alignments::type alignment() const
The alignment of this unit.
Definition: unit.hpp:490
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:919
int level() const
The current level of this unit.
Definition: unit.hpp:574
std::string usage() const
Gets this unit's usage.
Definition: unit.hpp:701
const std::string & get_role() const
Gets this unit's role.
Definition: unit.hpp:684
const std::vector< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
Definition: unit.hpp:639
const std::string & variation() const
The ID of the variation of this unit's type.
Definition: unit.hpp:587
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:514
int cost() const
How much gold is required to recruit this unit.
Definition: unit.hpp:648
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1423
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1958
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition: unit.hpp:735
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
Definition: unit.cpp:1406
const unit_race * race() const
Gets this unit's race.
Definition: unit.hpp:508
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:538
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:627
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:379
int side() const
The side this unit belongs to.
Definition: unit.hpp:342
config & variables()
Gets any user-defined variables this unit 'owns'.
Definition: unit.hpp:718
std::size_t underlying_id() const
This unit's unique internal ID.
Definition: unit.hpp:391
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:544
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:480
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:402
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
Definition: unit.hpp:243
attack_itors attacks()
Gets an iterator over this unit's attacks.
Definition: unit.hpp:941
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
Definition: unit.hpp:992
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:1008
std::size_t advancements_count() const
Definition: unit.hpp:1591
std::size_t traits_count() const
Definition: unit.hpp:1581
std::size_t objects_count() const
Definition: unit.hpp:1586
bool get_emit_zoc() const
Gets the raw zone-of-control flag, disregarding incapacitated.
Definition: unit.hpp:1418
const movetype & movement_type() const
Get the unit's movement type.
Definition: unit.hpp:1504
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1356
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1340
map_location::direction facing() const
The current direction this unit is facing within its hex.
Definition: unit.hpp:1447
bool resting() const
Checks whether this unit is 'resting'.
Definition: unit.hpp:1400
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1540
std::vector< std::string > get_advancements_list() const
Definition: unit.hpp:1153
std::vector< std::string > get_objects_list() const
Definition: unit.hpp:1148
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
Definition: unit.cpp:1728
bool is_healthy() const
Gets whether this unit is healthy - ie, always rest heals.
Definition: unit.hpp:1308
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
Definition: unit.hpp:1302
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has, including hidden traits.
Definition: unit.hpp:1143
Standard logging facilities (interface).
::tod_manager * tod_manager
Definition: resources.cpp:29
game_board * gameboard
Definition: resources.cpp:20
play_controller * controller
Definition: resources.cpp:21
Definition: callable.hpp:26
std::vector< formula_input > formula_input_vector
int w
Definition: pathfind.cpp:188
static std::string get_location(const std::string &loc)
Define the game's event mechanism.
const std::string & gender_string(unit_race::GENDER gender)
Definition: race.cpp:138
unit_const_ptr get_unit() const
entity_location loc1
Definition: pump.hpp:65
entity_location loc2
Definition: pump.hpp:66
std::string name
Definition: pump.hpp:63
Encapsulates the map of the game.
Definition: location.hpp:45
static std::string write_direction(direction dir)
Definition: location.cpp:154
int wml_y() const
Definition: location.hpp:186
static const map_location & null_location()
Definition: location.hpp:102
int wml_x() const
Definition: location.hpp:185
int do_compare(const map_location &a) const
three-way comparator
Definition: location.hpp:126
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
variant operator()(utils::monostate) const
variant operator()(bool b) const
variant operator()(const std::string &s) const
variant operator()(int i) const
variant operator()(unsigned long long i) const
variant operator()(const t_string &s) const
variant operator()(double i) const
mock_party p
static map_location::direction s
#define h
#define b