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 
195  if(key == "x") {
197  return variant();
198  }
199 
200  return variant(loc_.wml_x());
201  } else if(key == "y") {
203  return variant();
204  }
205 
206  return variant(loc_.wml_y());
207  } else if(key == "loc") {
209  return variant();
210  }
211 
212  return variant(std::make_shared<location_callable>(loc_));
213  } else if(key == "terrain") {
215  return variant();
216  }
217  return variant(std::make_shared<terrain_callable>(*resources::gameboard, loc_));
218  } else if(key == "id") {
219  return variant(u_.id());
220  } else if(key == "type") {
221  return variant(u_.type_id());
222  } else if(key == "name") {
223  return variant(u_.name());
224  } else if(key == "usage") {
225  return variant(u_.usage());
226  } else if(key == "leader" || key == "canrecruit") {
227  return variant(u_.can_recruit());
228  } else if(key == "undead") {
229  return variant(u_.get_state("not_living") ? 1 : 0);
230  } else if(key == "attacks") {
231  std::vector<variant> res;
232  for(const attack_type& att : u_.attacks()) {
233  res.emplace_back(std::make_shared<attack_type_callable>(att));
234  }
235 
236  return variant(res);
237  } else if(key == "abilities") {
239  } else if(key == "hitpoints") {
240  return variant(u_.hitpoints());
241  } else if(key == "max_hitpoints") {
242  return variant(u_.max_hitpoints());
243  } else if(key == "experience") {
244  return variant(u_.experience());
245  } else if(key == "max_experience") {
246  return variant(u_.max_experience());
247  } else if(key == "level" || key == "full") {
248  // This allows writing "upkeep == full"
249  return variant(u_.level());
250  } else if(key == "total_movement" || key == "max_moves") {
251  return variant(u_.total_movement());
252  } else if(key == "movement_left" || key == "moves") {
253  return variant(u_.movement_left());
254  } else if(key == "attacks_left") {
255  return variant(u_.attacks_left());
256  } else if(key == "max_attacks") {
257  return variant(u_.max_attacks());
258  } else if(key == "traits") {
260  } else if(key == "advancements_taken") {
262  } else if(key == "objects") {
264  } else if(key == "traits_count") {
265  return variant(u_.traits_count());
266  } else if(key == "advancements_taken_count") {
267  return variant(u_.advancements_count());
268  } else if(key == "objects_count") {
269  return variant(u_.objects_count());
270  } else if(key == "extra_recruit") {
272  } else if(key == "advances_to") {
274  } else if(key == "states" || key == "status") {
276  } else if(key == "side") {
277  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.");
278  return variant(u_.side()-1);
279  } else if(key == "side_number") {
280  return variant(u_.side());
281  } else if(key == "cost") {
282  return variant(u_.cost());
283  } else if(key == "upkeep") {
284  return variant(u_.upkeep());
285  } else if(key == "loyal") {
286  // So we can write "upkeep == loyal"
287  return variant(0);
288  } else if(key == "hidden") {
289  return variant(u_.get_hidden());
290  } else if(key == "petrified") {
291  return variant(u_.incapacitated());
292  } else if(key == "resting") {
293  return variant(u_.resting());
294  } else if(key == "role") {
295  return variant(u_.get_role());
296  } else if(key == "race") {
297  return variant(u_.race()->id());
298  } else if(key == "gender") {
299  return variant(gender_string(u_.gender()));
300  } else if(key == "variation") {
301  return variant(u_.variation());
302  } else if(key == "zoc") {
303  return variant(u_.get_emit_zoc());
304  } else if(key == "alignment") {
306  } else if(key == "facing") {
308  } else if(key == "resistance" || key == "movement_cost" || key == "vision_cost" || key == "jamming_cost" || key == "defense") {
309  const auto& mt = u_.movement_type();
310  config cfg;
311  bool needs_flip = false;
312  if(key == "resistance") {
313  mt.get_resistances().write(cfg);
314  needs_flip = true;
315  } else if(key == "movement_cost") {
316  mt.get_movement().write(cfg);
317  } else if(key == "vision_cost") {
318  mt.get_vision().write(cfg);
319  } else if(key == "jamming_cost") {
320  mt.get_jamming().write(cfg);
321  } else if(key == "defense") {
322  mt.get_defense().write(cfg);
323  needs_flip = true;
324  }
325  std::map<variant, variant> res;
326  for(const auto& p : cfg.attribute_range()) {
327  int val = p.second;
328  if(needs_flip) {
329  val = 100 - val;
330  }
331  res.emplace(variant(p.first), variant(val));
332  }
333 
334  return variant(res);
335  } else if(key == "flying") {
336  return variant(u_.is_flying());
337  } else if(key == "vars") {
340  }
341 
342  return variant();
343  } else if(key == "wml_vars") {
344  return variant(std::make_shared<config_callable>(u_.variables()));
345  } else if(key == "n" || key == "s" || key == "ne" || key == "se" || key == "nw" || key == "sw" ||
346  key == "lawful" || key == "neutral" || key == "chaotic" || key == "liminal" ||
347  key == "male" || key == "female")
348  {
349  return variant(key);
350  }
351 
352  return variant();
353 }
354 
356 {
357  add_input(inputs, "x");
358  add_input(inputs, "y");
359  add_input(inputs, "loc");
360  add_input(inputs, "terrain");
361  add_input(inputs, "id");
362  add_input(inputs, "type");
363  add_input(inputs, "name");
364  add_input(inputs, "canrecruit");
365  add_input(inputs, "undead");
366  add_input(inputs, "traits");
367  add_input(inputs, "advancements_taken");
368  add_input(inputs, "objects");
369  add_input(inputs, "traits_count");
370  add_input(inputs, "advancements_taken_count");
371  add_input(inputs, "objects_count");
372  add_input(inputs, "attacks");
373  add_input(inputs, "abilities");
374  add_input(inputs, "hitpoints");
375  add_input(inputs, "max_hitpoints");
376  add_input(inputs, "experience");
377  add_input(inputs, "max_experience");
378  add_input(inputs, "level");
379  add_input(inputs, "moves");
380  add_input(inputs, "max_moves");
381  add_input(inputs, "attacks_left");
382  add_input(inputs, "max_attacks");
383  add_input(inputs, "side_number");
384  add_input(inputs, "extra_recruit");
385  add_input(inputs, "advances_to");
386  add_input(inputs, "status");
387  add_input(inputs, "cost");
388  add_input(inputs, "usage");
389  add_input(inputs, "upkeep");
390  add_input(inputs, "hidden");
391  add_input(inputs, "petrified");
392  add_input(inputs, "resting");
393  add_input(inputs, "role");
394  add_input(inputs, "race");
395  add_input(inputs, "gender");
396  add_input(inputs, "variation");
397  add_input(inputs, "zoc");
398  add_input(inputs, "alignment");
399  add_input(inputs, "facing");
400  add_input(inputs, "resistance");
401  add_input(inputs, "movement_cost");
402  add_input(inputs, "vision_cost");
403  add_input(inputs, "jamming_cost");
404  add_input(inputs, "defense");
405  add_input(inputs, "flying");
406  add_input(inputs, "vars");
407  add_input(inputs, "wml_vars");
408 }
409 
410 int unit_callable::do_compare(const formula_callable* callable) const
411 {
412  const unit_callable* u_callable = dynamic_cast<const unit_callable*>(callable);
413  if(u_callable == nullptr) {
414  return formula_callable::do_compare(callable);
415  }
416 
417  return u_.underlying_id() - u_callable->u_.underlying_id();
418 }
419 
420 variant unit_type_callable::get_value(const std::string& key) const
421 {
422  if(key == "id") {
423  return variant(u_.id());
424  } else if(key == "type") {
425  return variant(u_.type_name());
426  } else if(key == "alignment") {
428  } else if(key == "race") {
429  return variant(u_.race_id());
430  } else if(key == "abilities") {
432  } else if(key == "traits") {
433  std::vector<variant> res;
434  for(const auto& config : u_.possible_traits()) {
435  res.emplace_back(config["id"].str());
436  }
437 
438  return variant(res);
439  } else if(key == "attacks") {
440  std::vector<variant> res;
441  for(const attack_type& att : u_.attacks()) {
442  res.emplace_back(std::make_shared<attack_type_callable>(att));
443  }
444 
445  return variant(res);
446  } else if(key == "hitpoints" || key == "max_hitpoints") {
447  return variant(u_.hitpoints());
448  } else if(key == "experience" || key == "max_experience") {
449  return variant(u_.experience_needed(true));
450  } else if(key == "level") {
451  return variant(u_.level());
452  } else if(key == "total_movement" || key == "max_moves" || key == "moves") {
453  return variant(u_.movement());
454  } else if(key == "undead") {
455  return variant(u_.musthave_status("unpoisonable") && u_.musthave_status("undrainable") && u_.musthave_status("unplagueable"));
456  } else if(key == "unpoisonable") {
457  return variant(u_.musthave_status("unpoisonable"));
458  } else if(key == "unslowable") {
459  return variant(u_.musthave_status("unslowable"));
460  } else if(key == "unpetrifiable") {
461  return variant(u_.musthave_status("unpetrifiable"));
462  } else if(key == "undrainable") {
463  return variant(u_.musthave_status("undrainable"));
464  } else if(key == "unplagueable") {
465  return variant(u_.musthave_status("unplagueable"));
466  } else if(key == "cost") {
467  return variant(u_.cost());
468  } else if(key == "recall_cost") {
469  return variant(u_.recall_cost());
470  } else if(key == "usage") {
471  return variant(u_.usage());
472  }
473 
474  return variant();
475 }
476 
478 {
479  add_input(inputs, "id");
480  add_input(inputs, "type");
481  add_input(inputs, "race");
482  add_input(inputs, "alignment");
483  add_input(inputs, "abilities");
484  add_input(inputs, "traits");
485  add_input(inputs, "attacks");
486  add_input(inputs, "hitpoints");
487  add_input(inputs, "experience");
488  add_input(inputs, "level");
489  add_input(inputs, "total_movement");
490  add_input(inputs, "undead");
491  add_input(inputs, "cost");
492  add_input(inputs, "recall_cost");
493  add_input(inputs, "usage");
494 }
495 
497 {
498  const unit_type_callable* u_callable = dynamic_cast<const unit_type_callable*>(callable);
499  if(u_callable == nullptr) {
500  return formula_callable::do_compare(callable);
501  }
502 
503  return u_.id().compare(u_callable->u_.id());
504 }
505 
507 #ifdef USING_BOOST_VARIANT
508  : public boost::static_visitor<variant>
509 #endif
510 {
511  variant operator()(bool b) const { return variant(b ? 1 : 0); }
512  variant operator()(int i) const { return variant(i); }
513  variant operator()(unsigned long long i) const { return variant(i); }
514  variant operator()(double i) const { return variant(i * 1000, variant::DECIMAL_VARIANT); }
515  // TODO: Should comma-separated lists of stuff be returned as a list?
516  // The challenge is to distinguish them from ordinary strings that happen to contain a comma
517  // (or should we assume that such strings will be translatable?).
518  variant operator()(const std::string& s) const { return variant(s); }
519  variant operator()(const t_string& s) const { return variant(s.str()); }
520  variant operator()(utils::monostate) const { return variant(); }
521 };
522 
523 variant config_callable::get_value(const std::string& key) const
524 {
525  if(cfg_.has_attribute(key)) {
526  return cfg_[key].apply_visitor(fai_variant_visitor());
527  } else if(cfg_.has_child(key)) {
528  std::vector<variant> result;
529  for(const auto& child : cfg_.child_range(key)) {
530  result.emplace_back(std::make_shared<config_callable>(child));
531  }
532 
533  return variant(result);
534  } else if(key == "__all_children") {
535  std::vector<variant> result;
536  for(const auto child : cfg_.all_children_range()) {
537  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
538  const variant kv(std::make_shared<key_value_pair>(variant(child.key), cfg_child));
539  result.push_back(kv);
540  }
541 
542  return variant(result);
543  } else if(key == "__children") {
544  std::map<std::string, std::vector<variant>> build;
545  for(const auto child : cfg_.all_children_range()) {
546  const variant cfg_child(std::make_shared<config_callable>(child.cfg));
547  build[child.key].push_back(cfg_child);
548  }
549 
550  std::map<variant,variant> result;
551  for(auto& p : build) {
552  result[variant(p.first)] = variant(p.second);
553  }
554 
555  return variant(result);
556  } else if(key == "__attributes") {
557  std::map<variant,variant> result;
558  for(const auto& val : cfg_.attribute_range()) {
559  result[variant(val.first)] = val.second.apply_visitor(fai_variant_visitor());
560  }
561 
562  return variant(result);
563  }
564 
565  return variant();
566 }
567 
569 {
570  add_input(inputs, "__all_children");
571  add_input(inputs, "__children");
572  add_input(inputs, "__attributes");
573 
574  for(const auto& val : cfg_.attribute_range()) {
575  if(val.first.find_first_not_of(formula::id_chars) != std::string::npos) {
576  add_input(inputs, val.first);
577  }
578  }
579 }
580 
582 {
583  const config_callable* cfg_callable = dynamic_cast<const config_callable*>(callable);
584  if(cfg_callable == nullptr) {
585  return formula_callable::do_compare(callable);
586  }
587 
588  if(cfg_ == cfg_callable->get_config()) {
589  return 0;
590  }
591 
592  return cfg_.hash().compare(cfg_callable->get_config().hash());
593 }
594 
595 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))
596 {
597  type_ = TERRAIN_C;
598 }
599 
600 variant terrain_callable::get_value(const std::string& key) const
601 {
602  if(key == "x") {
603  return variant(loc_.wml_x());
604  } else if(key == "y") {
605  return variant(loc_.wml_y());
606  } else if(key == "loc") {
607  return variant(std::make_shared<location_callable>(loc_));
608  } else if(key == "id") {
609  return variant(std::string(t_.id()));
610  } else if(key == "name") {
611  return variant(t_.name());
612  } else if(key == "editor_name") {
613  return variant(t_.editor_name());
614  } else if(key == "description") {
615  return variant(t_.description());
616  } else if(key == "icon") {
617  return variant(t_.icon_image());
618  } else if(key == "light") {
619  return variant(t_.light_bonus(0));
620  } else if(key == "village") {
621  return variant(t_.is_village());
622  } else if(key == "castle") {
623  return variant(t_.is_castle());
624  } else if(key == "keep") {
625  return variant(t_.is_keep());
626  } else if(key == "healing") {
627  return variant(t_.gives_healing());
628  } else if(key == "owner") {
629  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.");
630  return variant(owner_ - 1);
631  } else if(key == "owner_side") {
632  return variant(owner_);
633  }
634 
635  return variant();
636 }
637 
639 {
640  add_input(inputs, "x");
641  add_input(inputs, "y");
642  add_input(inputs, "loc");
643  add_input(inputs, "id");
644  add_input(inputs, "name");
645  add_input(inputs, "editor_name");
646  add_input(inputs, "description");
647  add_input(inputs, "icon");
648  add_input(inputs, "light");
649  add_input(inputs, "village");
650  add_input(inputs, "castle");
651  add_input(inputs, "keep");
652  add_input(inputs, "healing");
653  add_input(inputs, "owner_side");
654 }
655 
657 {
658  const terrain_callable* terr_callable = dynamic_cast<const terrain_callable*>(callable);
659  if(terr_callable == nullptr) {
660  return formula_callable::do_compare(callable);
661  }
662 
663  const map_location& other_loc = terr_callable->loc_;
664  return loc_.do_compare(other_loc);
665 }
666 
668  return board_.map();
669 }
670 
672 {
673  add_input(inputs, "w");
674  add_input(inputs, "h");
675 }
676 
677 variant gamemap_callable::get_value(const std::string& key) const
678 {
679  if(key == "terrain") {
680  int w = get_gamemap().w();
681  int h = get_gamemap().h();
682 
683  std::vector<variant> vars;
684  for(int i = 0; i < w; i++) {
685  for(int j = 0; j < h; j++) {
686  const map_location loc(i, j);
687  vars.emplace_back(std::make_shared<terrain_callable>(board_, loc));
688  }
689  }
690 
691  return variant(vars);
692  } else if(key == "gamemap") {
693  int w = get_gamemap().w();
694  int h = get_gamemap().h();
695 
696  std::map<variant, variant> vars;
697  for(int i = 0; i < w; i++) {
698  for(int j = 0; j < h; j++) {
699  const map_location loc(i, j);
700  vars.emplace(std::make_shared<location_callable>(loc), std::make_shared<terrain_callable>(board_, loc));
701  }
702  }
703 
704  return variant(vars);
705  } else if(key == "w") {
706  return variant(get_gamemap().w());
707  } else if(key == "h") {
708  return variant(get_gamemap().h());
709  } else {
710  return variant();
711  }
712 }
713 
715 {
716  add_input(inputs, "side_number");
717  add_input(inputs, "id");
718  add_input(inputs, "gold");
719  add_input(inputs, "start_gold");
720  add_input(inputs, "base_income");
721  add_input(inputs, "total_income");
722  add_input(inputs, "village_gold");
723  add_input(inputs, "village_support");
724  add_input(inputs, "recall_cost");
725  add_input(inputs, "is_human");
726  add_input(inputs, "is_ai");
727  add_input(inputs, "is_network");
728  add_input(inputs, "fog");
729  add_input(inputs, "shroud");
730  add_input(inputs, "hidden");
731  add_input(inputs, "flag");
732  add_input(inputs, "flag_icon");
733  add_input(inputs, "team_name");
734  add_input(inputs, "faction");
735  add_input(inputs, "faction_name");
736  add_input(inputs, "color");
737  add_input(inputs, "share_vision");
738  add_input(inputs, "carryover_bonus");
739  add_input(inputs, "carryover_percentage");
740  add_input(inputs, "carryover_add");
741  add_input(inputs, "recruit");
742  add_input(inputs, "wml_vars");
743 }
744 
745 variant team_callable::get_value(const std::string& key) const
746 {
747  if(key == "side") {
748  deprecated_message("team.side", DEP_LEVEL::INDEFINITE, version_info("1.17"), "Use side_number instead.");
749  return variant(team_.side());
750  } else if(key == "side_number") {
751  return variant(team_.side());
752  } else if(key == "id") {
753  return variant(team_.save_id());
754  } else if(key == "save_id") {
755  return variant(team_.save_id());
756  } else if(key == "gold") {
757  return variant(team_.gold());
758  } else if(key == "start_gold") {
759  return variant(team_.start_gold());
760  } else if(key == "base_income") {
761  return variant(team_.base_income());
762  } else if(key == "total_income") {
763  return variant(team_.total_income());
764  } else if(key == "village_gold") {
765  return variant(team_.village_gold());
766  } else if(key == "village_support") {
767  return variant(team_.village_support());
768  } else if(key == "recall_cost") {
769  return variant(team_.recall_cost());
770  } else if(key == "is_human") {
771  return variant(team_.is_local_human());
772  } else if(key == "is_ai") {
773  return variant(team_.is_local_ai());
774  } else if(key == "is_network") {
775  return variant(team_.is_network());
776  } else if(key == "fog") {
777  return variant(team_.uses_fog());
778  } else if(key == "shroud") {
779  return variant(team_.uses_shroud());
780  } else if(key == "hidden") {
781  return variant(team_.hidden());
782  } else if(key == "flag") {
783  return variant(team_.flag());
784  } else if(key == "flag_icon") {
785  return variant(team_.flag_icon());
786  } else if(key == "team_name") {
787  return variant(team_.team_name());
788  } else if(key == "faction") {
789  return variant(team_.faction());
790  } else if(key == "faction_name") {
791  return variant(team_.faction_name());
792  } else if(key == "color") {
793  return variant(team_.color());
794  } else if(key == "share_vision") {
796  } else if(key == "carryover_bonus") {
798  } else if(key == "carryover_percentage") {
800  } else if(key == "carryover_add") {
801  return variant(team_.carryover_add());
802  } else if(key == "recruit") {
803  std::vector<variant> result;
804  for(const auto& recruit : team_.recruits()) {
805  result.emplace_back(recruit);
806  }
807  return variant(result);
808  } else if(key == "recall") {
809  std::vector<variant> result;
810  for(const auto& u : team_.recall_list()) {
811  result.push_back(std::make_shared<unit_callable>(*u));
812  }
813  return variant(result);
814  } else if(key == "wml_vars") {
815  return variant(std::make_shared<config_callable>(team_.variables()));
816  }
817 
818  return variant();
819 }
820 
821 variant set_var_callable::get_value(const std::string& key) const
822 {
823  if(key == "key") {
824  return variant(key_);
825  } else if(key == "value") {
826  return value_;
827  }
828 
829  return variant();
830 }
831 
833 {
834  add_input(inputs, "key");
835  add_input(inputs, "value");
836 }
837 
839 {
840  //if(infinite_loop_guardian_.set_var_check()) {
841  if(auto obj = ctxt.try_convert<formula_callable>()) {
842  LOG_SF << "Setting variable: " << key_ << " -> " << value_.to_debug_string();
843  obj->mutate_value(key_, value_);
844  return variant(true);
845  }
846  //}
847  //too many calls in a row - possible infinite loop
848  ERR_SF << "ERROR #" << 5001 << " while executing 'set_var' formula function";
849 
850  return variant(std::make_shared<safe_call_result>(fake_ptr(), 5001));
851 }
852 
853 variant safe_call_callable::get_value(const std::string& key) const
854 {
855  if(key == "main") {
856  return variant(main_);
857  } else if(key == "backup") {
858  return variant(backup_);
859  }
860 
861  return variant();
862 }
863 
865 {
866  add_input(inputs, "main");
867  add_input(inputs, "backup");
868 }
869 
871 {
872  variant res;
873  if(auto action = main_.try_convert<action_callable>()) {
874  res = action->execute_self(ctxt);
875  }
876 
877  if(res.try_convert<safe_call_result>()) {
878  /* If we have safe_call formula and either an error occurred, or the current action
879  * was not recognized, then evaluate backup formula from safe_call and execute it
880  * during the next loop
881  */
882 
883  map_formula_callable callable(ctxt.as_callable());
884  callable.add("error", res);
885 
886  /* Store the result in safe_call_callable in case we would like to display it to the user,
887  * for example if this formula was executed from the commandline.
888  */
889  backup_ = get_backup()->evaluate(callable);
890  ctxt.execute_variant(backup_);
891  }
892  return variant(true);
893 }
894 
895 variant safe_call_result::get_value(const std::string& key) const
896 {
897  if(key == "status") {
898  return variant(status_);
899  } else if(key == "object") {
900  if(failed_callable_) {
901  return variant(failed_callable_);
902  }
903 
904  return variant();
905  } else if(key == "current_loc" && current_unit_location_ != map_location()) {
906  return variant(std::make_shared<location_callable>(current_unit_location_));
907  }
908 
909  return variant();
910 }
911 
913 {
914  add_input(inputs, "status");
915  add_input(inputs, "object");
916 
918  add_input(inputs, "current_loc");
919  }
920 }
921 
923 {
924  add_input(inputs, "turn_number");
925  add_input(inputs, "time_of_day");
926  add_input(inputs, "side_number");
927  add_input(inputs, "sides");
928  add_input(inputs, "units");
929  add_input(inputs, "map");
930 }
931 
932 variant gamestate_callable::get_value(const std::string &key) const
933 {
934  if(key == "turn_number") {
935  return variant(resources::tod_manager->turn());
936  } else if(key == "time_of_day") {
937  return variant(resources::tod_manager->get_time_of_day().id);
938  } else if(key == "side_number") {
939  return variant(resources::controller->current_side());
940  } else if(key == "sides") {
941  std::vector<variant> vars;
942  for(const auto& team : resources::gameboard->teams()) {
943  vars.emplace_back(std::make_shared<team_callable>(team));
944  }
945  return variant(vars);
946  } else if(key == "units") {
947  std::vector<variant> vars;
948  for(const auto& unit : resources::gameboard->units()) {
949  vars.emplace_back(std::make_shared<unit_callable>(unit));
950  }
951  return variant(vars);
952  } else if(key == "map") {
953  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
954  }
955 
956  return variant();
957 }
958 
960 {
961  add_input(inputs, "event");
962  add_input(inputs, "event_id");
963  add_input(inputs, "event_data");
964  add_input(inputs, "loc");
965  add_input(inputs, "unit");
966  add_input(inputs, "weapon");
967  add_input(inputs, "second_loc");
968  add_input(inputs, "second_unit");
969  add_input(inputs, "second_weapon");
970 }
971 
972 variant event_callable::get_value(const std::string &key) const
973 {
974  if(key == "event") {
975  return variant(event_info.name);
976  } else if(key == "event_id") {
977  return variant(event_info.id);
978  } else if(key == "loc") {
979  return variant(std::make_shared<location_callable>(event_info.loc1));
980  } else if(key == "second_loc") {
981  return variant(std::make_shared<location_callable>(event_info.loc2));
982  } else if(key == "event_data") {
983  return variant(std::make_shared<config_callable>(event_info.data));
984  } else if(key == "unit") {
985  if(auto u1 = event_info.loc1.get_unit()) {
986  return variant(std::make_shared<unit_callable>(*u1));
987  }
988  } else if(key == "second_unit") {
989  if(auto u2 = event_info.loc2.get_unit()) {
990  return variant(std::make_shared<unit_callable>(*u2));
991  }
992  } else if(key == "weapon") {
993  if(event_info.data.has_child("first")) {
994  first_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("first"));
995  return variant(std::make_shared<attack_type_callable>(*first_weapon));
996  }
997  } else if(key == "second_weapon") {
998  if(event_info.data.has_child("second")) {
999  second_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("second"));
1000  return variant(std::make_shared<attack_type_callable>(*second_weapon));
1001  }
1002  }
1003 
1004  return variant();
1005 }
1006 
1007 } // 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:272
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:141
int hitpoints() const
Definition: types.hpp:161
const_attack_itors attacks() const
Definition: types.cpp:543
const std::string & usage() const
Definition: types.hpp:175
int movement() const
Definition: types.hpp:166
int cost() const
Definition: types.hpp:172
int experience_needed(bool with_acceleration=true) const
Definition: types.cpp:577
bool musthave_status(const std::string &status) const
Definition: types.cpp:672
std::vector< std::string > get_ability_list() const
Definition: types.cpp:604
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:138
config::const_child_itors possible_traits() const
Definition: types.hpp:231
int level() const
Definition: types.hpp:164
unit_alignments::type alignment() const
Definition: types.hpp:193
int recall_cost() const
Definition: types.hpp:165
This class represents a single unit of a specific type.
Definition: unit.hpp:133
Represents version numbers.
int do_compare(const formula_callable *callable) const override
variant get_value(const std::string &key) const override
attack_type_callable(const attack_type &attack)
void get_inputs(formula_input_vector &inputs) const override
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:1902
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:1349
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1983
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:1332
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
std::size_t advancements_count() const
Definition: unit.hpp:1556
std::size_t traits_count() const
Definition: unit.hpp:1546
std::size_t objects_count() const
Definition: unit.hpp:1551
bool get_emit_zoc() const
Gets the raw zone-of-control flag, disregarding incapacitated.
Definition: unit.hpp:1383
const movetype & movement_type() const
Get the unit's movement type.
Definition: unit.hpp:1469
map_location::DIRECTION facing() const
The current direction this unit is facing within its hex.
Definition: unit.hpp:1412
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition: unit.hpp:1321
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1305
bool resting() const
Checks whether this unit is 'resting'.
Definition: unit.hpp:1365
bool is_flying() const
Check if the unit is a flying unit.
Definition: unit.hpp:1505
std::vector< std::string > get_advancements_list() const
Definition: unit.hpp:1139
std::vector< std::string > get_objects_list() const
Definition: unit.hpp:1134
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
Definition: unit.cpp:1752
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has, including hidden traits.
Definition: unit.hpp:1129
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