00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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 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
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 return res;
00304 }
00305
00306
00307
00308
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
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
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
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
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 bool attack_type::get_special_bool(const std::string& special,bool force) const
00515 {
00516
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
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
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
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
00626
00627
00628 bool attack_type::special_active(const config& cfg,bool self,bool report) const
00629 {
00630
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
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
00771
00772
00773 bool attack_type::special_affects_opponent(const config& cfg) const
00774 {
00775
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
00792
00793
00794 bool attack_type::special_affects_self(const config& cfg) const
00795 {
00796
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 }
00952