unit_abilities.cpp

Go to the documentation of this file.
00001 /* $Id: unit_abilities.cpp 26798 2008-05-23 17:50:49Z mordante $ */
00002 /*
00003    Copyright (C) 2006 - 2008 by Dominic Bolin <dominic.bolin@exong.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 /**
00016  *  @file unit_abilities.cpp
00017  *  Manage unit-abilities, like heal, cure, and weapon_specials.
00018  */
00019 
00020 #include "unit.hpp"
00021 #include "unit_abilities.hpp"
00022 
00023 #include "log.hpp"
00024 #include "pathutils.hpp"
00025 #include "terrain_filter.hpp"
00026 #include "variable.hpp"
00027 
00028 #include <cassert>
00029 
00030 #define LOG_NG LOG_STREAM(info, engine)
00031 
00032 /*
00033  *
00034  * [abilities]
00035  * ...
00036  *
00037  * [heals]
00038  *  value=4
00039  *  max_value=8
00040  *  cumulative=no
00041  *  affect_allies=yes
00042  *  name= _ "heals"
00043 // *    name_inactive=null
00044  *  description=  _ "Heals:
00045 Allows the unit to heal adjacent friendly units at the beginning of each turn.
00046 
00047 A unit cared for by a healer may heal up to 4 HP per turn.
00048 A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
00049 // *    description_inactive=null
00050  *  icon="misc/..."
00051 // *    icon_inactive=null
00052  *  [adjacent_description]
00053  *      name= _ "heals"
00054 // *        name_inactive=null
00055  *      description=  _ "Heals:
00056 Allows the unit to heal adjacent friendly units at the beginning of each turn.
00057 
00058 A unit cared for by a healer may heal up to 4 HP per turn.
00059 A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
00060 // *        description_inactive=null
00061  *      icon="misc/..."
00062 // *        icon_inactive=null
00063  *  [/adjacent_description]
00064  *
00065  *  affect_self=yes
00066  *  [filter] // SUF
00067  *      ...
00068  *  [/filter]
00069  *  [filter_location]
00070  *      terrain=f
00071  *      tod=lawful
00072  *  [/filter_location]
00073  *  [filter_self] // SUF
00074  *      ...
00075  *  [/filter_self]
00076  *  [filter_adjacent] // SUF
00077  *      adjacent=n,ne,nw
00078  *      ...
00079  *  [/filter_adjacent]
00080  *  [filter_adjacent_location]
00081  *      adjacent=n,ne,nw
00082  *      ...
00083  *  [/filter_adjacent]
00084  *  [affect_adjacent]
00085  *      adjacent=n,ne,nw
00086  *      [filter] // SUF
00087  *          ...
00088  *      [/filter]
00089  *  [/affect_adjacent]
00090  *  [affect_adjacent]
00091  *      adjacent=s,se,sw
00092  *      [filter] // SUF
00093  *          ...
00094  *      [/filter]
00095  *  [/affect_adjacent]
00096  *
00097  * [/heals]
00098  *
00099  * ...
00100  * [/abilities]
00101  *
00102  */
00103 
00104 
00105 namespace unit_abilities {
00106 
00107 static bool affects_side(const config& cfg, const std::vector<team>& teams, size_t side, size_t other_side)
00108 {
00109     if (side == other_side)
00110         return utils::string_bool(cfg["affect_allies"], true);
00111     if (teams[side - 1].is_enemy(other_side))
00112         return utils::string_bool(cfg["affect_enemies"]);
00113     else
00114         return utils::string_bool(cfg["affect_allies"]);
00115 }
00116 
00117 }
00118 
00119 
00120 bool unit::get_ability_bool(const std::string& ability, const gamemap::location& loc) const
00121 {
00122     const config* abilities = cfg_.child("abilities");
00123     if(abilities) {
00124         const config::child_list& list = abilities->get_children(ability);
00125         for (config::child_list::const_iterator i = list.begin(),
00126              i_end = list.end(); i != i_end; ++i) {
00127             if (ability_active(ability, **i, loc) &&
00128                 ability_affects_self(ability, **i, loc))
00129                 return true;
00130         }
00131     }
00132 
00133     assert(units_ && teams_);
00134     gamemap::location adjacent[6];
00135     get_adjacent_tiles(loc,adjacent);
00136     for(int i = 0; i != 6; ++i) {
00137         const unit_map::const_iterator it = units_->find(adjacent[i]);
00138         if (it == units_->end() || it->second.incapacitated())
00139             continue;
00140         const config* adj_abilities = it->second.cfg_.child("abilities");
00141         if (!adj_abilities)
00142             continue;
00143         const config::child_list& list = adj_abilities->get_children(ability);
00144         for (config::child_list::const_iterator j = list.begin(),
00145              j_end = list.end(); j != j_end; ++j) {
00146             if (unit_abilities::affects_side(**j, *teams_, side(), it->second.side()) &&
00147                 it->second.ability_active(ability, **j, adjacent[i]) &&
00148                 ability_affects_adjacent(ability,  **j, i, loc))
00149                 return true;
00150         }
00151     }
00152 
00153 
00154     return false;
00155 }
00156 unit_ability_list unit::get_abilities(const std::string& ability, const gamemap::location& loc) const
00157 {
00158     unit_ability_list res;
00159 
00160     const config* abilities = cfg_.child("abilities");
00161     if(abilities) {
00162         const config::child_list& list = abilities->get_children(ability);
00163         for (config::child_list::const_iterator i = list.begin(),
00164              i_end = list.end(); i != i_end; ++i) {
00165             if (ability_active(ability, **i, loc) &&
00166                 ability_affects_self(ability, **i, loc))
00167                 res.cfgs.push_back(std::pair<config*, gamemap::location>
00168                     (*i, loc));
00169         }
00170     }
00171 
00172     assert(units_ != NULL);
00173     gamemap::location adjacent[6];
00174     get_adjacent_tiles(loc,adjacent);
00175     for(int i = 0; i != 6; ++i) {
00176         const unit_map::const_iterator it = units_->find(adjacent[i]);
00177         if (it == units_->end() || it->second.incapacitated())
00178             continue;
00179         const config* adj_abilities = it->second.cfg_.child("abilities");
00180         if (!adj_abilities)
00181             continue;
00182         const config::child_list& list = adj_abilities->get_children(ability);
00183         for (config::child_list::const_iterator j = list.begin(),
00184              j_end = list.end(); j != j_end; ++j) {
00185             if (unit_abilities::affects_side(**j, *teams_, side(), it->second.side()) &&
00186                 it->second.ability_active(ability, **j, adjacent[i]) &&
00187                 ability_affects_adjacent(ability, **j, i, loc))
00188                 res.cfgs.push_back(std::pair<config*, gamemap::location>
00189                     (*j, adjacent[i]));
00190         }
00191     }
00192 
00193 
00194     return res;
00195 }
00196 
00197 bool unit::abilities_affects_adjacent() const
00198 {
00199     if (cfg_.child("abilities")
00200         && cfg_.child("abilities")->child("affects_adjacent"))
00201         return true;
00202     return false;
00203 }
00204 
00205 std::vector<std::string> unit::unit_ability_tooltips() const
00206 {
00207     std::vector<std::string> res;
00208 
00209     const config* abilities = cfg_.child("abilities");
00210     if (!abilities) return res;
00211     const config::child_map& list_map = abilities->all_children();
00212     for (config::child_map::const_iterator i = list_map.begin(),
00213          i_end = list_map.end(); i != i_end; ++i) {
00214         for (config::child_list::const_iterator j = i->second.begin(),
00215              j_end = i->second.end(); j != j_end; ++j) {
00216             std::string const &name = (**j)["name"];
00217             if (!name.empty()) {
00218                 res.push_back(name);
00219                 res.push_back((**j)["description"]);
00220             }
00221         }
00222     }
00223     return res;
00224 }
00225 
00226 std::vector<std::string> unit::ability_tooltips(const gamemap::location& loc) const
00227 {
00228     std::vector<std::string> res;
00229 
00230     const config* abilities = cfg_.child("abilities");
00231     if(abilities) {
00232         const config::child_map& list_map = abilities->all_children();
00233         for (config::child_map::const_iterator i = list_map.begin(),
00234              i_end = list_map.end(); i != i_end; ++i) {
00235             for (config::child_list::const_iterator j = i->second.begin(),
00236                  j_end = i->second.end(); j != j_end; ++j) {
00237                 if (ability_active(i->first, **j, loc)) {
00238                     std::string const &name = (**j)["name"];
00239                     if (!name.empty()) {
00240                         res.push_back(name);
00241                         res.push_back((**j)["description"]);
00242                     }
00243                 } else {
00244                     std::string const &name = (**j)["name_inactive"];
00245                     if (!name.empty()) {
00246                         res.push_back(name);
00247                         res.push_back((**j)["description_inactive"]);
00248                     }
00249                 }
00250             }
00251         }
00252     }
00253     /*
00254     assert(units_ != NULL);
00255     gamemap::location adjacent[6];
00256     get_adjacent_tiles(loc,adjacent);
00257     for(int i = 0; i != 6; ++i) {
00258         const unit_map::const_iterator it = units_->find(adjacent[i]);
00259         if(it != units_->end() && 0 &&
00260         !it->second.incapacitated()) {
00261             const config* adj_abilities = it->second.cfg_.child("abilities");
00262             if(adj_abilities) {
00263                 const config::child_map& adj_list_map = adj_abilities->all_children();
00264                 for(config::child_map::const_iterator k = adj_list_map.begin(); k != adj_list_map.end(); ++k) {
00265                     for(config::child_list::const_iterator j = k->second.begin(); j != k->second.end(); ++j) {
00266                         if(unit_abilities::affects_side(**j,*teams_,side(),it->second.side())) {
00267                             const config* adj_desc = (*j)->child("adjacent_description");
00268                             if(ability_affects_adjacent(k->first,**j,i,adjacent[i])) {
00269                                 if(!adj_desc) {
00270                                     if(it->second.ability_active(k->first,**j,loc)) {
00271                                         if((**j)["name"] != "") {
00272                                             res.push_back((**j)["name"].str());
00273                                             res.push_back((**j)["description"].str());
00274                                         }
00275                                     } else {
00276                                         if((**j)["name_inactive"] != "") {
00277                                             res.push_back((**j)["name_inactive"].str());
00278                                             res.push_back((**j)["description_inactive"].str());
00279                                         }
00280                                     }
00281                                 } else {
00282                                     if(it->second.ability_active(k->first,**j,loc)) {
00283                                         if((*adj_desc)["name"] != "") {
00284                                             res.push_back((*adj_desc)["name"].str());
00285                                             res.push_back((*adj_desc)["description"].str());
00286                                         }
00287                                     } else {
00288                                         if((*adj_desc)["name_inactive"] != "") {
00289                                             res.push_back((*adj_desc)["name_inactive"].str());
00290                                             res.push_back((*adj_desc)["description_inacive"].str());
00291                                         }
00292                                     }
00293                                 }
00294                             }
00295                         }
00296                     }
00297                 }
00298             }
00299         }
00300     }
00301     */
00302 
00303     return res;
00304 }
00305 
00306 /*
00307  *
00308  * cfg: an ability WML structure
00309  *
00310  */
00311 static bool cache_illuminates(int &cache, std::string const &ability)
00312 {
00313     if (cache < 0)
00314         cache = (ability == "illuminates");
00315     return (cache != 0);
00316 }
00317 
00318 bool unit::ability_active(const std::string& ability,const config& cfg,const gamemap::location& loc) const
00319 {
00320     int illuminates = -1;
00321     assert(units_ && map_ && gamestatus_);
00322 
00323     if (const config* afilter = cfg.child("filter"))
00324         if (!matches_filter(afilter,loc, cache_illuminates(illuminates, ability)))
00325             return false;
00326 
00327     gamemap::location adjacent[6];
00328     get_adjacent_tiles(loc,adjacent);
00329     config::child_list::const_iterator i, i_end;
00330     const config::child_list& adj_filt = cfg.get_children("filter_adjacent");
00331     for (i = adj_filt.begin(), i_end = adj_filt.end(); i != i_end; ++i) {
00332         std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
00333         for (std::vector<std::string>::const_iterator j = dirs.begin(),
00334              j_end = dirs.end(); j != j_end; ++j) {
00335             gamemap::location::DIRECTION index =
00336                 gamemap::location::parse_direction(*j);
00337             if (index == gamemap::location::NDIRECTIONS)
00338                 continue;
00339             unit_map::const_iterator unit = units_->find(adjacent[index]);
00340             if (unit == units_->end())
00341                 return false;
00342             if (!unit->second.matches_filter(*i, unit->first,
00343                 cache_illuminates(illuminates, ability)))
00344                 return false;
00345         }
00346     }
00347     const config::child_list& adj_filt_loc = cfg.get_children("filter_adjacent_location");
00348     for (i = adj_filt_loc.begin(), i_end = adj_filt_loc.end(); i != i_end; ++i) {
00349         std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
00350         for (std::vector<std::string>::const_iterator j = dirs.begin(),
00351              j_end = dirs.end(); j != j_end; ++j) {
00352             gamemap::location::DIRECTION index = gamemap::location::parse_direction(*j);
00353             if (index == gamemap::location::NDIRECTIONS) {
00354                 continue;
00355             }
00356             /* GCC-3.3 doesn't accept vconfig(*i) in adj_filter */
00357             const vconfig& v = vconfig(*i);
00358             terrain_filter adj_filter(v, *map_, *gamestatus_, *units_);
00359             adj_filter.flatten(cache_illuminates(illuminates, ability));
00360             if(!adj_filter.match(adjacent[index])) {
00361                 return false;
00362             }
00363         }
00364     }
00365     return true;
00366 }
00367 /*
00368  *
00369  * cfg: an ability WML structure
00370  *
00371  */
00372 bool unit::ability_affects_adjacent(const std::string& ability, const config& cfg,int dir,const gamemap::location& loc) const
00373 {
00374     int illuminates = -1;
00375 
00376     assert(dir >=0 && dir <= 5);
00377     static const std::string adjacent_names[6] = {"n","ne","se","s","sw","nw"};
00378     const config::child_list& affect_adj = cfg.get_children("affect_adjacent");
00379     for (config::child_list::const_iterator i = affect_adj.begin(),
00380          i_end = affect_adj.end(); i != i_end; ++i) {
00381         std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
00382         if(std::find(dirs.begin(),dirs.end(),adjacent_names[dir]) != dirs.end()) {
00383             if (config const *filter = (*i)->child("filter")) {
00384                 if (matches_filter(filter, loc,
00385                     cache_illuminates(illuminates, ability)))
00386                     return true;
00387             } else
00388                 return true;
00389         }
00390     }
00391     return false;
00392 }
00393 /*
00394  *
00395  * cfg: an ability WML structure
00396  *
00397  */
00398 bool unit::ability_affects_self(const std::string& ability,const config& cfg,const gamemap::location& loc) const
00399 {
00400     int illuminates = -1;
00401     config const *filter = cfg.child("filter_self");
00402     bool affect_self = utils::string_bool(cfg["affect_self"], true);
00403     if (filter == NULL || !affect_self) return affect_self;
00404     return matches_filter(filter, loc,cache_illuminates(illuminates, ability));
00405 }
00406 
00407 bool unit::has_ability_type(const std::string& ability) const
00408 {
00409     const config* list = cfg_.child("abilities");
00410     if(list) {
00411         return !list->get_children(ability).empty();
00412     }
00413     return false;
00414 }
00415 
00416 
00417 bool unit_ability_list::empty() const
00418 {
00419     return cfgs.empty();
00420 }
00421 
00422 std::pair<int,gamemap::location> unit_ability_list::highest(const std::string& key, int def) const
00423 {
00424     if(cfgs.empty()) {
00425         return std::make_pair(def,gamemap::location::null_location);
00426     }
00427     gamemap::location best_loc = gamemap::location::null_location;
00428     int abs_max = -10000;
00429     int flat = -10000;
00430     int stack = 0;
00431     for (std::vector< std::pair<config*, gamemap::location> >::const_iterator i = cfgs.begin(),
00432          i_end = cfgs.end(); i != i_end; ++i) {
00433         std::string const &text = (*i->first)[key];
00434         int value = lexical_cast_default<int>(text);
00435         if (utils::string_bool((*i->first)["cumulative"])) {
00436             stack += value;
00437             if (value > abs_max) {
00438                 abs_max = value;
00439                 best_loc = i->second;
00440             }
00441         } else {
00442             int val = text.empty() ? def : value;
00443             flat = maximum<int>(flat,val);
00444             if (value > abs_max) {
00445                 abs_max = value;
00446                 best_loc = i->second;
00447             }
00448         }
00449     }
00450     return std::make_pair(flat + stack, best_loc);
00451 }
00452 std::pair<int,gamemap::location> unit_ability_list::lowest(const std::string& key, int def) const
00453 {
00454     if(cfgs.empty()) {
00455         return std::make_pair(def,gamemap::location::null_location);
00456     }
00457     gamemap::location best_loc = gamemap::location::null_location;
00458     int abs_max = 10000;
00459     int flat = 10000;
00460     int stack = 0;
00461     for (std::vector< std::pair<config*, gamemap::location> >::const_iterator i = cfgs.begin(),
00462          i_end = cfgs.end(); i != i_end; ++i) {
00463         std::string const &text = (*i->first)[key];
00464         int value = lexical_cast_default<int>(text);
00465         if (utils::string_bool((*i->first)["cumulative"])) {
00466             stack += value;
00467             if (value < abs_max) {
00468                 abs_max = value;
00469                 best_loc = i->second;
00470             }
00471         } else {
00472             int val = text.empty() ? def : value;
00473             flat = minimum<int>(flat,val);
00474             if (value < abs_max) {
00475                 abs_max = value;
00476                 best_loc = i->second;
00477             }
00478         }
00479     }
00480     return std::make_pair(flat + stack, best_loc);
00481 }
00482 
00483 
00484 
00485 /*
00486  *
00487  * [special]
00488  * [swarm]
00489  *  name= _ "swarm"
00490  *  name_inactive= _ ""
00491  *  description= _ ""
00492  *  description_inactive= _ ""
00493  *  cumulative=no
00494  *  apply_to=self  #self,opponent,defender,attacker
00495  *  #active_on=defend  .. offense
00496  *
00497  *  attacks_max=4
00498  *  attacks_min=2
00499  *
00500  *  [filter_self] // SUF
00501  *      ...
00502  *  [/filter_self]
00503  *  [filter_opponent] // SUF
00504  *  [filter_attacker] // SUF
00505  *  [filter_defender] // SUF
00506  *  [filter_adjacent] // SAUF
00507  *  [filter_adjacent_location] // SAUF + locs
00508  * [/swarm]
00509  * [/special]
00510  *
00511  */
00512 
00513 
00514 bool attack_type::get_special_bool(const std::string& special,bool force) const
00515 {
00516 //  log_scope("get_special_bool");
00517     const config* specials = cfg_.child("specials");
00518     if(specials) {
00519         const config::child_list& list = specials->get_children(special);
00520         if (!list.empty() && force) return true;
00521         for (config::child_list::const_iterator i = list.begin(),
00522              i_end = list.end(); i != i_end; ++i) {
00523             if (special_active(**i, true))
00524                 return true;
00525         }
00526     }
00527     if (force || !other_attack_) return false;
00528     specials = other_attack_->cfg_.child("specials");
00529     if (specials) {
00530         const config::child_list& list = specials->get_children(special);
00531         for (config::child_list::const_iterator i = list.begin(),
00532              i_end = list.end(); i != i_end; ++i) {
00533             if (other_attack_->special_active(**i, false))
00534                 return true;
00535         }
00536     }
00537     return false;
00538 }
00539 unit_ability_list attack_type::get_specials(const std::string& special) const
00540 {
00541 //  log_scope("get_specials");
00542     unit_ability_list res;
00543     const config* specials = cfg_.child("specials");
00544     if(specials) {
00545         const config::child_list& list = specials->get_children(special);
00546         for (config::child_list::const_iterator i = list.begin(),
00547              i_end = list.end(); i != i_end; ++i) {
00548             if (special_active(**i, true))
00549                 res.cfgs.push_back(std::pair<config*, gamemap::location>
00550                     (*i, attacker_ ? aloc_ : dloc_));
00551         }
00552     }
00553     if (!other_attack_) return res;
00554     specials = other_attack_->cfg_.child("specials");
00555     if (specials) {
00556         const config::child_list& list = specials->get_children(special);
00557         for (config::child_list::const_iterator i = list.begin(),
00558              i_end = list.end(); i != i_end; ++i) {
00559             if (other_attack_->special_active(**i, false))
00560                 res.cfgs.push_back(std::pair<config*, gamemap::location>
00561                     (*i, attacker_ ? dloc_ : aloc_));
00562         }
00563     }
00564     return res;
00565 }
00566 std::vector<std::string> attack_type::special_tooltips(bool force) const
00567 {
00568 //  log_scope("special_tooltips");
00569     std::vector<std::string> res;
00570     const config* specials = cfg_.child("specials");
00571     if (!specials) return res;
00572 
00573     const config::child_map& list_map = specials->all_children();
00574     for (config::child_map::const_iterator i = list_map.begin(),
00575          i_end = list_map.end(); i != i_end; ++i) {
00576         for (config::child_list::const_iterator j = i->second.begin(),
00577              j_end = i->second.end(); j != j_end; ++j) {
00578             if (force || special_active(**j, true)) {
00579                 std::string const &name = (**j)["name"];
00580                 if (!name.empty()) {
00581                     res.push_back(name);
00582                     res.push_back((**j)["description"]);
00583                 }
00584             } else {
00585                 std::string const &name = (**j)["name_inactive"];
00586                 if (!name.empty()) {
00587                     res.push_back(name);
00588                     res.push_back((**j)["description_inactive"]);
00589                 }
00590             }
00591         }
00592     }
00593     return res;
00594 }
00595 std::string attack_type::weapon_specials(bool force) const
00596 {
00597 //  log_scope("weapon_specials");
00598     std::string res;
00599     const config* specials = cfg_.child("specials");
00600     if (!specials) return res;
00601 
00602     const config::child_map& list_map = specials->all_children();
00603     for (config::child_map::const_iterator i = list_map.begin(),
00604          i_end = list_map.end(); i != i_end; ++i) {
00605         for (config::child_list::const_iterator j = i->second.begin(),
00606              j_end = i->second.end(); j != j_end; ++j) {
00607             char const *s = (force || special_active(**j, true, true))
00608                 ? "name" : "name_inactive";
00609             std::string const &name = (**j)[s];
00610 
00611             if (!name.empty()) {
00612                 if (!res.empty()) res += ',';
00613                 res += name;
00614             }
00615         }
00616     }
00617 
00618     return res;
00619 }
00620 
00621 
00622 
00623 /*
00624  *
00625  * cfg: a weapon special WML structure
00626  *
00627  */
00628 bool attack_type::special_active(const config& cfg,bool self,bool report) const
00629 {
00630 //  log_scope("special_active");
00631     assert(unitmap_ != NULL);
00632     unit_map::const_iterator att = unitmap_->find(aloc_);
00633     unit_map::const_iterator def = unitmap_->find(dloc_);
00634 
00635     if(self) {
00636         if(!special_affects_self(cfg)) {
00637             return false;
00638         }
00639     } else {
00640         if(!special_affects_opponent(cfg)) {
00641             return false;
00642         }
00643     }
00644 
00645     if(attacker_) {
00646         if (!report) {
00647             std::string const &active = cfg["active_on"];
00648             if (!active.empty() && active != "offense")
00649                 return false;
00650         }
00651         if (config const *filter_self = cfg.child("filter_self")) {
00652             if (att == unitmap_->end() ||
00653                 !att->second.matches_filter(filter_self, aloc_))
00654                 return false;
00655             if (config const *filter_weapon = filter_self->child("filter_weapon")) {
00656                 if (!matches_filter(*filter_weapon, true))
00657                     return false;
00658             }
00659         }
00660         if (config const *filter_opponent = cfg.child("filter_opponent")) {
00661             if (def == unitmap_->end() ||
00662                 !def->second.matches_filter(filter_opponent, dloc_))
00663                 return false;
00664             if (config const *filter_weapon = filter_opponent->child("filter_weapon")) {
00665                 if (!other_attack_ ||
00666                     !other_attack_->matches_filter(*filter_weapon, true))
00667                     return false;
00668             }
00669         }
00670     } else {
00671         if (!report) {
00672             std::string const &active = cfg["active_on"];
00673             if (!active.empty() && active != "defense")
00674                 return false;
00675         }
00676         if (config const *filter_self = cfg.child("filter_self")) {
00677             if (def == unitmap_->end() ||
00678                 !def->second.matches_filter(filter_self, dloc_))
00679                 return false;
00680             if (config const *filter_weapon = filter_self->child("filter_weapon")) {
00681                 if (!matches_filter(*filter_weapon, true))
00682                     return false;
00683             }
00684         }
00685         if (config const *filter_opponent = cfg.child("filter_opponent")) {
00686             if (att == unitmap_->end() ||
00687                 !att->second.matches_filter(filter_opponent, aloc_))
00688                 return false;
00689             if (config const *filter_weapon = filter_opponent->child("filter_weapon")) {
00690                 if (!other_attack_ ||
00691                     !other_attack_->matches_filter(*filter_weapon, true))
00692                     return false;
00693             }
00694         }
00695     }
00696     if (config const *filter_attacker = cfg.child("filter_attacker")) {
00697         if (att == unitmap_->end() ||
00698             !att->second.matches_filter(filter_attacker, aloc_))
00699             return false;
00700         if (config const *filter_weapon = filter_attacker->child("filter_weapon")) {
00701             if (attacker_) {
00702                 if (!matches_filter(*filter_weapon, true))
00703                     return false;
00704             } else {
00705                 if (!other_attack_ ||
00706                     !other_attack_->matches_filter(*filter_weapon, true))
00707                     return false;
00708             }
00709         }
00710     }
00711     if (config const *filter_defender = cfg.child("filter_defender")) {
00712         if (def == unitmap_->end() ||
00713             !def->second.matches_filter(filter_defender, dloc_))
00714             return false;
00715         if (config const *filter_weapon = filter_defender->child("filter_weapon")) {
00716             if (!attacker_) {
00717                 if(!matches_filter(*filter_weapon, true))
00718                     return false;
00719             } else {
00720                 if (!other_attack_ ||
00721                     !other_attack_->matches_filter(*filter_weapon, true))
00722                     return false;
00723             }
00724         }
00725     }
00726     gamemap::location adjacent[6];
00727     if(attacker_) {
00728         get_adjacent_tiles(aloc_,adjacent);
00729     } else {
00730         get_adjacent_tiles(dloc_,adjacent);
00731     }
00732     const config::child_list& adj_filt = cfg.get_children("filter_adjacent");
00733     config::child_list::const_iterator i, i_end;
00734     for (i = adj_filt.begin(), i_end = adj_filt.end(); i != i_end; ++i) {
00735         std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
00736         for (std::vector<std::string>::const_iterator j = dirs.begin(),
00737              j_end = dirs.end(); j != j_end; ++j) {
00738             gamemap::location::DIRECTION index =
00739                 gamemap::location::parse_direction(*j);
00740             if (index == gamemap::location::NDIRECTIONS)
00741                 continue;
00742             unit_map::const_iterator unit = unitmap_->find(adjacent[index]);
00743             if (unit == unitmap_->end() ||
00744                 !unit->second.matches_filter(*i, unit->first))
00745                 return false;
00746         }
00747     }
00748     assert(map_ && game_status_);
00749     const config::child_list& adj_filt_loc = cfg.get_children("filter_adjacent_location");
00750     for (i = adj_filt_loc.begin(), i_end = adj_filt_loc.end(); i != i_end; ++i) {
00751         std::vector<std::string> dirs = utils::split((**i)["adjacent"]);
00752         for (std::vector<std::string>::const_iterator j = dirs.begin(),
00753              j_end = dirs.end(); j != j_end; ++j) {
00754             gamemap::location::DIRECTION index =
00755                 gamemap::location::parse_direction(*j);
00756             if (index == gamemap::location::NDIRECTIONS)
00757                 continue;
00758             /* GCC-3.3 doesn't accept vconfig(*i) in adj_filter */
00759             const vconfig& v = vconfig(*i);
00760             terrain_filter adj_filter(v, *map_, *game_status_, *unitmap_);
00761             if(!adj_filter.match(adjacent[index])) {
00762                 return false;
00763             }
00764         }
00765     }
00766     return true;
00767 }
00768 /*
00769  *
00770  * cfg: a weapon special WML structure
00771  *
00772  */
00773 bool attack_type::special_affects_opponent(const config& cfg) const
00774 {
00775 //  log_scope("special_affects_opponent");
00776     std::string const &apply_to = cfg["apply_to"];
00777     if (apply_to.empty())
00778         return false;
00779     if (apply_to == "both")
00780         return true;
00781     if (apply_to == "opponent")
00782         return true;
00783     if (attacker_ && apply_to == "defender")
00784         return true;
00785     if (!attacker_ && apply_to == "attacker")
00786         return true;
00787     return false;
00788 }
00789 /*
00790  *
00791  * cfg: a weapon special WML structure
00792  *
00793  */
00794 bool attack_type::special_affects_self(const config& cfg) const
00795 {
00796 //  log_scope("special_affects_self");
00797     std::string const &apply_to = cfg["apply_to"];
00798     if (apply_to.empty())
00799         return true;
00800     if (apply_to == "both")
00801         return true;
00802     if (apply_to == "self")
00803         return true;
00804     if (attacker_ && apply_to == "attacker")
00805         return true;
00806     if (!attacker_ && apply_to == "defender")
00807         return true;
00808     return false;
00809 }
00810 void attack_type::set_specials_context(const gamemap::location& aloc,const gamemap::location& dloc,
00811                               const unit_map* unitmap,
00812                               const gamemap* map, const gamestatus* game_status,
00813                               const std::vector<team>* teams, bool attacker,const attack_type* other_attack) const
00814 {
00815     aloc_ = aloc;
00816     dloc_ = dloc;
00817     unitmap_ = unitmap;
00818     map_ = map;
00819     game_status_ = game_status;
00820     teams_ = teams;
00821     attacker_ = attacker;
00822     other_attack_ = other_attack;
00823 }
00824 
00825 void attack_type::set_specials_context(const gamemap::location& loc, const gamemap::location& dloc, const unit& un, bool attacker) const
00826 {
00827     aloc_ = loc;
00828     dloc_ = dloc;
00829     unitmap_ = un.units_;
00830     map_ = un.map_;
00831     game_status_ = un.gamestatus_;
00832     teams_ = un.teams_;
00833     attacker_ = attacker;
00834     other_attack_ = NULL;
00835 }
00836 
00837 
00838 
00839 
00840 namespace unit_abilities
00841 {
00842 
00843 
00844 individual_effect::individual_effect(value_modifier t,int val,config* abil,const gamemap::location& l)
00845 {
00846     set(t,val,abil,l);
00847 }
00848 void individual_effect::set(value_modifier t,int val,config* abil,const gamemap::location& l)
00849 {
00850     type=t;
00851     value=val;
00852     ability=abil;
00853     loc=l;
00854 }
00855 
00856 
00857 
00858 effect::effect(const unit_ability_list& list, int def, bool backstab)
00859 {
00860 
00861     int value_set = def; bool value_is_set = false;
00862     std::map<std::string,individual_effect> values_add;
00863     std::map<std::string,individual_effect> values_mul;
00864 
00865     individual_effect set_effect;
00866 
00867     for (std::vector< std::pair<config*, gamemap::location> >::const_iterator
00868          i = list.cfgs.begin(), i_end = list.cfgs.end(); i != i_end; ++i) {
00869         const config& cfg = (*i->first);
00870         std::string const &effect_id = cfg[cfg["id"].empty() ? "name" : "id"];
00871 
00872         if (!backstab && utils::string_bool(cfg["backstab"]))
00873             continue;
00874 
00875         if (config const *apply_filter = cfg.child("filter_base_value")) {
00876             std::string const &cond_eq = (*apply_filter)["equals"];
00877             if (!cond_eq.empty() && lexical_cast_default<int>(cond_eq) != def)
00878                 continue;
00879             std::string const &cond_ne = (*apply_filter)["not_equals"];
00880             if (!cond_ne.empty() && lexical_cast_default<int>(cond_ne) == def)
00881                 continue;
00882             std::string const &cond_lt = (*apply_filter)["less_than"];
00883             if (!cond_lt.empty() && lexical_cast_default<int>(cond_lt) <= def)
00884                 continue;
00885             std::string const &cond_gt = (*apply_filter)["greater_than"];
00886             if (!cond_gt.empty() && lexical_cast_default<int>(cond_gt) >= def)
00887                 continue;
00888             std::string const &cond_ge = (*apply_filter)["greater_than_equal_to"];
00889             if (!cond_ge.empty() && lexical_cast_default<int>(cond_ge) > def)
00890                 continue;
00891             std::string const &cond_le = (*apply_filter)["less_than_equal_to"];
00892             if (!cond_le.empty() && lexical_cast_default<int>(cond_le) < def)
00893                 continue;
00894         }
00895         std::string const &cfg_value = cfg["value"];
00896         if (!cfg_value.empty()) {
00897             int value = lexical_cast_default<int>(cfg_value);
00898             bool cumulative = utils::string_bool(cfg["cumulative"]);
00899             if (!value_is_set && !cumulative) {
00900                 value_set = value;
00901                 set_effect.set(SET, value, i->first, i->second);
00902             } else {
00903                 if (cumulative) value_set = maximum<int>(value_set, def);
00904                 if (value > value_set) {
00905                     value_set = value;
00906                     set_effect.set(SET, value, i->first, i->second);
00907                 }
00908             }
00909             value_is_set = true;
00910         }
00911 
00912         std::string const &cfg_add = cfg["add"];
00913         if (!cfg_add.empty()) {
00914             int add = lexical_cast_default<int>(cfg_add);
00915             std::map<std::string,individual_effect>::iterator add_effect = values_add.find(effect_id);
00916             if(add_effect == values_add.end() || add > add_effect->second.value) {
00917                 values_add[effect_id].set(ADD,add,i->first,i->second);
00918             }
00919         }
00920         std::string const &cfg_mul = cfg["multiply"];
00921         if (!cfg_mul.empty()) {
00922             int multiply = int(lexical_cast_default<float>(cfg_mul) * 100);
00923             std::map<std::string,individual_effect>::iterator mul_effect = values_mul.find(effect_id);
00924             if(mul_effect == values_mul.end() || multiply > mul_effect->second.value) {
00925                 values_mul[effect_id].set(MUL,multiply,i->first,i->second);
00926             }
00927         }
00928     }
00929 
00930     if(value_is_set && set_effect.type != NOT_USED) {
00931         effect_list_.push_back(set_effect);
00932     }
00933 
00934     int multiplier = 1;
00935     int divisor = 1;
00936     std::map<std::string,individual_effect>::const_iterator e, e_end;
00937     for (e = values_mul.begin(), e_end = values_mul.end(); e != e_end; ++e) {
00938         multiplier *= e->second.value;
00939         divisor *= 100;
00940         effect_list_.push_back(e->second);
00941     }
00942     int addition = 0;
00943     for (e = values_add.begin(), e_end = values_add.end(); e != e_end; ++e) {
00944         addition += e->second.value;
00945         effect_list_.push_back(e->second);
00946     }
00947 
00948     composite_value_ = (value_set + addition) * multiplier / divisor;
00949 }
00950 
00951 } // end namespace unit_abilities
00952 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs