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