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