The Battle for Wesnoth  1.19.0-dev
callable_objects.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "formula/callable_objects.hpp"
17 
18 #include "config.hpp"
19 #include "formula/function.hpp"
20 #include "map/map.hpp"
21 #include "display_context.hpp"
22 #include "team.hpp"
23 #include "units/attack_type.hpp"
25 #include "units/unit.hpp"
26 #include "units/types.hpp"
27 #include "log.hpp"
28 #include "recall_list_manager.hpp"
29 #include "deprecation.hpp"
30 #include "game_board.hpp"
31 #include "game_version.hpp"
32 #include "resources.hpp"
33 #include "tod_manager.hpp"
34 #include "play_controller.hpp"
35 #include "game_events/pump.hpp"
36 
37 static lg::log_domain log_scripting_formula("scripting/formula");
38 #define LOG_SF LOG_STREAM(info, log_scripting_formula)
39 #define ERR_SF LOG_STREAM(err, log_scripting_formula)
40 
41 namespace wfl
42 {
43 
44 variant location_callable::get_value(const std::string& key) const
45 {
46  if(key == "x") {
47  return variant(loc_.wml_x());
48  } else if(key == "y") {
49  return variant(loc_.wml_y());
50  }
51 
52  return variant();
53 }
54 
56 {
57  add_input(inputs, "x");
58  add_input(inputs, "y");
59 }
60 
62 {
63  const location_callable* loc_callable = dynamic_cast<const location_callable*>(callable);
64  if(loc_callable == nullptr) {
65  return formula_callable::do_compare(callable);
66  }
67 
68  const map_location& other_loc = loc_callable->loc();
69  return loc_.do_compare(other_loc);
70 }
71 
72 void location_callable::serialize_to_string(std::string& str) const
73 {
74  std::ostringstream s;
75  s << "loc(" << (loc_.wml_x()) << "," << (loc_.wml_y()) << ")";
76  str += s.str();
77 }
78 
79 attack_type_callable::attack_type_callable(const attack_type& attack) : att_(attack.shared_from_this())
80 {
82 }
83 
84 variant attack_type_callable::get_value(const std::string& key) const
85 {
86  if(key == "id" || key == "name") {
87  return variant(att_->id());
88  } else if(key == "description") {
89  return variant(att_->name());
90  } else if(key == "type") {
91  return variant(att_->type());
92  } else if(key == "icon") {
93  return variant(att_->icon());
94  } else if(key == "range") {
95  return variant(att_->range());
96  } else if(key == "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_jamming().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 == "undead") {
439  return variant(u_.musthave_status("unpoisonable") && u_.musthave_status("undrainable") && u_.musthave_status("unplagueable"));
440  } else if(key == "unpoisonable") {
441  return variant(u_.musthave_status("unpoisonable"));
442  } else if(key == "unslowable") {
443  return variant(u_.musthave_status("unslowable"));
444  } else if(key == "unpetrifiable") {
445  return variant(u_.musthave_status("unpetrifiable"));
446  } else if(key == "undrainable") {
447  return variant(u_.musthave_status("undrainable"));
448  } else if(key == "unplagueable") {
449  return variant(u_.musthave_status("unplagueable"));
450  } else if(key == "cost") {
451  return variant(u_.cost());
452  } else if(key == "recall_cost") {
453  return variant(u_.recall_cost());
454  } else if(key == "usage") {
455  return variant(u_.usage());
456  }
457 
458  return variant();
459 }
460 
462 {
463  add_input(inputs, "id");
464  add_input(inputs, "type");
465  add_input(inputs, "race");
466  add_input(inputs, "alignment");
467  add_input(inputs, "abilities");
468  add_input(inputs, "traits");
469  add_input(inputs, "attacks");
470  add_input(inputs, "hitpoints");
471  add_input(inputs, "experience");
472  add_input(inputs, "level");
473  add_input(inputs, "total_movement");
474  add_input(inputs, "undead");
475  add_input(inputs, "cost");
476  add_input(inputs, "recall_cost");
477  add_input(inputs, "usage");
478 }
479 
481 {
482  const unit_type_callable* u_callable = dynamic_cast<const unit_type_callable*>(callable);
483  if(u_callable == nullptr) {
484  return formula_callable::do_compare(callable);
485  }
486 
487  return u_.id().compare(u_callable->u_.id());
488 }
489 
491 #ifdef USING_BOOST_VARIANT
492  : public boost::static_visitor<variant>
493 #endif
494 {
495  variant operator()(bool b) const { return variant(b ? 1 : 0); }
496  variant operator()(int i) const { return variant(i); }
497  variant operator()(unsigned long long i) const { return variant(i); }
498  variant operator()(double i) const { return variant(i * 1000, variant::DECIMAL_VARIANT); }
499  // TODO: Should comma-separated lists of stuff be returned as a list?
500  // The challenge is to distinguish them from ordinary strings that happen to contain a comma
501  // (or should we assume that such strings will be translatable?).
502  variant operator()(const std::string& s) const { return variant(s); }
503  variant operator()(const t_string& s) const { return variant(s.str()); }
504  variant operator()(utils::monostate) const { return variant(); }
505 };
506 
507 variant config_callable::get_value(const std::string& key) const
508 {
509  if(cfg_.has_attribute(key)) {
510  return cfg_[key].apply_visitor(fai_variant_visitor());
511  } else if(cfg_.has_child(key)) {
512  std::vector<variant> result;
513  for(const auto& child : cfg_.child_range(key)) {
514  result.emplace_back(std::make_shared<config_callable>(child));
515  }
516 
517  return variant(result);
518  } else if(key == "__all_children") {
519  std::vector<variant> result;
520  for(const auto child : cfg_.all_children_range()) {
521  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
522  const variant kv(std::make_shared<key_value_pair>(variant(child.key), cfg_child));
523  result.push_back(kv);
524  }
525 
526  return variant(result);
527  } else if(key == "__children") {
528  std::map<std::string, std::vector<variant>> build;
529  for(const auto child : cfg_.all_children_range()) {
530  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
531  build[child.key].push_back(cfg_child);
532  }
533 
534  std::map<variant,variant> result;
535  for(auto& p : build) {
536  result[variant(p.first)] = variant(p.second);
537  }
538 
539  return variant(result);
540  } else if(key == "__attributes") {
541  std::map<variant,variant> result;
542  for(const auto& val : cfg_.attribute_range()) {
543  result[variant(val.first)] = val.second.apply_visitor(fai_variant_visitor());
544  }
545 
546  return variant(result);
547  }
548 
549  return variant();
550 }
551 
553 {
554  add_input(inputs, "__all_children");
555  add_input(inputs, "__children");
556  add_input(inputs, "__attributes");
557 
558  for(const auto& val : cfg_.attribute_range()) {
559  if(val.first.find_first_not_of(formula::id_chars) != std::string::npos) {
560  add_input(inputs, val.first);
561  }
562  }
563 }
564 
566 {
567  const config_callable* cfg_callable = dynamic_cast<const config_callable*>(callable);
568  if(cfg_callable == nullptr) {
569  return formula_callable::do_compare(callable);
570  }
571 
572  if(cfg_ == cfg_callable->get_config()) {
573  return 0;
574  }
575 
576  return cfg_.hash().compare(cfg_callable->get_config().hash());
577 }
578 
579 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))
580 {
581  type_ = TERRAIN_C;
582 }
583 
584 variant terrain_callable::get_value(const std::string& key) const
585 {
586  if(key == "x") {
587  return variant(loc_.wml_x());
588  } else if(key == "y") {
589  return variant(loc_.wml_y());
590  } else if(key == "loc") {
591  return variant(std::make_shared<location_callable>(loc_));
592  } else if(key == "id") {
593  return variant(std::string(t_.id()));
594  } else if(key == "name") {
595  return variant(t_.name());
596  } else if(key == "editor_name") {
597  return variant(t_.editor_name());
598  } else if(key == "description") {
599  return variant(t_.description());
600  } else if(key == "icon") {
601  return variant(t_.icon_image());
602  } else if(key == "light") {
603  return variant(t_.light_bonus(0));
604  } else if(key == "village") {
605  return variant(t_.is_village());
606  } else if(key == "castle") {
607  return variant(t_.is_castle());
608  } else if(key == "keep") {
609  return variant(t_.is_keep());
610  } else if(key == "healing") {
611  return variant(t_.gives_healing());
612  } else if(key == "owner") {
613  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.");
614  return variant(owner_ - 1);
615  } else if(key == "owner_side") {
616  return variant(owner_);
617  }
618 
619  return variant();
620 }
621 
623 {
624  add_input(inputs, "x");
625  add_input(inputs, "y");
626  add_input(inputs, "loc");
627  add_input(inputs, "id");
628  add_input(inputs, "name");
629  add_input(inputs, "editor_name");
630  add_input(inputs, "description");
631  add_input(inputs, "icon");
632  add_input(inputs, "light");
633  add_input(inputs, "village");
634  add_input(inputs, "castle");
635  add_input(inputs, "keep");
636  add_input(inputs, "healing");
637  add_input(inputs, "owner_side");
638 }
639 
641 {
642  const terrain_callable* terr_callable = dynamic_cast<const terrain_callable*>(callable);
643  if(terr_callable == nullptr) {
644  return formula_callable::do_compare(callable);
645  }
646 
647  const map_location& other_loc = terr_callable->loc_;
648  return loc_.do_compare(other_loc);
649 }
650 
652  return board_.map();
653 }
654 
656 {
657  add_input(inputs, "w");
658  add_input(inputs, "h");
659 }
660 
661 variant gamemap_callable::get_value(const std::string& key) const
662 {
663  if(key == "terrain") {
664  int w = get_gamemap().w();
665  int h = get_gamemap().h();
666 
667  std::vector<variant> vars;
668  for(int i = 0; i < w; i++) {
669  for(int j = 0; j < h; j++) {
670  const map_location loc(i, j);
671  vars.emplace_back(std::make_shared<terrain_callable>(board_, loc));
672  }
673  }
674 
675  return variant(vars);
676  } else if(key == "gamemap") {
677  int w = get_gamemap().w();
678  int h = get_gamemap().h();
679 
680  std::map<variant, variant> vars;
681  for(int i = 0; i < w; i++) {
682  for(int j = 0; j < h; j++) {
683  const map_location loc(i, j);
684  vars.emplace(std::make_shared<location_callable>(loc), std::make_shared<terrain_callable>(board_, loc));
685  }
686  }
687 
688  return variant(vars);
689  } else if(key == "w") {
690  return variant(get_gamemap().w());
691  } else if(key == "h") {
692  return variant(get_gamemap().h());
693  } else {
694  return variant();
695  }
696 }
697 
699 {
700  add_input(inputs, "side_number");
701  add_input(inputs, "id");
702  add_input(inputs, "gold");
703  add_input(inputs, "start_gold");
704  add_input(inputs, "base_income");
705  add_input(inputs, "total_income");
706  add_input(inputs, "village_gold");
707  add_input(inputs, "village_support");
708  add_input(inputs, "recall_cost");
709  add_input(inputs, "is_human");
710  add_input(inputs, "is_ai");
711  add_input(inputs, "is_network");
712  add_input(inputs, "fog");
713  add_input(inputs, "shroud");
714  add_input(inputs, "hidden");
715  add_input(inputs, "flag");
716  add_input(inputs, "flag_icon");
717  add_input(inputs, "team_name");
718  add_input(inputs, "faction");
719  add_input(inputs, "faction_name");
720  add_input(inputs, "color");
721  add_input(inputs, "share_vision");
722  add_input(inputs, "carryover_bonus");
723  add_input(inputs, "carryover_percentage");
724  add_input(inputs, "carryover_add");
725  add_input(inputs, "recruit");
726  add_input(inputs, "wml_vars");
727 }
728 
729 variant team_callable::get_value(const std::string& key) const
730 {
731  if(key == "side") {
732  deprecated_message("team.side", DEP_LEVEL::INDEFINITE, version_info("1.17"), "Use side_number instead.");
733  return variant(team_.side());
734  } else if(key == "side_number") {
735  return variant(team_.side());
736  } else if(key == "id") {
737  return variant(team_.save_id());
738  } else if(key == "save_id") {
739  return variant(team_.save_id());
740  } else if(key == "gold") {
741  return variant(team_.gold());
742  } else if(key == "start_gold") {
743  return variant(team_.start_gold());
744  } else if(key == "base_income") {
745  return variant(team_.base_income());
746  } else if(key == "total_income") {
747  return variant(team_.total_income());
748  } else if(key == "village_gold") {
749  return variant(team_.village_gold());
750  } else if(key == "village_support") {
751  return variant(team_.village_support());
752  } else if(key == "recall_cost") {
753  return variant(team_.recall_cost());
754  } else if(key == "is_human") {
755  return variant(team_.is_local_human());
756  } else if(key == "is_ai") {
757  return variant(team_.is_local_ai());
758  } else if(key == "is_network") {
759  return variant(team_.is_network());
760  } else if(key == "fog") {
761  return variant(team_.uses_fog());
762  } else if(key == "shroud") {
763  return variant(team_.uses_shroud());
764  } else if(key == "hidden") {
765  return variant(team_.hidden());
766  } else if(key == "flag") {
767  return variant(team_.flag());
768  } else if(key == "flag_icon") {
769  return variant(team_.flag_icon());
770  } else if(key == "team_name") {
771  return variant(team_.team_name());
772  } else if(key == "faction") {
773  return variant(team_.faction());
774  } else if(key == "faction_name") {
775  return variant(team_.faction_name());
776  } else if(key == "color") {
777  return variant(team_.color());
778  } else if(key == "share_vision") {
780  } else if(key == "carryover_bonus") {
782  } else if(key == "carryover_percentage") {
784  } else if(key == "carryover_add") {
785  return variant(team_.carryover_add());
786  } else if(key == "recruit") {
787  std::vector<variant> result;
788  for(const auto& recruit : team_.recruits()) {
789  result.emplace_back(recruit);
790  }
791  return variant(result);
792  } else if(key == "recall") {
793  std::vector<variant> result;
794  for(const auto& u : team_.recall_list()) {
795  result.push_back(std::make_shared<unit_callable>(*u));
796  }
797  return variant(result);
798  } else if(key == "wml_vars") {
799  return variant(std::make_shared<config_callable>(team_.variables()));
800  }
801 
802  return variant();
803 }
804 
805 variant set_var_callable::get_value(const std::string& key) const
806 {
807  if(key == "key") {
808  return variant(key_);
809  } else if(key == "value") {
810  return value_;
811  }
812 
813  return variant();
814 }
815 
817 {
818  add_input(inputs, "key");
819  add_input(inputs, "value");
820 }
821 
823 {
824  //if(infinite_loop_guardian_.set_var_check()) {
825  if(auto obj = ctxt.try_convert<formula_callable>()) {
826  LOG_SF << "Setting variable: " << key_ << " -> " << value_.to_debug_string();
827  obj->mutate_value(key_, value_);
828  return variant(true);
829  }
830  //}
831  //too many calls in a row - possible infinite loop
832  ERR_SF << "ERROR #" << 5001 << " while executing 'set_var' formula function";
833 
834  return variant(std::make_shared<safe_call_result>(fake_ptr(), 5001));
835 }
836 
837 variant safe_call_callable::get_value(const std::string& key) const
838 {
839  if(key == "main") {
840  return variant(main_);
841  } else if(key == "backup") {
842  return variant(backup_);
843  }
844 
845  return variant();
846 }
847 
849 {
850  add_input(inputs, "main");
851  add_input(inputs, "backup");
852 }
853 
855 {
856  variant res;
857  if(auto action = main_.try_convert<action_callable>()) {
858  res = action->execute_self(ctxt);
859  }
860 
861  if(res.try_convert<safe_call_result>()) {
862  /* If we have safe_call formula and either an error occurred, or the current action
863  * was not recognized, then evaluate backup formula from safe_call and execute it
864  * during the next loop
865  */
866 
867  map_formula_callable callable(ctxt.as_callable());
868  callable.add("error", res);
869 
870  /* Store the result in safe_call_callable in case we would like to display it to the user,
871  * for example if this formula was executed from the commandline.
872  */
873  backup_ = get_backup()->evaluate(callable);
874  ctxt.execute_variant(backup_);
875  }
876  return variant(true);
877 }
878 
879 variant safe_call_result::get_value(const std::string& key) const
880 {
881  if(key == "status") {
882  return variant(status_);
883  } else if(key == "object") {
884  if(failed_callable_) {
885  return variant(failed_callable_);
886  }
887 
888  return variant();
889  } else if(key == "current_loc" && current_unit_location_ != map_location()) {
890  return variant(std::make_shared<location_callable>(current_unit_location_));
891  }
892 
893  return variant();
894 }
895 
897 {
898  add_input(inputs, "status");
899  add_input(inputs, "object");
900 
902  add_input(inputs, "current_loc");
903  }
904 }
905 
907 {
908  add_input(inputs, "turn_number");
909  add_input(inputs, "time_of_day");
910  add_input(inputs, "side_number");
911  add_input(inputs, "sides");
912  add_input(inputs, "units");
913  add_input(inputs, "map");
914 }
915 
916 variant gamestate_callable::get_value(const std::string &key) const
917 {
918  if(key == "turn_number") {
919  return variant(resources::tod_manager->turn());
920  } else if(key == "time_of_day") {
921  return variant(resources::tod_manager->get_time_of_day().id);
922  } else if(key == "side_number") {
923  return variant(resources::controller->current_side());
924  } else if(key == "sides") {
925  std::vector<variant> vars;
926  for(const auto& team : resources::gameboard->teams()) {
927  vars.emplace_back(std::make_shared<team_callable>(team));
928  }
929  return variant(vars);
930  } else if(key == "units") {
931  std::vector<variant> vars;
932  for(const auto& unit : resources::gameboard->units()) {
933  vars.emplace_back(std::make_shared<unit_callable>(unit));
934  }
935  return variant(vars);
936  } else if(key == "map") {
937  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
938  }
939 
940  return variant();
941 }
942 
944 {
945  add_input(inputs, "event");
946  add_input(inputs, "event_id");
947  add_input(inputs, "event_data");
948  add_input(inputs, "loc");
949  add_input(inputs, "unit");
950  add_input(inputs, "weapon");
951  add_input(inputs, "second_loc");
952  add_input(inputs, "second_unit");
953  add_input(inputs, "second_weapon");
954 }
955 
956 variant event_callable::get_value(const std::string &key) const
957 {
958  if(key == "event") {
959  return variant(event_info.name);
960  } else if(key == "event_id") {
961  return variant(event_info.id);
962  } else if(key == "loc") {
963  return variant(std::make_shared<location_callable>(event_info.loc1));
964  } else if(key == "second_loc") {
965  return variant(std::make_shared<location_callable>(event_info.loc2));
966  } else if(key == "event_data") {
967  return variant(std::make_shared<config_callable>(event_info.data));
968  } else if(key == "unit") {
969  if(auto u1 = event_info.loc1.get_unit()) {
970  return variant(std::make_shared<unit_callable>(*u1));
971  }
972  } else if(key == "second_unit") {
973  if(auto u2 = event_info.loc2.get_unit()) {
974  return variant(std::make_shared<unit_callable>(*u2));
975  }
976  } else if(key == "weapon") {
977  if(event_info.data.has_child("first")) {
978  first_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("first"));
979  return variant(std::make_shared<attack_type_callable>(*first_weapon));
980  }
981  } else if(key == "second_weapon") {
982  if(event_info.data.has_child("second")) {
983  second_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("second"));
984  return variant(std::make_shared<attack_type_callable>(*second_weapon));
985  }
986  }
987 
988  return variant();
989 }
990 
991 } // namespace wfl
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition: config.cpp:367
const_attr_itors attribute_range() const
Definition: config.cpp:763
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:317
bool has_attribute(config_key_type key) const
Definition: config.cpp:155
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:887
child_itors child_range(config_key_type key)
Definition: config.cpp:273
std::string hash() const
Definition: config.cpp:1287
Abstract class for exposing game data that doesn't depend on the GUI, however which for historical re...
virtual const gamemap & map() const =0
int w() const
Effective map width.
Definition: map.hpp:50
int h() const
Effective map height.
Definition: map.hpp:53
Encapsulates the map of the game.
Definition: map.hpp:172
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:74
bool uses_shroud() const
Definition: team.hpp:303
const std::string & color() const
Definition: team.hpp:242
config & variables()
Definition: team.hpp:348
int side() const
Definition: team.hpp:174
const std::string & faction() const
Definition: team.hpp:296
int village_support() const
Definition: team.hpp:185
int recall_cost() const
Definition: team.hpp:179
const std::string & team_name() const
Definition: team.hpp:282
bool is_local_human() const
Definition: team.hpp:253
int village_gold() const
Definition: team.hpp:178
team_shared_vision::type share_vision() const
Definition: team.hpp:377
int gold() const
Definition: team.hpp:175
const t_string & faction_name() const
Definition: team.hpp:297
bool carryover_add() const
Definition: team.hpp:343
int carryover_percentage() const
Definition: team.hpp:341
bool is_network() const
Definition: team.hpp:248
int total_income() const
Definition: team.hpp:182
const std::string & save_id() const
Definition: team.hpp:217
bool is_local_ai() const
Definition: team.hpp:254
double carryover_bonus() const
Definition: team.hpp:345
int start_gold() const
Definition: team.hpp:176
const std::string & flag_icon() const
Definition: team.hpp:287
int base_income() const
Definition: team.hpp:177
bool uses_fog() const
Definition: team.hpp:304
const std::string & flag() const
Definition: team.hpp:286
bool hidden() const
Definition: team.hpp:333
recall_list_manager & recall_list()
Definition: team.hpp:201
const std::set< std::string > & recruits() const
Definition: team.hpp:209
const std::string & icon_image() const
Definition: terrain.hpp:44
const t_string & name() const
Definition: terrain.hpp:48
bool is_keep() const
Definition: terrain.hpp:143
bool is_castle() const
Definition: terrain.hpp:142
const std::string & id() const
Definition: terrain.hpp:52
const t_string & description() const
Definition: terrain.hpp:50
bool is_village() const
Definition: terrain.hpp:141
int light_bonus(int base) const
Returns the light (lawful) bonus for this terrain when the time of day gives a base bonus.
Definition: terrain.hpp:132
const t_string & editor_name() const
Definition: terrain.hpp:49
int gives_healing() const
Definition: terrain.hpp:140
const wfl::map_formula_callable_ptr & formula_vars() const
const std::string & id() const
Definition: race.hpp:35
std::string race_id() const
Returns the ID of this type's race without the need to build the type.
Definition: types.hpp:271
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:141
int hitpoints() const
Definition: types.hpp:161
const_attack_itors attacks() const
Definition: types.cpp:542
const std::string & usage() const
Definition: types.hpp:175
int movement() const
Definition: types.hpp:166
int cost() const
Definition: types.hpp:172
int experience_needed(bool with_acceleration=true) const
Definition: types.cpp:576
bool musthave_status(const std::string &status) const
Definition: types.cpp:671
std::vector< std::string > get_ability_list() const
Definition: types.cpp:603
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:138
config::const_child_itors possible_traits() const
Definition: types.hpp:230
int level() const
Definition: types.hpp:164
unit_alignments::type alignment() const
Definition: types.hpp:192
int recall_cost() const
Definition: types.hpp:165
This class represents a single unit of a specific type.
Definition: unit.hpp:133
Represents version numbers.
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
attack_type_callable(const attack_type &attack)
void get_inputs(formula_input_vector &inputs) const override
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
int do_compare(const formula_callable *callable) const override
const config & get_config() const
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
std::shared_ptr< attack_type > second_weapon
const game_events::queued_event & event_info
std::shared_ptr< attack_type > first_weapon
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
formula_input_vector inputs() const
Definition: callable.hpp:63
static void add_input(formula_input_vector &inputs, const std::string &key, formula_access access_type=formula_access::read_only)
Definition: callable.hpp:136
virtual int do_compare(const formula_callable *callable) const
Definition: callable.hpp:146
static variant convert_vector(const std::vector< T > &input_vector)
Definition: callable.hpp:126
static variant convert_set(const std::set< T > &input_set)
Definition: callable.hpp:115
static const char *const id_chars
Definition: formula.hpp:75
const display_context & board_
const gamemap & get_gamemap() const
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
variant get_value(const std::string &key) const override
void get_inputs(formula_input_vector &inputs) const override
const map_location & loc() const
void serialize_to_string(std::string &str) const override
void get_inputs(formula_input_vector &inputs) const override
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
const expression_ptr & get_backup() const
variant execute_self(variant ctxt) override
variant get_value(const std::string &key) const override
void get_inputs(formula_input_vector &inputs) const override
const map_location current_unit_location_
void get_inputs(formula_input_vector &inputs) const override
const_formula_callable_ptr failed_callable_
variant get_value(const std::string &key) const override
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
const std::string & key() const
variant execute_self(variant ctxt) override
void get_inputs(formula_input_vector &inputs) const override
variant get_value(const std::string &key) const override
variant get_value(const std::string &key) const override
const terrain_type & t_
terrain_callable(const display_context &m, const map_location &loc)
void get_inputs(formula_input_vector &inputs) const override
const map_location loc_
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
const map_location & loc_
void get_inputs(formula_input_vector &inputs) const override
unit_callable(const map_location &loc, const unit &u)
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
int do_compare(const formula_callable *callable) const override
void get_inputs(formula_input_vector &inputs) const override
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:653
std::shared_ptr< T > try_convert() const
Definition: variant.hpp:90
const_formula_callable_ptr as_callable() const
Definition: variant.hpp:83
@ DECIMAL_VARIANT
Definition: variant.hpp:31
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:643
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:29
#define LOG_SF
static lg::log_domain log_scripting_formula("scripting/formula")
#define ERR_SF
std::size_t i
Definition: function.cpp:968
map_location loc_
int w
Interfaces for manipulating version numbers of engine, add-ons, etc.
std::vector< std::string > get_ability_list() const
Get a list of all abilities by ID.
Definition: abilities.cpp:267
unit_formula_manager & formula_manager() const
Get the unit formula manager.
Definition: unit.hpp:1840
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:505
unit_alignments::type alignment() const
The alignment of this unit.
Definition: unit.hpp:475
bool incapacitated() const
Check if the unit has been petrified.
Definition: unit.hpp:905
int level() const
The current level of this unit.
Definition: unit.hpp:559
std::string usage() const
Gets this unit's usage.
Definition: unit.hpp:686
const std::string & get_role() const
Gets this unit's role.
Definition: unit.hpp:669
const std::vector< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
Definition: unit.hpp:624
const std::string & variation() const
The ID of the variation of this unit's type.
Definition: unit.hpp:572
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:499
int cost() const
How much gold is required to recruit this unit.
Definition: unit.hpp:633
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1331
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1949
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition: unit.hpp:720
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
Definition: unit.cpp:1314
const unit_race * race() const
Gets this unit's race.
Definition: unit.hpp:493
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:523
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:612
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:380
int side() const
The side this unit belongs to.
Definition: unit.hpp:343
config & variables()
Gets any user-defined variables this unit 'owns'.
Definition: unit.hpp:703
std::size_t underlying_id() const
This unit's unique internal ID.
Definition: unit.hpp:392
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:529
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:465
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:403
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
Definition: unit.hpp:244
attack_itors attacks()
Gets an iterator over this unit's attacks.
Definition: unit.hpp:927
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
Definition: unit.hpp:978
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition: unit.hpp:994
bool get_emit_zoc() const
Gets the raw zone-of-control flag, disregarding incapacitated.
Definition: unit.hpp:1344
const movetype & movement_type() const
Get the unit's movement type.
Definition: unit.hpp:1430
map_location::DIRECTION facing() const
The current direction this unit is facing within its hex.
Definition: unit.hpp:1373
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1282
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1266
bool resting() const
Checks whether this unit is 'resting'.
Definition: unit.hpp:1326
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1466
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
Definition: unit.cpp:1734
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has.
Definition: unit.cpp:889
Standard logging facilities (interface).
std::unique_ptr< window > build(const builder_window::window_resolution &definition)
Builds a window.
::tod_manager * tod_manager
Definition: resources.cpp:29
game_board * gameboard
Definition: resources.cpp:20
play_controller * controller
Definition: resources.cpp:21
Definition: contexts.hpp:43
std::vector< formula_input > formula_input_vector
static std::string get_location(const std::string &loc)
Define the game's event mechanism.
const std::string & gender_string(unit_race::GENDER gender)
Definition: race.cpp:140
unit_const_ptr get_unit() const
entity_location loc1
Definition: pump.hpp:65
entity_location loc2
Definition: pump.hpp:66
std::string name
Definition: pump.hpp:63
Encapsulates the map of the game.
Definition: location.hpp:38
int wml_y() const
Definition: location.hpp:154
static const map_location & null_location()
Definition: location.hpp:81
int wml_x() const
Definition: location.hpp:153
int do_compare(const map_location &a) const
three-way comparator
Definition: location.hpp:105
static std::string write_direction(DIRECTION dir)
Definition: location.cpp:140
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
variant operator()(utils::monostate) const
variant operator()(bool b) const
variant operator()(const std::string &s) const
variant operator()(int i) const
variant operator()(unsigned long long i) const
variant operator()(const t_string &s) const
variant operator()(double i) const
mock_party p
static map_location::DIRECTION s
#define h
#define b