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