wesnoth/src/formula/function_gamestate.cpp
Charles Dang 45f871067f Use std::size_t everywhere instead of plain size_t
Excludes:
* spirit_po/
* xBRZ/

(cherry-picked from commit fc2a58f693)
2018-10-07 03:17:59 +00:00

260 lines
7.5 KiB
C++

/*
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "formula/function_gamestate.hpp"
#include "formula/callable_objects.hpp"
#include "resources.hpp"
#include "game_board.hpp"
#include "map/map.hpp"
#include "pathutils.hpp"
#include "units/types.hpp"
#include "units/unit.hpp"
namespace wfl {
namespace gamestate {
DEFINE_WFL_FUNCTION(adjacent_locs, 1, 1)
{
const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "adjacent_locs:location")).convert_to<location_callable>()->loc();
adjacent_loc_array_t adj;
get_adjacent_tiles(loc, adj.data());
std::vector<variant> v;
for(unsigned n = 0; n < adj.size(); ++n) {
if(resources::gameboard->map().on_board(adj[n])) {
v.emplace_back(std::make_shared<location_callable>(adj[n]));
}
}
return variant(v);
}
DEFINE_WFL_FUNCTION(locations_in_radius, 2, 2)
{
const map_location loc = args()[0]->evaluate(variables, fdb).convert_to<location_callable>()->loc();
int range = args()[1]->evaluate(variables, fdb).as_int();
if(range < 0) {
return variant();
}
if(!range) {
return variant(std::make_shared<location_callable>(loc));
}
std::vector<map_location> res;
get_tiles_in_radius(loc, range, res);
std::vector<variant> v;
v.reserve(res.size() + 1);
v.emplace_back(std::make_shared<location_callable>(loc));
for(std::size_t n = 0; n != res.size(); ++n) {
if(resources::gameboard->map().on_board(res[n])) {
v.emplace_back(std::make_shared<location_callable>(res[n]));
}
}
return variant(v);
}
DEFINE_WFL_FUNCTION(get_unit_type, 1, 1)
{
const std::string type = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "get_unit_type:name")).as_string();
const unit_type *ut = unit_types.find(type);
if(ut) {
return variant(std::make_shared<unit_type_callable>(*ut));
}
return variant();
}
DEFINE_WFL_FUNCTION(unit_at, 1, 1)
{
variant loc_var = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "unit_at:location"));
if(loc_var.is_null()) {
return variant();
}
auto loc = loc_var.convert_to<location_callable>();
const unit_map::const_iterator i = resources::gameboard->units().find(loc->loc());
if(i != resources::gameboard->units().end()) {
return variant(std::make_shared<unit_callable>(*i));
} else {
return variant();
}
}
DEFINE_WFL_FUNCTION(defense_on, 2, 2)
{
variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "defense_on:unit"));
variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "defense_on:location"));
if(u.is_null() || loc_var.is_null()) {
return variant();
}
auto u_call = u.try_convert<unit_callable>();
auto u_type = u.try_convert<unit_type_callable>();
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
if(u_call) {
const unit& un = u_call->get_unit();
if(un.total_movement() < un.movement_cost((resources::gameboard->map())[loc]))
return variant();
if(!resources::gameboard->map().on_board(loc)) {
return variant();
}
return variant(100 - un.defense_modifier((resources::gameboard->map())[loc]));
}
if(u_type) {
const unit_type& un = u_type->get_unit_type();
if(un.movement() < un.movement_type().movement_cost((resources::gameboard->map())[loc]))
return variant();
if(!resources::gameboard->map().on_board(loc)) {
return variant();
}
return variant(100 - un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
}
return variant();
}
DEFINE_WFL_FUNCTION(chance_to_hit, 2, 2)
{
variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "chance_to_hit:unit"));
variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "chance_to_hit:location"));
if(u.is_null() || loc_var.is_null()) {
return variant();
}
auto u_call = u.try_convert<unit_callable>();
auto u_type = u.try_convert<unit_type_callable>();
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
if(u_call) {
const unit& un = u_call->get_unit();
if(!resources::gameboard->map().on_board(loc)) {
return variant();
}
return variant(un.defense_modifier((resources::gameboard->map())[loc]));
}
if(u_type) {
const unit_type& un = u_type->get_unit_type();
if(!resources::gameboard->map().on_board(loc)) {
return variant();
}
return variant(un.movement_type().defense_modifier((resources::gameboard->map())[loc]));
}
return variant();
}
DEFINE_WFL_FUNCTION(movement_cost, 2, 2)
{
variant u = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "movement_cost:unit"));
variant loc_var = args()[1]->evaluate(variables, add_debug_info(fdb, 0, "movement_cost:location"));
if(u.is_null() || loc_var.is_null()) {
return variant();
}
//we can pass to this function either unit_callable or unit_type callable
auto u_call = u.try_convert<unit_callable>();
auto u_type = u.try_convert<unit_type_callable>();
const map_location& loc = loc_var.convert_to<location_callable>()->loc();
if(u_call) {
const unit& un = u_call->get_unit();
if(!resources::gameboard->map().on_board(loc)) {
return variant();
}
return variant(un.movement_cost((resources::gameboard->map())[loc]));
}
if(u_type) {
const unit_type& un = u_type->get_unit_type();
if(!resources::gameboard->map().on_board(loc)) {
return variant();
}
return variant(un.movement_type().movement_cost((resources::gameboard->map())[loc]));
}
return variant();
}
DEFINE_WFL_FUNCTION(enemy_of, 2, 2)
{
variant self_v = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "enemy_of:self"));
variant other_v = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "enemy_of:other"));
int self, other;
if(auto uc = self_v.try_convert<unit_callable>()) {
// For some obscure, bizarre reason, the unit callable returns a 0-indexed side. :|
self = uc->get_value("side").as_int() + 1;
} else if(auto tc = self_v.try_convert<team_callable>()) {
self = tc->get_value("side").as_int();
} else {
self = self_v.as_int();
}
if(auto uc = other_v.try_convert<unit_callable>()) {
// For some obscure, bizarre reason, the unit callable returns a 0-indexed side. :|
other = uc->get_value("side").as_int() + 1;
} else if(auto tc = other_v.try_convert<team_callable>()) {
other = tc->get_value("side").as_int();
} else {
other = other_v.as_int();
}
int num_teams = resources::gameboard->teams().size();
if(self < 1 || self > num_teams || other < 1 || other > num_teams) {
return variant(0);
}
return variant(resources::gameboard->get_team(self).is_enemy(other) ? 1 : 0);
}
} // namespace gamestate
gamestate_function_symbol_table::gamestate_function_symbol_table(std::shared_ptr<function_symbol_table> parent) : function_symbol_table(parent) {
using namespace gamestate;
function_symbol_table& functions_table = *this;
DECLARE_WFL_FUNCTION(get_unit_type);
DECLARE_WFL_FUNCTION(unit_at);
DECLARE_WFL_FUNCTION(defense_on);
DECLARE_WFL_FUNCTION(chance_to_hit);
DECLARE_WFL_FUNCTION(movement_cost);
DECLARE_WFL_FUNCTION(adjacent_locs); // This is deliberately duplicated here; this form excludes off-map locations, while the core form does not
DECLARE_WFL_FUNCTION(locations_in_radius);
DECLARE_WFL_FUNCTION(enemy_of);
}
}