The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
callable_objects.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
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
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"
24#include "units/unit.hpp"
25#include "units/types.hpp"
26#include "log.hpp"
28#include "deprecation.hpp"
29#include "game_board.hpp"
30#include "game_version.hpp"
31#include "resources.hpp"
32#include "tod_manager.hpp"
33#include "play_controller.hpp"
34#include "game_events/pump.hpp"
35
36static lg::log_domain log_scripting_formula("scripting/formula");
37#define LOG_SF LOG_STREAM(info, log_scripting_formula)
38#define ERR_SF LOG_STREAM(err, log_scripting_formula)
39
40namespace wfl
41{
42
43variant location_callable::get_value(const std::string& key) const
44{
45 if(key == "x") {
46 return variant(loc_.wml_x());
47 } else if(key == "y") {
48 return variant(loc_.wml_y());
49 }
50
51 return variant();
52}
53
59
61{
62 const location_callable* loc_callable = dynamic_cast<const location_callable*>(callable);
63 if(loc_callable == nullptr) {
64 return formula_callable::do_compare(callable);
65 }
66
67 const map_location& other_loc = loc_callable->loc();
68 return loc_.do_compare(other_loc);
69}
70
72{
73 std::ostringstream ss;
74 ss << "loc(" << (loc_.wml_x()) << "," << (loc_.wml_y()) << ")";
75 return ss.str();
76}
77
78attack_type_callable::attack_type_callable(const attack_type& attack) : att_(attack.shared_from_this())
79{
81}
82
83variant attack_type_callable::get_value(const std::string& key) const
84{
85 if(key == "id" || key == "name") {
86 return variant(att_->id());
87 } else if(key == "description") {
88 return variant(att_->name());
89 } else if(key == "base_type") {
90 return variant(att_->type());
91 } else if(key == "type") {
92 return variant(att_->effective_damage_type().first);
93 } else if(key == "icon") {
94 return variant(att_->icon());
95 } else if(key == "range") {
96 return variant(att_->range());
97 } else if(key == "alignment") {
98 return variant(att_->alignment_str());
99 } else if(key == "damage") {
100 return variant(att_->damage());
101 } else if(key == "number_of_attacks" || key == "number" || key == "num_attacks" || key == "attacks") {
102 return variant(att_->num_attacks());
103 } else if(key == "attack_weight") {
104 return variant(att_->attack_weight(), variant::DECIMAL_VARIANT);
105 } else if(key == "defense_weight") {
106 return variant(att_->defense_weight(), variant::DECIMAL_VARIANT);
107 } else if(key == "accuracy") {
108 return variant(att_->accuracy());
109 } else if(key == "parry") {
110 return variant(att_->parry());
111 } else if(key == "movement_used") {
112 return variant(att_->movement_used());
113 } else if(key == "attacks_used") {
114 return variant(att_->attacks_used());
115 } else if(key == "min_range") {
116 return variant(att_->min_range());
117 } else if(key == "max_range") {
118 return variant(att_->max_range());
119 } else if(key == "specials" || key == "special") {
120 std::vector<variant> res;
121
122 for(const auto& p_ab : att_->specials()) {
123 if(!p_ab->id().empty()) {
124 res.emplace_back(p_ab->id());
125 }
126 }
127 return variant(std::move(res));
128 }
129
130 return variant();
131}
132
134{
135 add_input(inputs, "name");
136 add_input(inputs, "type");
137 add_input(inputs, "base_type");
138 add_input(inputs, "description");
139 add_input(inputs, "icon");
140 add_input(inputs, "range");
141 add_input(inputs, "alignment");
142 add_input(inputs, "damage");
143 add_input(inputs, "number");
144 add_input(inputs, "accuracy");
145 add_input(inputs, "parry");
146 add_input(inputs, "movement_used");
147 add_input(inputs, "attacks_used");
148 add_input(inputs, "attack_weight");
149 add_input(inputs, "defense_weight");
150 add_input(inputs, "min_range");
151 add_input(inputs, "max_range");
152 add_input(inputs, "specials");
153}
154
156{
157 const attack_type_callable* att_callable = dynamic_cast<const attack_type_callable*>(callable);
158 if(att_callable == nullptr) {
159 return formula_callable::do_compare(callable);
160 }
161
162 if(att_->damage() != att_callable->att_->damage()) {
163 return att_->damage() - att_callable->att_->damage();
164 }
165
166 if(att_->num_attacks() != att_callable->att_->num_attacks()) {
167 return att_->num_attacks() - att_callable->att_->num_attacks();
168 }
169
170 if(att_->id() != att_callable->att_->id()) {
171 return att_->id().compare(att_callable->att_->id());
172 }
173
174 if(att_->type() != att_callable->att_->type()) {
175 return att_->type().compare(att_callable->att_->type());
176 }
177
178 if(att_->range() != att_callable->att_->range()) {
179 return att_->range().compare(att_callable->att_->range());
180 }
181
182 if(att_->alignment_str() != att_callable->att_->alignment_str()) {
183 return att_->alignment_str().compare(att_callable->att_->alignment_str());
184 }
185
186 const auto& self_specials = att_->specials();
187 const auto& other_specials = att_callable->att_->specials();
188 if(self_specials.size() != other_specials.size()) {
189 return self_specials.size() < other_specials.size() ? -1 : 1;
190 }
191 for(std::size_t i = 0; i < self_specials.size(); ++i) {
192 const auto& s = self_specials[i]->id();
193 const auto& o = other_specials[i]->id();
194 if(s != o) {
195 return s.compare(o);
196 }
197 }
198
199 return 0;
200}
201
203{
204 type_ = UNIT_C;
205}
206
207variant unit_callable::get_value(const std::string& key) const
208{
209
210 if(key == "x") {
212 return variant();
213 }
214
215 return variant(loc_.wml_x());
216 } else if(key == "y") {
218 return variant();
219 }
220
221 return variant(loc_.wml_y());
222 } else if(key == "loc") {
224 return variant();
225 }
226
227 return make_callable<location_callable>(loc_);
228 } else if(key == "terrain") {
230 return variant();
231 }
232 return make_callable<terrain_callable>(*resources::gameboard, loc_);
233 } else if(key == "id") {
234 return variant(u_.id());
235 } else if(key == "type") {
236 return variant(u_.type_id());
237 } else if(key == "name") {
238 return variant(u_.name());
239 } else if(key == "usage") {
240 return variant(u_.usage());
241 } else if(key == "leader" || key == "canrecruit") {
242 return variant(u_.can_recruit());
243 } else if(key == "undead") {
244 return variant(u_.get_state("not_living") ? 1 : 0);
245 } else if(key == "attacks") {
246 std::vector<variant> res;
247 for(const attack_type& att : u_.attacks()) {
248 res.emplace_back(std::make_shared<attack_type_callable>(att));
249 }
250
251 return variant(std::move(res));
252 } else if(key == "abilities") {
253 deprecated_message("unit.abilities", DEP_LEVEL::FOR_REMOVAL, version_info("1.21"), "Use unit.ability_ids instead.");
255 } else if(key == "ability_ids") {
257 } else if(key == "hitpoints") {
258 return variant(u_.hitpoints());
259 } else if(key == "max_hitpoints") {
260 return variant(u_.max_hitpoints());
261 } else if(key == "experience") {
262 return variant(u_.experience());
263 } else if(key == "max_experience") {
264 return variant(u_.max_experience());
265 } else if(key == "level" || key == "full") {
266 // This allows writing "upkeep == full"
267 return variant(u_.level());
268 } else if(key == "total_movement" || key == "max_moves") {
269 return variant(u_.total_movement());
270 } else if(key == "movement_left" || key == "moves") {
271 return variant(u_.movement_left());
272 } else if(key == "attacks_left") {
273 return variant(u_.attacks_left());
274 } else if(key == "max_attacks") {
275 return variant(u_.max_attacks());
276 } else if(key == "traits") {
278 } else if(key == "advancements_taken") {
280 } else if(key == "objects") {
282 } else if(key == "traits_count") {
283 return variant(u_.traits_count());
284 } else if(key == "advancements_taken_count") {
285 return variant(u_.advancements_count());
286 } else if(key == "objects_count") {
287 return variant(u_.objects_count());
288 } else if(key == "extra_recruit") {
290 } else if(key == "advances_to") {
292 } else if(key == "states" || key == "status") {
294 } else if(key == "side_number") {
295 return variant(u_.side());
296 } else if(key == "cost") {
297 return variant(u_.cost());
298 } else if(key == "upkeep") {
299 return variant(u_.upkeep());
300 } else if(key == "loyal") {
301 // So we can write "upkeep == loyal"
302 return variant(0);
303 } else if(key == "hidden") {
304 return variant(u_.get_hidden());
305 } else if(key == "petrified") {
306 return variant(u_.incapacitated());
307 } else if(key == "resting") {
308 return variant(u_.resting());
309 } else if(key == "role") {
310 return variant(u_.get_role());
311 } else if(key == "race") {
312 return variant(u_.race()->id());
313 } else if(key == "gender") {
314 return variant(gender_string(u_.gender()));
315 } else if(key == "variation") {
316 return variant(u_.variation());
317 } else if(key == "zoc") {
318 return variant(u_.get_emit_zoc());
319 } else if(key == "alignment") {
321 } else if(key == "facing") {
323 } else if(key == "resistance" || key == "movement_cost" || key == "vision_cost" || key == "jamming_cost" || key == "defense") {
324 const auto& mt = u_.movement_type();
325 config cfg;
326 bool needs_flip = false;
327 if(key == "resistance") {
328 mt.get_resistances().write(cfg);
329 needs_flip = true;
330 } else if(key == "movement_cost") {
331 mt.get_movement().write(cfg);
332 } else if(key == "vision_cost") {
333 mt.get_vision().write(cfg);
334 } else if(key == "jamming_cost") {
335 mt.get_jamming().write(cfg);
336 } else if(key == "defense") {
337 mt.get_defense().write(cfg);
338 needs_flip = true;
339 }
340 std::map<variant, variant> res;
341 for(const auto& [key, value] : cfg.attribute_range()) {
342 int val = value.to_int();
343 if(needs_flip) {
344 val = 100 - val;
345 }
346 res.emplace(variant(key), variant(val));
347 }
348
349 return variant(std::move(res));
350 } else if(key == "flying") {
351 return variant(u_.is_flying());
352 } else if(key == "fearless") {
353 return variant(u_.is_fearless());
354 } else if(key == "healthy") {
355 return variant(u_.is_healthy());
356 } else if(key == "wml_vars") {
357 return make_callable<config_callable>(u_.variables());
358 } else if(key == "n" || key == "s" || key == "ne" || key == "se" || key == "nw" || key == "sw" ||
359 key == "lawful" || key == "neutral" || key == "chaotic" || key == "liminal" ||
360 key == "male" || key == "female")
361 {
362 return variant(key);
363 }
364
365 return variant();
366}
367
369{
370 add_input(inputs, "x");
371 add_input(inputs, "y");
372 add_input(inputs, "loc");
373 add_input(inputs, "terrain");
374 add_input(inputs, "id");
375 add_input(inputs, "type");
376 add_input(inputs, "name");
377 add_input(inputs, "canrecruit");
378 add_input(inputs, "undead");
379 add_input(inputs, "traits");
380 add_input(inputs, "advancements_taken");
381 add_input(inputs, "objects");
382 add_input(inputs, "traits_count");
383 add_input(inputs, "advancements_taken_count");
384 add_input(inputs, "objects_count");
385 add_input(inputs, "attacks");
386 add_input(inputs, "abilities");
387 add_input(inputs, "ability_ids");
388 add_input(inputs, "hitpoints");
389 add_input(inputs, "max_hitpoints");
390 add_input(inputs, "experience");
391 add_input(inputs, "max_experience");
392 add_input(inputs, "level");
393 add_input(inputs, "moves");
394 add_input(inputs, "max_moves");
395 add_input(inputs, "attacks_left");
396 add_input(inputs, "max_attacks");
397 add_input(inputs, "side_number");
398 add_input(inputs, "extra_recruit");
399 add_input(inputs, "advances_to");
400 add_input(inputs, "status");
401 add_input(inputs, "cost");
402 add_input(inputs, "usage");
403 add_input(inputs, "upkeep");
404 add_input(inputs, "hidden");
405 add_input(inputs, "petrified");
406 add_input(inputs, "resting");
407 add_input(inputs, "role");
408 add_input(inputs, "race");
409 add_input(inputs, "gender");
410 add_input(inputs, "variation");
411 add_input(inputs, "zoc");
412 add_input(inputs, "alignment");
413 add_input(inputs, "facing");
414 add_input(inputs, "resistance");
415 add_input(inputs, "movement_cost");
416 add_input(inputs, "vision_cost");
417 add_input(inputs, "jamming_cost");
418 add_input(inputs, "defense");
419 add_input(inputs, "flying");
420 add_input(inputs, "fearless");
421 add_input(inputs, "healthy");
422 add_input(inputs, "vars");
423 add_input(inputs, "wml_vars");
424}
425
427{
428 const unit_callable* u_callable = dynamic_cast<const unit_callable*>(callable);
429 if(u_callable == nullptr) {
430 return formula_callable::do_compare(callable);
431 }
432
433 return u_.underlying_id() - u_callable->u_.underlying_id();
434}
435
436variant unit_type_callable::get_value(const std::string& key) const
437{
438 if(key == "id") {
439 return variant(u_.id());
440 } else if(key == "type") {
441 return variant(u_.type_name());
442 } else if(key == "alignment") {
444 } else if(key == "race") {
445 return variant(u_.race_id());
446 } else if(key == "abilities") {
447 deprecated_message("unittype.abilities", DEP_LEVEL::FOR_REMOVAL, version_info("1.21"), "Use unittype.ability_ids instead.");
449 } else if(key == "ability_ids") {
451 } else if(key == "traits") {
452 std::vector<variant> res;
453 for(const auto& config : u_.possible_traits()) {
454 res.emplace_back(config["id"].str());
455 }
456
457 return variant(std::move(res));
458 } else if(key == "attacks") {
459 std::vector<variant> res;
460 for(const attack_type& att : u_.attacks()) {
461 res.emplace_back(std::make_shared<attack_type_callable>(att));
462 }
463
464 return variant(std::move(res));
465 } else if(key == "hitpoints" || key == "max_hitpoints") {
466 return variant(u_.hitpoints());
467 } else if(key == "experience" || key == "max_experience") {
468 return variant(u_.experience_needed(true));
469 } else if(key == "level") {
470 return variant(u_.level());
471 } else if(key == "total_movement" || key == "max_moves" || key == "moves") {
472 return variant(u_.movement());
473 } else if(key == "undead") {
474 return variant(u_.musthave_status("unpoisonable") && u_.musthave_status("undrainable") && u_.musthave_status("unplagueable"));
475 } else if(key == "unpoisonable") {
476 return variant(u_.musthave_status("unpoisonable"));
477 } else if(key == "unslowable") {
478 return variant(u_.musthave_status("unslowable"));
479 } else if(key == "unpetrifiable") {
480 return variant(u_.musthave_status("unpetrifiable"));
481 } else if(key == "undrainable") {
482 return variant(u_.musthave_status("undrainable"));
483 } else if(key == "unplagueable") {
484 return variant(u_.musthave_status("unplagueable"));
485 } else if(key == "cost") {
486 return variant(u_.cost());
487 } else if(key == "recall_cost") {
488 return variant(u_.recall_cost());
489 } else if(key == "usage") {
490 return variant(u_.usage());
491 }
492
493 return variant();
494}
495
497{
498 add_input(inputs, "id");
499 add_input(inputs, "type");
500 add_input(inputs, "race");
501 add_input(inputs, "alignment");
502 add_input(inputs, "abilities");
503 add_input(inputs, "ability_ids");
504 add_input(inputs, "traits");
505 add_input(inputs, "attacks");
506 add_input(inputs, "hitpoints");
507 add_input(inputs, "experience");
508 add_input(inputs, "level");
509 add_input(inputs, "total_movement");
510 add_input(inputs, "undead");
511 add_input(inputs, "cost");
512 add_input(inputs, "recall_cost");
513 add_input(inputs, "usage");
514}
515
517{
518 const unit_type_callable* u_callable = dynamic_cast<const unit_type_callable*>(callable);
519 if(u_callable == nullptr) {
520 return formula_callable::do_compare(callable);
521 }
522
523 return u_.id().compare(u_callable->u_.id());
524}
525
527#ifdef USING_BOOST_VARIANT
528 : public boost::static_visitor<variant>
529#endif
530{
531 variant operator()(bool b) const { return variant(b ? 1 : 0); }
532 variant operator()(int i) const { return variant(i); }
533 variant operator()(unsigned long long i) const { return variant(i); }
535 // TODO: Should comma-separated lists of stuff be returned as a list?
536 // The challenge is to distinguish them from ordinary strings that happen to contain a comma
537 // (or should we assume that such strings will be translatable?).
538 variant operator()(const std::string& s) const { return variant(s); }
539 variant operator()(const t_string& s) const { return variant(s.str()); }
540 variant operator()(utils::monostate) const { return variant(); }
541};
542
543variant config_callable::get_value(const std::string& key) const
544{
545 if(cfg_.has_attribute(key)) {
546 return cfg_[key].apply_visitor(wfl_variant_visitor{});
547 } else if(cfg_.has_child(key)) {
548 std::vector<variant> result;
549 for(const auto& child : cfg_.child_range(key)) {
550 result.emplace_back(std::make_shared<config_callable>(child));
551 }
552
553 return variant(std::move(result));
554 } else if(key == "__all_children") {
555 std::vector<variant> result;
556 for(const auto [child_key, child_cfg] : cfg_.all_children_view()) {
557 const variant cfg_child(std::make_shared<config_callable>(child_cfg));
558 const variant kv(std::make_shared<key_value_pair>(variant(child_key), cfg_child));
559 result.push_back(kv);
560 }
561
562 return variant(std::move(result));
563 } else if(key == "__children") {
564 std::map<std::string, std::vector<variant>> build;
565 for(const auto [child_key, child_cfg] : cfg_.all_children_view()) {
566 const variant cfg_child(std::make_shared<config_callable>(child_cfg));
567 build[child_key].push_back(cfg_child);
568 }
569
570 std::map<variant, variant> result;
571 for(auto& p : build) {
572 result[variant(p.first)] = variant(p.second);
573 }
574
575 return variant(std::move(result));
576 } else if(key == "__attributes") {
577 std::map<variant, variant> result;
578 for(const auto& [key, value] : cfg_.attribute_range()) {
579 result[variant(key)] = value.apply_visitor(wfl_variant_visitor{});
580 }
581
582 return variant(std::move(result));
583 }
584
585 return variant();
586}
587
589{
590 add_input(inputs, "__all_children");
591 add_input(inputs, "__children");
592 add_input(inputs, "__attributes");
593
594 for(const auto& [key, _] : cfg_.attribute_range()) {
595 if(key.find_first_not_of(formula::id_chars) != std::string::npos) {
596 add_input(inputs, key);
597 }
598 }
599}
600
602{
603 const config_callable* cfg_callable = dynamic_cast<const config_callable*>(callable);
604 if(cfg_callable == nullptr) {
605 return formula_callable::do_compare(callable);
606 }
607
608 if(cfg_ == cfg_callable->get_config()) {
609 return 0;
610 }
611
612 return cfg_.hash().compare(cfg_callable->get_config().hash());
613}
614
615terrain_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))
616{
618}
619
620variant terrain_callable::get_value(const std::string& key) const
621{
622 if(key == "x") {
623 return variant(loc_.wml_x());
624 } else if(key == "y") {
625 return variant(loc_.wml_y());
626 } else if(key == "loc") {
627 return make_callable<location_callable>(loc_);
628 } else if(key == "id") {
629 return variant(std::string(t_.id()));
630 } else if(key == "name") {
631 return variant(t_.name());
632 } else if(key == "editor_name") {
633 return variant(t_.editor_name());
634 } else if(key == "description") {
635 return variant(t_.description());
636 } else if(key == "icon") {
637 return variant(t_.icon_image());
638 } else if(key == "light") {
639 return variant(t_.light_bonus(0));
640 } else if(key == "village") {
641 return variant(t_.is_village());
642 } else if(key == "castle") {
643 return variant(t_.is_castle());
644 } else if(key == "keep") {
645 return variant(t_.is_keep());
646 } else if(key == "healing") {
647 return variant(t_.gives_healing());
648 } else if(key == "owner_side") {
649 return variant(owner_);
650 }
651
652 return variant();
653}
654
656{
657 add_input(inputs, "x");
658 add_input(inputs, "y");
659 add_input(inputs, "loc");
660 add_input(inputs, "id");
661 add_input(inputs, "name");
662 add_input(inputs, "editor_name");
663 add_input(inputs, "description");
664 add_input(inputs, "icon");
665 add_input(inputs, "light");
666 add_input(inputs, "village");
667 add_input(inputs, "castle");
668 add_input(inputs, "keep");
669 add_input(inputs, "healing");
670 add_input(inputs, "owner_side");
671}
672
674{
675 const terrain_callable* terr_callable = dynamic_cast<const terrain_callable*>(callable);
676 if(terr_callable == nullptr) {
677 return formula_callable::do_compare(callable);
678 }
679
680 const map_location& other_loc = terr_callable->loc_;
681 return loc_.do_compare(other_loc);
682}
683
685 return board_.map();
686}
687
689{
690 add_input(inputs, "w");
691 add_input(inputs, "h");
692}
693
694variant gamemap_callable::get_value(const std::string& key) const
695{
696 if(key == "terrain") {
697 int w = get_gamemap().w();
698 int h = get_gamemap().h();
699
700 std::vector<variant> vars;
701 for(int i = 0; i < w; i++) {
702 for(int j = 0; j < h; j++) {
703 const map_location loc(i, j);
704 vars.emplace_back(std::make_shared<terrain_callable>(board_, loc));
705 }
706 }
707
708 return variant(std::move(vars));
709 } else if(key == "gamemap") {
710 int w = get_gamemap().w();
711 int h = get_gamemap().h();
712
713 std::map<variant, variant> vars;
714 for(int i = 0; i < w; i++) {
715 for(int j = 0; j < h; j++) {
716 const map_location loc(i, j);
717 vars.emplace(std::make_shared<location_callable>(loc), std::make_shared<terrain_callable>(board_, loc));
718 }
719 }
720
721 return variant(std::move(vars));
722 } else if(key == "w") {
723 return variant(get_gamemap().w());
724 } else if(key == "h") {
725 return variant(get_gamemap().h());
726 } else {
727 return variant();
728 }
729}
730
732{
733 add_input(inputs, "side_number");
734 add_input(inputs, "id");
735 add_input(inputs, "gold");
736 add_input(inputs, "start_gold");
737 add_input(inputs, "base_income");
738 add_input(inputs, "total_income");
739 add_input(inputs, "village_gold");
740 add_input(inputs, "village_support");
741 add_input(inputs, "recall_cost");
742 add_input(inputs, "is_human");
743 add_input(inputs, "is_ai");
744 add_input(inputs, "is_network");
745 add_input(inputs, "fog");
746 add_input(inputs, "shroud");
747 add_input(inputs, "hidden");
748 add_input(inputs, "flag");
749 add_input(inputs, "flag_icon");
750 add_input(inputs, "team_name");
751 add_input(inputs, "faction");
752 add_input(inputs, "faction_name");
753 add_input(inputs, "color");
754 add_input(inputs, "share_vision");
755 add_input(inputs, "carryover_bonus");
756 add_input(inputs, "carryover_percentage");
757 add_input(inputs, "carryover_add");
758 add_input(inputs, "recruit");
759 add_input(inputs, "wml_vars");
760}
761
762variant team_callable::get_value(const std::string& key) const
763{
764 if(key == "side") {
765 deprecated_message("team.side", DEP_LEVEL::INDEFINITE, version_info("1.17"), "Use side_number instead.");
766 return variant(team_.side());
767 } else if(key == "side_number") {
768 return variant(team_.side());
769 } else if(key == "id") {
770 return variant(team_.save_id());
771 } else if(key == "save_id") {
772 return variant(team_.save_id());
773 } else if(key == "gold") {
774 return variant(team_.gold());
775 } else if(key == "start_gold") {
776 return variant(team_.start_gold());
777 } else if(key == "base_income") {
778 return variant(team_.base_income());
779 } else if(key == "total_income") {
780 return variant(team_.total_income());
781 } else if(key == "village_gold") {
782 return variant(team_.village_gold());
783 } else if(key == "village_support") {
784 return variant(team_.village_support());
785 } else if(key == "recall_cost") {
786 return variant(team_.recall_cost());
787 } else if(key == "is_human") {
788 return variant(team_.is_local_human());
789 } else if(key == "is_ai") {
790 return variant(team_.is_local_ai());
791 } else if(key == "is_network") {
792 return variant(team_.is_network());
793 } else if(key == "fog") {
794 return variant(team_.uses_fog());
795 } else if(key == "shroud") {
796 return variant(team_.uses_shroud());
797 } else if(key == "hidden") {
798 return variant(team_.hidden());
799 } else if(key == "flag") {
800 return variant(team_.flag());
801 } else if(key == "flag_icon") {
802 return variant(team_.flag_icon());
803 } else if(key == "team_name") {
804 return variant(team_.team_name());
805 } else if(key == "faction") {
806 return variant(team_.faction());
807 } else if(key == "faction_name") {
808 return variant(team_.faction_name());
809 } else if(key == "color") {
810 return variant(team_.color());
811 } else if(key == "share_vision") {
813 } else if(key == "carryover_bonus") {
815 } else if(key == "carryover_percentage") {
817 } else if(key == "carryover_add") {
818 return variant(team_.carryover_add());
819 } else if(key == "recruit") {
820 std::vector<variant> result;
821 for(const auto& recruit : team_.recruits()) {
822 result.emplace_back(recruit);
823 }
824 return variant(std::move(result));
825 } else if(key == "recall") {
826 std::vector<variant> result;
827 for(const auto& u : team_.recall_list()) {
828 result.emplace_back(std::make_shared<unit_callable>(*u));
829 }
830 return variant(std::move(result));
831 } else if(key == "wml_vars") {
832 return make_callable<config_callable>(team_.variables());
833 }
834
835 return variant();
836}
837
838variant set_var_callable::get_value(const std::string& key) const
839{
840 if(key == "key") {
841 return variant(key_);
842 } else if(key == "value") {
843 return value_;
844 }
845
846 return variant();
847}
848
850{
851 add_input(inputs, "key");
852 add_input(inputs, "value");
853}
854
856{
857 if(auto obj = callable_cast<formula_callable*>(ctxt)) {
858 LOG_SF << "Setting variable: " << key_ << " -> " << value_.to_debug_string();
859 std::const_pointer_cast<formula_callable>(obj)->mutate_value(key_, value_);
860 return variant(true);
861 }
862
863 ERR_SF << "ERROR #" << 5001 << " while executing 'set_var' formula function";
864 return make_callable<safe_call_result>(fake_ptr(), 5001);
865}
866
867variant safe_call_callable::get_value(const std::string& key) const
868{
869 if(key == "main") {
870 return variant(main_);
871 } else if(key == "backup") {
872 return variant(backup_);
873 }
874
875 return variant();
876}
877
879{
880 add_input(inputs, "main");
881 add_input(inputs, "backup");
882}
883
885{
886 variant res;
887 if(auto action = callable_cast<action_callable*>(main_)) {
888 res = std::const_pointer_cast<action_callable>(action)->execute_self(ctxt);
889 }
890
891 if(callable_cast<safe_call_result*>(res)) {
892 /* If we have safe_call formula and either an error occurred, or the current action
893 * was not recognized, then evaluate backup formula from safe_call and execute it
894 * during the next loop
895 */
896
897 map_formula_callable callable(ctxt.as_callable());
898 callable.add("error", res);
899
900 /* Store the result in safe_call_callable in case we would like to display it to the user,
901 * for example if this formula was executed from the commandline.
902 */
903 backup_ = get_backup()->evaluate(callable);
905 }
906 return variant(true);
907}
908
909variant safe_call_result::get_value(const std::string& key) const
910{
911 if(key == "status") {
912 return variant(status_);
913 } else if(key == "object") {
914 if(failed_callable_) {
916 }
917
918 return variant();
919 } else if(key == "current_loc" && current_unit_location_ != map_location()) {
920 return make_callable<location_callable>(current_unit_location_);
921 }
922
923 return variant();
924}
925
927{
928 add_input(inputs, "status");
929 add_input(inputs, "object");
930
932 add_input(inputs, "current_loc");
933 }
934}
935
937{
938 add_input(inputs, "turn_number");
939 add_input(inputs, "time_of_day");
940 add_input(inputs, "side_number");
941 add_input(inputs, "sides");
942 add_input(inputs, "units");
943 add_input(inputs, "map");
944}
945
946variant gamestate_callable::get_value(const std::string &key) const
947{
948 if(key == "turn_number") {
949 return variant(resources::tod_manager->turn());
950 } else if(key == "time_of_day") {
951 return variant(resources::tod_manager->get_time_of_day().id);
952 } else if(key == "side_number") {
953 return variant(resources::controller->current_side());
954 } else if(key == "sides") {
955 std::vector<variant> vars;
956 for(const auto& team : resources::gameboard->teams()) {
957 vars.emplace_back(std::make_shared<team_callable>(team));
958 }
959 return variant(std::move(vars));
960 } else if(key == "units") {
961 std::vector<variant> vars;
962 for(const auto& unit : resources::gameboard->units()) {
963 vars.emplace_back(std::make_shared<unit_callable>(unit));
964 }
965 return variant(std::move(vars));
966 } else if(key == "map") {
967 return make_callable<gamemap_callable>(*resources::gameboard);
968 }
969
970 return variant();
971}
972
974{
975 add_input(inputs, "event");
976 add_input(inputs, "event_id");
977 add_input(inputs, "event_data");
978 add_input(inputs, "loc");
979 add_input(inputs, "unit");
980 add_input(inputs, "weapon");
981 add_input(inputs, "second_loc");
982 add_input(inputs, "second_unit");
983 add_input(inputs, "second_weapon");
984}
985
986variant event_callable::get_value(const std::string &key) const
987{
988 if(key == "event") {
989 return variant(event_info.name);
990 } else if(key == "event_id") {
991 return variant(event_info.id);
992 } else if(key == "loc") {
993 return make_callable<location_callable>(event_info.loc1);
994 } else if(key == "second_loc") {
995 return make_callable<location_callable>(event_info.loc2);
996 } else if(key == "event_data") {
997 return make_callable<config_callable>(event_info.data);
998 } else if(key == "unit") {
999 if(auto u1 = event_info.loc1.get_unit()) {
1000 return make_callable<unit_callable>(*u1);
1001 }
1002 } else if(key == "second_unit") {
1003 if(auto u2 = event_info.loc2.get_unit()) {
1004 return make_callable<unit_callable>(*u2);
1005 }
1006 } else if(key == "weapon") {
1007 if(event_info.data.has_child("first")) {
1008 first_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("first"));
1009 return make_callable<attack_type_callable>(*first_weapon);
1010 }
1011 } else if(key == "second_weapon") {
1012 if(event_info.data.has_child("second")) {
1013 second_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("second"));
1014 return make_callable<attack_type_callable>(*second_weapon);
1015 }
1016 }
1017
1018 return variant();
1019}
1020
1022{
1023 add_input(inputs, "red");
1024 add_input(inputs, "green");
1025 add_input(inputs, "blue");
1026 add_input(inputs, "alpha");
1027}
1028
1029variant color_callable::get_value(const std::string& key) const
1030{
1031 if(key == "red") {
1032 return variant(clr_.r);
1033 } else if(key == "green") {
1034 return variant(clr_.g);
1035 } else if(key == "blue") {
1036 return variant(clr_.b);
1037 } else if(key == "alpha") {
1038 return variant(clr_.a);
1039 }
1040
1041 return variant();
1042}
1043
1044} // namespace wfl
map_location loc
Definition move.cpp:172
#define LOG_SF
static lg::log_domain log_scripting_formula("scripting/formula")
#define ERR_SF
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
const_attr_itors attribute_range() const
Definition config.cpp:740
auto all_children_view() const
In-order iteration over all children.
Definition config.hpp:795
child_itors child_range(std::string_view key)
Definition config.cpp:268
bool has_attribute(std::string_view key) const
Definition config.cpp:157
bool has_child(std::string_view key) const
Determine whether a config has a child or not.
Definition config.cpp:312
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition config.cpp:362
std::string hash() const
Definition config.cpp:1227
Abstract class for exposing game data that doesn't depend on the GUI, however which for historical re...
virtual const gamemap & map() const =0
virtual const std::vector< team > & teams() const override
virtual const unit_map & units() const override
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:176
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
bool uses_shroud() const
Definition team.hpp:344
const t_string & faction_name() const
Definition team.hpp:338
const std::string & faction() const
Definition team.hpp:337
const std::set< std::string > & recruits() const
Definition team.hpp:250
int side() const
Definition team.hpp:182
const std::string & save_id() const
Definition team.hpp:258
int village_support() const
Definition team.hpp:207
int recall_cost() const
Definition team.hpp:198
bool is_local_human() const
Definition team.hpp:294
int village_gold() const
Definition team.hpp:197
team_shared_vision::type share_vision() const
Definition team.hpp:419
const std::string & flag_icon() const
Definition team.hpp:328
int gold() const
Definition team.hpp:183
bool carryover_add() const
Definition team.hpp:385
recall_list_manager & recall_list()
Definition team.hpp:242
int carryover_percentage() const
Definition team.hpp:383
bool is_network() const
Definition team.hpp:289
int total_income() const
Definition team.hpp:201
bool is_local_ai() const
Definition team.hpp:295
double carryover_bonus() const
Definition team.hpp:387
const std::string & team_name() const
Definition team.hpp:323
int start_gold() const
Definition team.hpp:184
int base_income() const
Definition team.cpp:403
bool uses_fog() const
Definition team.hpp:345
bool hidden() const
Definition team.hpp:375
const std::string & color() const
Definition team.hpp:283
const std::string & flag() const
Definition team.hpp:327
config & variables()
Definition team.hpp:390
bool is_keep() const
Definition terrain.hpp:153
const std::string & id() const
Definition terrain.hpp:52
bool is_castle() const
Definition terrain.hpp:152
const t_string & name() const
Definition terrain.hpp:48
const std::string & icon_image() const
Definition terrain.hpp:44
bool is_village() const
Definition terrain.hpp:151
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:142
int gives_healing() const
Definition terrain.hpp:150
const t_string & description() const
Definition terrain.hpp:50
const t_string & editor_name() const
Definition terrain.hpp:49
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:274
std::vector< std::string > get_ability_id_list() const
Definition types.cpp:564
int hitpoints() const
Definition types.hpp:165
const_attack_itors attacks() const
Definition types.cpp:505
const std::string & usage() const
Definition types.hpp:179
int movement() const
Definition types.hpp:170
const t_string & type_name() const
The name of the unit in the current language setting.
Definition types.hpp:142
int cost() const
Definition types.hpp:176
int experience_needed(bool with_acceleration=true) const
Definition types.cpp:539
bool musthave_status(const std::string &status) const
Definition types.cpp:630
config::const_child_itors possible_traits() const
Definition types.hpp:239
int level() const
Definition types.hpp:168
unit_alignments::type alignment() const
Definition types.hpp:198
const std::string & id() const
The id for this unit_type.
Definition types.hpp:145
int recall_cost() const
Definition types.hpp:169
This class represents a single unit of a specific type.
Definition unit.hpp:39
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
variant get_value(const std::string &key) const override
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:134
virtual int do_compare(const formula_callable *callable) const
Definition callable.hpp:144
static variant convert_vector(const std::vector< T > &input_vector)
Definition callable.hpp:124
static variant convert_set(const std::set< T > &input_set)
Definition callable.hpp:113
static const char *const id_chars
Definition formula.hpp:83
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 get_inputs(formula_input_vector &inputs) const override
std::string serialize_to_string() const override
Inherited from formula_callable.
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:249
variant execute_self(variant ctxt) override
const expression_ptr & get_backup() const
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
const_formula_callable_ptr as_callable() const
Definition variant.cpp:377
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition variant.cpp:686
Definitions for the interface to Wesnoth Markup Language (WML).
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
const config * cfg
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _(const char *str)
Definition gettext.hpp:100
std::vector< std::string > get_ability_id_list() const
Get a list of all abilities by ID.
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition unit.hpp:427
unit_alignments::type alignment() const
The alignment of this unit.
Definition unit.hpp:397
bool incapacitated() const
Check if the unit has been petrified.
Definition unit.hpp:826
int level() const
The current level of this unit.
Definition unit.hpp:481
std::string usage() const
Gets this unit's usage.
Definition unit.hpp:608
const std::set< std::string > & recruits() const
The type IDs of the other units this unit may recruit, if possible.
Definition unit.hpp:546
int hitpoints() const
The current number of hitpoints this unit has.
Definition unit.hpp:421
int cost() const
How much gold is required to recruit this unit.
Definition unit.hpp:555
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition unit.cpp:1446
const std::string & type_id() const
The id of this unit's type.
Definition unit.cpp:1964
bool get_hidden() const
Gets whether this unit is currently hidden on the map.
Definition unit.hpp:642
const std::set< std::string > get_states() const
Get the status effects currently affecting the unit.
Definition unit.cpp:1429
const std::string & get_role() const
Gets this unit's role.
Definition unit.hpp:591
const unit_race * race() const
Gets this unit's race.
Definition unit.hpp:415
int experience() const
The current number of experience points this unit has.
Definition unit.hpp:445
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition unit.hpp:534
const std::string & id() const
Gets this unit's id.
Definition unit.hpp:286
int side() const
The side this unit belongs to.
Definition unit.hpp:249
config & variables()
Gets any user-defined variables this unit 'owns'.
Definition unit.hpp:625
const std::string & variation() const
The ID of the variation of this unit's type.
Definition unit.hpp:494
std::size_t underlying_id() const
This unit's unique internal ID.
Definition unit.hpp:298
int max_experience() const
The max number of experience points this unit can have.
Definition unit.hpp:451
unit_race::GENDER gender() const
The gender of this unit.
Definition unit.hpp:387
const t_string & name() const
Gets this unit's translatable display name.
Definition unit.hpp:309
const advances_to_t & advances_to() const
Gets the possible types this unit can advance to on level-up.
Definition unit.hpp:150
attack_itors attacks()
Gets an iterator over this unit's attacks.
Definition unit.hpp:848
int max_attacks() const
The maximum number of attacks this unit may perform per turn, usually 1.
Definition unit.hpp:884
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
Definition unit.hpp:900
std::size_t advancements_count() const
Definition unit.hpp:1487
std::size_t traits_count() const
Definition unit.hpp:1477
std::size_t objects_count() const
Definition unit.hpp:1482
bool get_emit_zoc() const
Gets the raw zone-of-control flag, disregarding incapacitated.
Definition unit.hpp:1314
const movetype & movement_type() const
Get the unit's movement type.
Definition unit.hpp:1400
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
Definition unit.hpp:1252
int total_movement() const
The maximum moves this unit has.
Definition unit.hpp:1236
map_location::direction facing() const
The current direction this unit is facing within its hex.
Definition unit.hpp:1343
bool resting() const
Checks whether this unit is 'resting'.
Definition unit.hpp:1296
bool is_flying() const
Check if the unit is a flying unit.
Definition unit.hpp:1436
int upkeep() const
Gets the amount of gold this unit costs a side per turn.
Definition unit.cpp:1751
std::vector< std::string > get_objects_list() const
Definition unit.hpp:1032
bool is_healthy() const
Gets whether this unit is healthy - ie, always rest heals.
Definition unit.hpp:1192
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
Definition unit.hpp:1186
std::vector< std::string > get_traits_list() const
Gets a list of the traits this unit currently has, including hidden traits.
Definition unit.hpp:1027
std::vector< std::string > get_advancements_list() const
Definition unit.hpp:1037
Standard logging facilities (interface).
::tod_manager * tod_manager
Definition resources.cpp:29
game_board * gameboard
Definition resources.cpp:20
play_controller * controller
Definition resources.cpp:21
std::vector< formula_input > formula_input_vector
variant execute_actions(const variant &execute, const variant &context)
Executes all action_callables in execute using the provided context.
Definition variant.cpp:696
int w
Definition pathfind.cpp:188
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
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
unit_const_ptr get_unit() const
entity_location loc1
Definition pump.hpp:65
entity_location loc2
Definition pump.hpp:66
Encapsulates the map of the game.
Definition location.hpp:46
static std::string write_direction(direction dir)
Definition location.cpp:154
int wml_y() const
Definition location.hpp:187
int wml_x() const
Definition location.hpp:186
static const map_location & null_location()
Definition location.hpp:103
int do_compare(const map_location &a) const
three-way comparator
Definition location.hpp:127
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition enum_base.hpp:46
variant operator()(double i) const
variant operator()(int i) const
variant operator()(const std::string &s) const
variant operator()(unsigned long long i) const
variant operator()(const t_string &s) const
variant operator()(utils::monostate) const
variant operator()(bool b) const
mock_party p
static map_location::direction s
#define i
#define h
#define b