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