32 #define ERR_NG LOG_STREAM(err, log_engine)
35 class temporary_facing
45 u_->set_facing(new_dir);
51 u_->set_facing(save_dir_);
116 bool affects_side(
const config& cfg,
const std::vector<team>&
teams,
size_t side,
size_t other_side)
118 if (side == other_side)
119 return cfg[
"affect_allies"].to_bool(
true);
120 if (teams[side - 1].is_enemy(other_side))
121 return cfg[
"affect_enemies"].to_bool();
123 return cfg[
"affect_allies"].to_bool();
144 for(
int i = 0;
i != 6; ++
i) {
146 if (it == units.
end() || it->incapacitated())
155 for (
const config &j : it->abilities_.child_range(tag_name)) {
157 it->ability_active(tag_name, j, adjacent[i]) &&
185 for(
int i = 0;
i != 6; ++
i) {
187 if (it == units.
end() || it->incapacitated())
196 for (
const config &j : it->abilities_.child_range(tag_name)) {
198 it->ability_active(tag_name, j, adjacent[i]) &&
212 std::vector<std::string>
res;
235 return !value.
blank() ? value : cfg[default_key];
246 return default_value(cfg,
263 std::vector<boost::tuple<t_string,t_string,t_string> >
res;
265 active_list->clear();
272 gender_value(ab.cfg,
gender_,
"name",
"female_name",
"name").t_str();
275 res.push_back(boost::make_tuple(
276 ab.cfg[
"name"].t_str(),
278 ab.cfg[
"description"].t_str() ));
280 active_list->push_back(
true);
287 gender_value(ab.cfg,
gender_,
"name_inactive",
288 "female_name_inactive",
"name_inactive");
290 gender_value(ab.cfg,
gender_,
"name",
"female_name",
"name").t_str();
293 res.push_back(boost::make_tuple(
294 default_value(ab.cfg,
"name_inactive",
"name").t_str(),
296 default_value(ab.cfg,
"description_inactive",
"description").t_str() ));
297 active_list->push_back(
false);
311 bool illuminates = ability ==
"illuminates";
332 if (unit == units.
end())
334 if (!ufilt(*unit, *
this))
336 if (
i.has_attribute(
"is_enemy")) {
338 if (
i[
"is_enemy"].to_bool() != dc.
teams()[unit->side() - 1].is_enemy(
side_)) {
344 if (
i[
"count"].empty() && count != dirs.size()) {
356 adj_filter.
flatten(illuminates);
369 if (
i[
"count"].empty() && count != dirs.size()) {
385 bool illuminates = ability ==
"illuminates";
387 assert(dir >=0 && dir <= 5);
392 if (
i.has_attribute(
"adjacent")) {
394 if (
std::find(dirs.begin(), dirs.end(), direction) == dirs.end()) {
414 bool affect_self = cfg[
"affect_self"].to_bool(
true);
415 if (!filter || !affect_self)
return affect_self;
422 return itors.first != itors.second;
428 if (
cfgs_.empty() ) {
434 bool only_cumulative =
true;
440 int value = (*
p.first)[key].to_int(def);
441 if ((*
p.first)[
"cumulative"].to_bool()) {
443 if (value < 0) value = -
value;
444 if (only_cumulative && value >= abs_max) {
448 }
else if (only_cumulative || value > flat) {
449 only_cumulative =
false;
454 return std::make_pair(flat + stack, best_loc);
459 if (
cfgs_.empty() ) {
465 bool only_cumulative =
true;
471 int value = (*
p.first)[key].to_int(def);
472 if ((*
p.first)[
"cumulative"].to_bool()) {
474 if (value < 0) value = -
value;
475 if (only_cumulative && value <= abs_max) {
479 }
else if (only_cumulative || value < flat) {
480 only_cumulative =
false;
485 return std::make_pair(flat + stack, best_loc);
529 bool get_special_children(std::vector<const config*>&
result,
const config& parent,
533 if (
sp.key ==
id ||
sp.cfg[
"id"] ==
id) {
537 result.push_back(&
sp.cfg);
555 std::vector<const config*> list;
556 if ( get_special_children(list,
specials_, special, simple_check) ) {
573 std::vector<const config*> list;
613 std::vector<bool> *active_list)
const
616 std::vector<std::pair<t_string, t_string> >
res;
618 active_list->clear();
625 res.push_back(std::make_pair(name,
sp.cfg[
"description"].t_str() ));
627 active_list->push_back(
true);
630 t_string const &
name = default_value(
sp.cfg,
"name_inactive",
"name").t_str();
632 res.push_back(std::make_pair(
633 name, default_value(
sp.cfg,
"description_inactive",
"description").t_str() ));
634 active_list->push_back(
false);
660 if (!res.empty()) res +=
',';
718 unsigned & max_attacks)
const
724 if ( attacks_value < 0 ) {
726 ERR_NG <<
"negative number of strikes after applying weapon specials" << std::endl;
731 if ( !swarm_specials.
empty() ) {
732 min_attacks = std::max<int>(0, swarm_specials.
highest(
"swarm_attacks_min").first);
733 max_attacks = std::max<int>(0, swarm_specials.
highest(
"swarm_attacks_max", attacks_value).first);
735 min_attacks = max_attacks = attacks_value;
758 bool special_affects_opponent(
const config& special,
bool is_attacker)
762 if ( apply_to.empty() )
764 if ( apply_to ==
"both" )
766 if ( apply_to ==
"opponent" )
768 if ( is_attacker && apply_to ==
"defender" )
770 if ( !is_attacker && apply_to ==
"attacker" )
780 bool special_affects_self(
const config& special,
bool is_attacker)
784 if ( apply_to.empty() )
786 if ( apply_to ==
"both" )
788 if ( apply_to ==
"self" )
790 if ( is_attacker && apply_to ==
"attacker" )
792 if ( !is_attacker && apply_to ==
"defender")
811 const bool for_listing,
814 if (for_listing && !loc.
valid())
822 const config & filter_child = filter.
child(child_tag);
828 if (!un_it.
valid()) {
836 return ufilt.matches(*un_it, loc);
840 if (!ufilt.matches(*un_it, loc, *u2)) {
845 if (
const config & filter_weapon = filter_child.
child(
"filter_weapon") ) {
866 bool include_backstab)
const
871 if ( !include_backstab )
872 if ( special[
"backstab"].to_bool() )
886 const std::string & active_on = special[
"active_on"];
887 if ( !active_on.empty() ) {
916 if (!special_unit_matches(att, def, att_loc, att_weapon, special,
is_for_listing_,
"filter_attacker"))
918 if (!special_unit_matches(def, att, def_loc, def_weapon, special,
is_for_listing_,
"filter_defender"))
935 if (unit == units.
end() || !filter.
matches(*unit, adjacent[index], *
self))
937 if (
i.has_attribute(
"is_enemy")) {
939 if (
i[
"is_enemy"].to_bool() != dc.
teams()[unit->side() - 1].is_enemy(self->side())) {
945 if (
i[
"count"].empty() && count != dirs.size()) {
968 if (
i[
"count"].empty() && count != dirs.size()) {
994 if (
const config &apply_filter = cfg.
child(
"filter_base_value")) {
1001 return (cond_eq.
empty() || def == cond_eq.
to_int()) &&
1016 int value_set = def;
1017 bool value_is_set =
false;
1018 std::map<std::string,individual_effect> values_add;
1019 std::map<std::string,individual_effect> values_mul;
1020 std::map<std::string,individual_effect> values_div;
1025 const config& cfg = *ability.first;
1028 if (!cfg[
"backstab"].blank()) {
1029 lg::wml_error() <<
"The backstab= key in weapon specials is deprecated; use [filter_adjacent] instead\n";
1032 if (!backstab && cfg[
"backstab"].to_bool())
1039 bool cumulative = cfg[
"cumulative"].to_bool();
1040 if (!value_is_set && !cumulative) {
1042 set_effect.
set(
SET, value, ability.first, ability.second);
1044 if (cumulative) value_set = std::max<int>(value_set, def);
1045 if (value > value_set) {
1047 set_effect.
set(
SET, value, ability.first, ability.second);
1050 value_is_set =
true;
1056 if(add_effect == values_add.end() || add > add_effect->second.value) {
1057 values_add[effect_id].set(
ADD, add, ability.first, ability.second);
1063 if(sub_effect == values_add.end() || sub > sub_effect->second.value) {
1064 values_add[effect_id].set(
ADD, sub, ability.first, ability.second);
1068 int multiply =
int(
v->to_double() * 100);
1070 if(mul_effect == values_mul.end() || multiply > mul_effect->second.value) {
1071 values_mul[effect_id].set(
MUL, multiply, ability.first, ability.second);
1076 ERR_NG <<
"division by zero with divide= in ability/weapon special " << effect_id << std::endl;
1079 int divide =
int(
v->to_double() * 100);
1081 if(div_effect == values_div.end() || divide > div_effect->second.value) {
1082 values_div[effect_id].set(
DIV, divide, ability.first, ability.second);
1100 double multiplier = 1.0;
1102 std::map<std::string,individual_effect>::const_iterator
e, e_end;
1103 for (e = values_mul.begin(), e_end = values_mul.end(); e != e_end; ++
e) {
1104 multiplier *= e->second.value/100.0;
1107 for (e = values_div.begin(), e_end = values_div.end(); e != e_end; ++
e) {
1108 divisor *= e->second.value/100.0;
1112 for (e = values_add.begin(), e_end = values_add.end(); e != e_end; ++
e) {
1113 addition += e->second.value;
const t_string & name() const
child_itors child_range(const std::string &key)
std::vector< individual_effect > effect_list_
::tod_manager * tod_manager
virtual const display_context & get_disp_context() const =0
bool ability_affects_adjacent(const std::string &ability, const config &cfg, int dir, const map_location &loc, const unit &from) const
bool matches_filter(const config &filter) const
Returns whether or not *this matches the given filter.
void set_specials_context(const map_location &unit_loc, const map_location &other_loc, bool attacking, const attack_type *other_attack) const
Sets the context under which specials will be checked for being active.
const t_string & name() const
The unit name for display.
int modified_damage(bool is_backstab) const
Returns the damage per attack of this weapon, considering specials.
GLuint GLuint GLsizei GLenum type
std::vector< boost::tuple< t_string, t_string, t_string > > ability_tooltips(std::vector< bool > *active_list=nullptr) const
Tuple of: neutral ability name, gendered ability name, description.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
void set(value_modifier t, int val, const config *abil, const map_location &l)
void set_specials_context_for_listing() const
GLuint const GLfloat * val
std::pair< int, map_location > highest(const std::string &key, int def=0) const
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
static std::vector< DIRECTION > parse_directions(const std::string &str)
Parse_directions takes a comma-separated list, and filters out any invalid directions.
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Returns true if the unit is currently under effect by an ability with this given TAG NAME...
std::string weapon_specials(bool only_active=false, bool is_backstab=false) const
Returns a comma-separated string of active names for the specials of *this.
bool empty() const
Tests for an attribute that either was never set or was set to "".
std::vector< unit_ability > cfgs_
std::pair< const_child_iterator, const_child_iterator > const_child_itors
Variant for storing WML attributes.
bool filter_base_matches(const config &cfg, int def)
bool match(const map_location &loc) const
bool get_special_bool(const std::string &special, bool simple_check=false) const
Returns whether or not *this has a special with a tag or id equal to special.
bool blank() const
Tests for an attribute that was never set.
static std::vector< team > *& teams
static std::string sub(const std::string &s)
Private function to surround an argument with brackets.
std::vector< team > * teams
bool matches(const unit &u, const map_location &loc) const
Determine if *this matches filter at a specified location.
filter_context * filter_con
GLsizei const GLfloat * value
all_children_itors all_children_range() const
In-order iteration over all children.
bool ability_affects_self(const std::string &ability, const config &cfg, const map_location &loc) const
void flatten(const bool flat_tod=true)
effect(const unit_ability_list &list, int def, bool backstab)
static const map_location & null_location()
unit_race::GENDER gender_
bool has_ability_type(const std::string &ability) const
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
GLuint GLuint GLsizei count
bool special_active(const config &special, AFFECTS whom, bool include_backstab=true) const
Returns whether or not the given special is active for the specified unit, based on the current conte...
Encapsulates the map of the game.
virtual const std::vector< team > & teams() const =0
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
std::vector< std::pair< int, int > > parse_ranges(std::string const &str)
std::pair< const config *, map_location > unit_ability
The things contained within a unit_ability_list.
void modified_attacks(bool is_backstab, unsigned &min_attacks, unsigned &max_attacks) const
Calculates the number of attacks this weapon has, considering specials.
DIRECTION
Valid directions which can be moved in our hexagonal world.
unit_ability_list get_specials(const std::string &special) const
Returns the currently active specials as an ability list, given the current context (see set_specials...
unit_ability_list get_abilities(const std::string &tag_name, const map_location &loc) const
GLuint const GLchar * name
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
std::pair< int, map_location > lowest(const std::string &key, int def=0) const
bool find(E event, F functor)
Tests whether an event handler is available.
bool ability_active(const std::string &ability, const config &cfg, const map_location &loc) const
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
A variable-expanding proxy for the config class.
Standard logging facilities (interface).
Container associating units to locations.
int to_int(int def=0) const
void push_back(const unit_ability &ability)
int get_composite_value() const
unit_iterator find(size_t id)
GLuint GLdouble GLdouble u2
A config object defines a single node in a WML file, with access to child nodes.
const attack_type * other_attack_
std::vector< std::string > get_ability_list() const
GLsizei const GLcharARB ** string
static lg::log_domain log_engine("engine")
std::vector< std::pair< t_string, t_string > > special_tooltips(std::vector< bool > *active_list=nullptr) const
Returns a vector of names and descriptions for the specials of *this.