The Battle for Wesnoth  1.15.0-dev
function_gamestate.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 #include "formula/callable_objects.hpp"
17 
18 #include "resources.hpp"
19 #include "game_board.hpp"
20 #include "map/map.hpp"
21 #include "pathutils.hpp"
22 #include "units/types.hpp"
23 #include "units/unit.hpp"
24 
25 namespace wfl {
26 
27 namespace gamestate {
28 
29 DEFINE_WFL_FUNCTION(adjacent_locs, 1, 1)
30 {
31  const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "adjacent_locs:location")).convert_to<location_callable>()->loc();
33  get_adjacent_tiles(loc, adj.data());
34 
35  std::vector<variant> v;
36  for(unsigned n = 0; n < adj.size(); ++n) {
37  if(resources::gameboard->map().on_board(adj[n])) {
38  v.emplace_back(std::make_shared<location_callable>(adj[n]));
39  }
40  }
41 
42  return variant(v);
43 }
44 
45 DEFINE_WFL_FUNCTION(locations_in_radius, 2, 2)
46 {
47  const map_location loc = args()[0]->evaluate(variables, fdb).convert_to<location_callable>()->loc();
48 
49  int range = args()[1]->evaluate(variables, fdb).as_int();
50 
51  if(range < 0) {
52  return variant();
53  }
54 
55  if(!range) {
56  return variant(std::make_shared<location_callable>(loc));
57  }
58 
59  std::vector<map_location> res;
60 
61  get_tiles_in_radius(loc, range, res);
62 
63  std::vector<variant> v;
64  v.reserve(res.size() + 1);
65  v.emplace_back(std::make_shared<location_callable>(loc));
66 
67  for(std::size_t n = 0; n != res.size(); ++n) {
68  if(resources::gameboard->map().on_board(res[n])) {
69  v.emplace_back(std::make_shared<location_callable>(res[n]));
70  }
71  }
72 
73  return variant(v);
74 }
75 
77 {
78  const std::string type = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "get_unit_type:name")).as_string();
79 
80  const unit_type *ut = unit_types.find(type);
81  if(ut) {
82  return variant(std::make_shared<unit_type_callable>(*ut));
83  }
84 
85  return variant();
86 }
87 
88 DEFINE_WFL_FUNCTION(unit_at, 1, 1)
89 {
90  variant loc_var = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "unit_at:location"));
91  if(loc_var.is_null()) {
92  return variant();
93  }
94  auto loc = loc_var.convert_to<location_callable>();
96  if(i != resources::gameboard->units().end()) {
97  return variant(std::make_shared<unit_callable>(*i));
98  } else {
99  return variant();
100  }
101 }
102 
103 DEFINE_WFL_FUNCTION(defense_on, 2, 2)
104 {
105  variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "defense_on:unit"));
106  variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "defense_on:location"));
107  if(u.is_null() || loc_var.is_null()) {
108  return variant();
109  }
110 
111  auto u_call = u.try_convert<unit_callable>();
112  auto u_type = u.try_convert<unit_type_callable>();
113  const map_location& loc = loc_var.convert_to<location_callable>()->loc();
114 
115  if(u_call) {
116  const unit& un = u_call->get_unit();
117 
118  if(un.total_movement() < un.movement_cost((resources::gameboard->map())[loc]))
119  return variant();
120 
121  if(!resources::gameboard->map().on_board(loc)) {
122  return variant();
123  }
124 
125  return variant(100 - un.defense_modifier((resources::gameboard->map())[loc]));
126  }
127 
128  if(u_type) {
129  const unit_type& un = u_type->get_unit_type();
130 
131  if(un.movement() < un.movement_type().movement_cost((resources::gameboard->map())[loc]))
132  return variant();
133 
134  if(!resources::gameboard->map().on_board(loc)) {
135  return variant();
136  }
137 
138  return variant(100 - un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
139  }
140 
141  return variant();
142 }
143 
144 DEFINE_WFL_FUNCTION(chance_to_hit, 2, 2)
145 {
146  variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "chance_to_hit:unit"));
147  variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "chance_to_hit:location"));
148  if(u.is_null() || loc_var.is_null()) {
149  return variant();
150  }
151 
152  auto u_call = u.try_convert<unit_callable>();
153  auto u_type = u.try_convert<unit_type_callable>();
154  const map_location& loc = loc_var.convert_to<location_callable>()->loc();
155 
156  if(u_call) {
157  const unit& un = u_call->get_unit();
158 
159  if(!resources::gameboard->map().on_board(loc)) {
160  return variant();
161  }
162 
163  return variant(un.defense_modifier((resources::gameboard->map())[loc]));
164  }
165 
166  if(u_type) {
167  const unit_type& un = u_type->get_unit_type();
168 
169  if(!resources::gameboard->map().on_board(loc)) {
170  return variant();
171  }
172 
173  return variant(un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
174  }
175 
176  return variant();
177 }
178 
179 DEFINE_WFL_FUNCTION(movement_cost, 2, 2)
180 {
181  variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "movement_cost:unit"));
182  variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 0, "movement_cost:location"));
183  if(u.is_null() || loc_var.is_null()) {
184  return variant();
185  }
186  //we can pass to this function either unit_callable or unit_type callable
187  auto u_call = u.try_convert<unit_callable>();
188  auto u_type = u.try_convert<unit_type_callable>();
189  const map_location& loc = loc_var.convert_to<location_callable>()->loc();
190 
191  if(u_call) {
192  const unit& un = u_call->get_unit();
193 
194  if(!resources::gameboard->map().on_board(loc)) {
195  return variant();
196  }
197 
198  return variant(un.movement_cost((resources::gameboard->map())[loc]));
199  }
200 
201  if(u_type) {
202  const unit_type& un = u_type->get_unit_type();
203 
204  if(!resources::gameboard->map().on_board(loc)) {
205  return variant();
206  }
207 
208  return variant(un.movement_type().movement_cost((resources::gameboard->map())[loc]));
209  }
210 
211  return variant();
212 }
213 
214 DEFINE_WFL_FUNCTION(enemy_of, 2, 2)
215 {
216  variant self_v = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "enemy_of:self"));
217  variant other_v = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "enemy_of:other"));
218  int self, other;
219 
220  if(auto uc = self_v.try_convert<unit_callable>()) {
221  // For some obscure, bizarre reason, the unit callable returns a 0-indexed side. :|
222  self = uc->get_value("side").as_int() + 1;
223  } else if(auto tc = self_v.try_convert<team_callable>()) {
224  self = tc->get_value("side").as_int();
225  } else {
226  self = self_v.as_int();
227  }
228 
229  if(auto uc = other_v.try_convert<unit_callable>()) {
230  // For some obscure, bizarre reason, the unit callable returns a 0-indexed side. :|
231  other = uc->get_value("side").as_int() + 1;
232  } else if(auto tc = other_v.try_convert<team_callable>()) {
233  other = tc->get_value("side").as_int();
234  } else {
235  other = other_v.as_int();
236  }
237 
238  int num_teams = resources::gameboard->teams().size();
239  if(self < 1 || self > num_teams || other < 1 || other > num_teams) {
240  return variant(0);
241  }
242  return variant(resources::gameboard->get_team(self).is_enemy(other) ? 1 : 0);
243 }
244 
245 } // namespace gamestate
246 
247 gamestate_function_symbol_table::gamestate_function_symbol_table(std::shared_ptr<function_symbol_table> parent) : function_symbol_table(parent) {
248  using namespace gamestate;
249  function_symbol_table& functions_table = *this;
251  DECLARE_WFL_FUNCTION(unit_at);
252  DECLARE_WFL_FUNCTION(defense_on);
253  DECLARE_WFL_FUNCTION(chance_to_hit);
254  DECLARE_WFL_FUNCTION(movement_cost);
255  DECLARE_WFL_FUNCTION(adjacent_locs); // This is deliberately duplicated here; this form excludes off-map locations, while the core form does not
256  DECLARE_WFL_FUNCTION(locations_in_radius);
257  DECLARE_WFL_FUNCTION(enemy_of);
258 }
259 
260 }
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
Definition: movetype.hpp:207
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1275
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:517
virtual const unit_map & units() const override
Definition: game_board.hpp:114
This class represents a single unit of a specific type.
Definition: unit.hpp:99
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit&#39;s movement cost on a particular terrain.
Definition: unit.hpp:1339
int as_int() const
Definition: variant.cpp:298
formula_debugger * add_debug_info(formula_debugger *fdb, int arg_number, const std::string &f_name)
void get_tiles_in_radius(const map_location &center, const int radius, std::vector< map_location > &result)
Function that will add to result all locations within radius tiles of center (excluding center itself...
Definition: pathutils.cpp:55
virtual const gamemap & map() const override
Definition: game_board.hpp:109
unit_type_data unit_types
Definition: types.cpp:1452
A single unit type that the player may recruit.
Definition: types.hpp:42
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit&#39;s defense on a given terrain.
Definition: unit.cpp:1596
const movetype & movement_type() const
Definition: types.hpp:174
game_board * gameboard
Definition: resources.cpp:20
std::array< map_location, 6 > adjacent_loc_array_t
Definition: location.hpp:170
Encapsulates the map of the game.
Definition: location.hpp:42
unit_iterator find(std::size_t id)
Definition: map.cpp:311
std::size_t i
Definition: function.cpp:933
DEFINE_WFL_FUNCTION(adjacent_locs, 1, 1)
int movement() const
Definition: types.hpp:152
int movement_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to move through the indicated terrain.
Definition: movetype.hpp:197
#define DECLARE_WFL_FUNCTION(name)
Declares a function name in the local function table functions_table.
Definition: function.hpp:47
static const unit_type & get_unit_type(const std::string &type_id)
Converts a string ID to a unit_type.
Definition: unit.cpp:244
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:58
std::shared_ptr< T > try_convert() const
Definition: variant.hpp:86
Definition: contexts.hpp:42
gamestate_function_symbol_table(std::shared_ptr< function_symbol_table > parent=nullptr)
int total_movement() const
The maximum moves this unit has.
Definition: unit.hpp:1165
static map_location::DIRECTION n
std::shared_ptr< T > convert_to() const
Definition: variant.hpp:96