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