Skip to content

Commit

Permalink
add student variable to ability formulas
Browse files Browse the repository at this point in the history
This can be different from 'other' in case of a
an ability that effects the enemy, where 'other'
should be the unit that receives the effect
(here: the enemy), studend is the unit that
matches the [affect_adjacent], and the unnamed
unit is the unit that has the ability.

I think it'd be nice to have even more variables
available so that for example the effect could
depend on the opponent even when it doesn't
effect the opponent.
  • Loading branch information
gfgtdf committed Apr 18, 2020
1 parent 2ea9433 commit d9b4ae1
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 55 deletions.
4 changes: 2 additions & 2 deletions src/actions/attack.cpp
Expand Up @@ -163,7 +163,7 @@ battle_context_unit_stats::battle_context_unit_stats(const unit& u,
opp.undead_variation() != "null" && !resources::gameboard->map().is_village(opp_loc);

if(plagues) {
plague_type = (*plague_specials.front().first)["type"].str();
plague_type = (*plague_specials.front().ability_cfg)["type"].str();

if(plague_type.empty()) {
plague_type = u.type().base_id();
Expand Down Expand Up @@ -313,7 +313,7 @@ battle_context_unit_stats::battle_context_unit_stats(const unit_type* u_type,
opp_type->undead_variation() != "null";

if(plagues) {
plague_type = (*plague_specials.front().first)["type"].str();
plague_type = (*plague_specials.front().ability_cfg)["type"].str();
if(plague_type.empty()) {
plague_type = u_type->base_id();
}
Expand Down
8 changes: 4 additions & 4 deletions src/actions/heal.cpp
Expand Up @@ -97,7 +97,7 @@ namespace {
// Regeneration?
for (const unit_ability & regen : patient.get_abilities("regenerate"))
{
curing = std::max(curing, poison_status((*regen.first)["poison"]));
curing = std::max(curing, poison_status((*regen.ability_cfg)["poison"]));
if ( curing == POISON_CURE )
// This is as good as it gets.
return POISON_CURE;
Expand All @@ -109,14 +109,14 @@ namespace {
// Assumed: curing is not POISON_CURE at the start of any iteration.
for (const unit_ability & heal : patient.get_abilities("heals"))
{
POISON_STATUS this_cure = poison_status((*heal.first)["poison"]);
POISON_STATUS this_cure = poison_status((*heal.ability_cfg)["poison"]);
if ( this_cure <= curing )
// We already recorded this level of curing.
continue;

// NOTE: At this point, this_cure will be *_SLOW or *_CURE.

unit_map::iterator cure_it = units.find(heal.second);
unit_map::iterator cure_it = units.find(heal.teacher_loc);
assert(cure_it != units.end());
const int cure_side = cure_it->side();

Expand Down Expand Up @@ -201,7 +201,7 @@ namespace {
// Remove all healers not on this side (since they do not heal now).
unit_ability_list::iterator heal_it = heal_list.begin();
while ( heal_it != heal_list.end() ) {
unit_map::iterator healer = units.find(heal_it->second);
unit_map::iterator healer = units.find(heal_it->teacher_loc);
assert(healer != units.end());

if ( healer->side() != side )
Expand Down
2 changes: 1 addition & 1 deletion src/actions/move.cpp
Expand Up @@ -850,7 +850,7 @@ namespace { // Private helpers for move_unit()
{
for(const unit_ability &hide : ambusher.get_abilities("hides"))
{
const std::string & ambush_string = (*hide.first)["alert"].str();
const std::string & ambush_string = (*hide.ability_cfg)["alert"].str();
if (!ambush_string.empty()) {
return ambush_string;
}
Expand Down
4 changes: 2 additions & 2 deletions src/pathfind/teleport.cpp
Expand Up @@ -264,9 +264,9 @@ const teleport_map get_teleport_locations(const unit &u,
std::vector<teleport_group> groups;

for (const unit_ability & teleport : u.get_abilities("teleport")) {
const int tunnel_count = (teleport.first)->child_count("tunnel");
const int tunnel_count = (teleport.ability_cfg)->child_count("tunnel");
for(int i = 0; i < tunnel_count; ++i) {
config teleport_group_cfg = (teleport.first)->child("tunnel", i);
config teleport_group_cfg = (teleport.ability_cfg)->child("tunnel", i);
groups.emplace_back(vconfig(teleport_group_cfg, true), false);
}
}
Expand Down
62 changes: 32 additions & 30 deletions src/units/abilities.cpp
Expand Up @@ -189,7 +189,7 @@ unit_ability_list unit::get_abilities(const std::string& tag_name, const map_loc
if(ability_active(tag_name, i, loc)
&& ability_affects_self(tag_name, i, loc))
{
res.emplace_back(&i, loc);
res.emplace_back(&i, loc, loc);
}
}

Expand All @@ -214,7 +214,7 @@ unit_ability_list unit::get_abilities(const std::string& tag_name, const map_loc
&& it->ability_active(tag_name, j, adjacent[i])
&& ability_affects_adjacent(tag_name, j, i, loc, *it))
{
res.emplace_back(&j, adjacent[i]);
res.emplace_back(&j, loc, adjacent[i]);
}
}
}
Expand All @@ -227,7 +227,7 @@ unit_ability_list unit::get_abilities_weapons(const std::string& tag_name, const
{
unit_ability_list res = get_abilities(tag_name, loc);
for(unit_ability_list::iterator i = res.begin(); i != res.end();) {
if((!ability_affects_weapon(*i->first, weapon, false) || !ability_affects_weapon(*i->first, opp_weapon, true))) {
if((!ability_affects_weapon(*i->ability_cfg, weapon, false) || !ability_affects_weapon(*i->ability_cfg, opp_weapon, true))) {
i = res.erase(i);
} else {
++i;
Expand Down Expand Up @@ -504,23 +504,25 @@ get_ability_value_visitor<T, TFuncFormula> make_get_ability_value_visitor(T def,
return get_ability_value_visitor<T, TFuncFormula>(def, formula_handler);
}
template<typename T, typename TFuncFormula>
T get_single_ability_value(const config::attribute_value& v, T def, const map_location& sender_loc, const map_location& receiver_loc, const TFuncFormula& formula_handler)
T get_single_ability_value(const config::attribute_value& v, T def, const unit_ability& ability_info, const map_location& receiver_loc, const TFuncFormula& formula_handler)
{
return v.apply_visitor(make_get_ability_value_visitor(def, [&](const std::string& s) {

try {
assert(display::get_singleton());
const unit_map& units = display::get_singleton()->get_units();

auto u_itor = units.find(sender_loc);
auto u_itor = units.find(ability_info.teacher_loc);

if(u_itor == units.end()) {
return def;
}
wfl::map_formula_callable callable(std::make_shared<wfl::unit_callable>(*u_itor));
u_itor = units.find(receiver_loc);
if(u_itor != units.end()) {
callable.add("other", wfl::variant(std::make_shared<wfl::unit_callable>(*u_itor)));
if (auto uptr = units.find_unit_ptr(ability_info.student_loc)) {
callable.add("student", wfl::variant(std::make_shared<wfl::unit_callable>(*uptr)));
}
if (auto uptr = units.find_unit_ptr(receiver_loc)) {
callable.add("other", wfl::variant(std::make_shared<wfl::unit_callable>(*uptr)));
}
return formula_handler(wfl::formula(s, new wfl::gamestate_function_symbol_table), callable);
} catch(const wfl::formula_error& e) {
Expand All @@ -546,21 +548,21 @@ std::pair<int,map_location> unit_ability_list::get_extremum(const std::string& k
int stack = 0;
for (const unit_ability& p : cfgs_)
{
int value = get_single_ability_value((*p.first)[key], def, p.second, loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
int value = get_single_ability_value((*p.ability_cfg)[key], def, p, loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
return formula.evaluate(callable).as_int();
});

if ((*p.first)["cumulative"].to_bool()) {
if ((*p.ability_cfg)["cumulative"].to_bool()) {
stack += value;
if (value < 0) value = -value;
if (only_cumulative && !comp(value, abs_max)) {
abs_max = value;
best_loc = p.second;
best_loc = p.teacher_loc;
}
} else if (only_cumulative || comp(flat, value)) {
only_cumulative = false;
flat = value;
best_loc = p.second;
best_loc = p.teacher_loc;
}
}
return std::make_pair(flat + stack, best_loc);
Expand Down Expand Up @@ -761,7 +763,7 @@ unit_ability_list attack_type::get_specials(const std::string& special) const

for(const config& i : specials_.child_range(special)) {
if(special_active(i, AFFECT_SELF, special)) {
res.emplace_back(&i, loc);
res.emplace_back(&i, loc, loc);
}
}

Expand All @@ -771,7 +773,7 @@ unit_ability_list attack_type::get_specials(const std::string& special) const

for(const config& i : other_attack_->specials_.child_range(special)) {
if(other_attack_->special_active(i, AFFECT_OTHER, special)) {
res.emplace_back(&i, other_loc_);
res.emplace_back(&i, other_loc_, other_loc_);
}
}
return res;
Expand Down Expand Up @@ -1099,7 +1101,7 @@ unit_ability_list attack_type::list_ability(const std::string& ability) const
if(self_) {
abil_list.append((*self_).get_abilities(ability, self_loc_));
for(unit_ability_list::iterator i = abil_list.begin(); i != abil_list.end();) {
if(!special_active(*i->first, AFFECT_SELF, ability, true, "filter_student")) {
if(!special_active(*i->ability_cfg, AFFECT_SELF, ability, true, "filter_student")) {
i = abil_list.erase(i);
} else {
++i;
Expand All @@ -1110,7 +1112,7 @@ unit_ability_list attack_type::list_ability(const std::string& ability) const
if(other_) {
abil_other_list.append((*other_).get_abilities(ability, other_loc_));
for(unit_ability_list::iterator i = abil_other_list.begin(); i != abil_other_list.end();) {
if(!other_attack_->special_active(*i->first, AFFECT_OTHER, ability, true, "filter_student")) {
if(!other_attack_->special_active(*i->ability_cfg, AFFECT_OTHER, ability, true, "filter_student")) {
i = abil_other_list.erase(i);
} else {
++i;
Expand Down Expand Up @@ -1343,7 +1345,7 @@ effect::effect(const unit_ability_list& list, int def, bool backstab) :
individual_effect set_effect_min;

for (const unit_ability & ability : list) {
const config& cfg = *ability.first;
const config& cfg = *ability.ability_cfg;
const std::string& effect_id = cfg[cfg["id"].empty() ? "name" : "id"];

if (!cfg["backstab"].blank()) {
Expand All @@ -1356,59 +1358,59 @@ effect::effect(const unit_ability_list& list, int def, bool backstab) :
continue;

if (const config::attribute_value *v = cfg.get("value")) {
int value = get_single_ability_value(*v, def, ability.second, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
int value = get_single_ability_value(*v, def, ability, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
callable.add("base_value", wfl::variant(def));
return formula.evaluate(callable).as_int();
});

int value_cum = cfg["cumulative"].to_bool() ? std::max(def, value) : value;
assert((set_effect_min.type != NOT_USED) == (set_effect_max.type != NOT_USED));
if(set_effect_min.type == NOT_USED) {
set_effect_min.set(SET, value_cum, ability.first, ability.second);
set_effect_max.set(SET, value_cum, ability.first, ability.second);
set_effect_min.set(SET, value_cum, ability.ability_cfg, ability.teacher_loc);
set_effect_max.set(SET, value_cum, ability.ability_cfg, ability.teacher_loc);
}
else {
if(value_cum > set_effect_max.value) {
set_effect_max.set(SET, value_cum, ability.first, ability.second);
set_effect_max.set(SET, value_cum, ability.ability_cfg, ability.teacher_loc);
}
if(value_cum < set_effect_min.value) {
set_effect_min.set(SET, value_cum, ability.first, ability.second);
set_effect_min.set(SET, value_cum, ability.ability_cfg, ability.teacher_loc);
}
}
}

if (const config::attribute_value *v = cfg.get("add")) {
int add = get_single_ability_value(*v, def, ability.second, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
int add = get_single_ability_value(*v, def, ability, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
callable.add("base_value", wfl::variant(def));
return formula.evaluate(callable).as_int();
});
std::map<std::string,individual_effect>::iterator add_effect = values_add.find(effect_id);
if(add_effect == values_add.end() || add > add_effect->second.value) {
values_add[effect_id].set(ADD, add, ability.first, ability.second);
values_add[effect_id].set(ADD, add, ability.ability_cfg, ability.teacher_loc);
}
}
if (const config::attribute_value *v = cfg.get("sub")) {
int sub = - get_single_ability_value(*v, def, ability.second, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
int sub = - get_single_ability_value(*v, def, ability, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
callable.add("base_value", wfl::variant(def));
return formula.evaluate(callable).as_int();
});
std::map<std::string,individual_effect>::iterator sub_effect = values_add.find(effect_id);
if(sub_effect == values_add.end() || sub < sub_effect->second.value) {
values_add[effect_id].set(ADD, sub, ability.first, ability.second);
values_add[effect_id].set(ADD, sub, ability.ability_cfg, ability.teacher_loc);
}
}
if (const config::attribute_value *v = cfg.get("multiply")) {
int multiply = static_cast<int>(get_single_ability_value(*v, static_cast<double>(def), ability.second, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
int multiply = static_cast<int>(get_single_ability_value(*v, static_cast<double>(def), ability, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
callable.add("base_value", wfl::variant(def));
return formula.evaluate(callable).as_decimal() / 1000.0 ;
}) * 100);
std::map<std::string,individual_effect>::iterator mul_effect = values_mul.find(effect_id);
if(mul_effect == values_mul.end() || multiply > mul_effect->second.value) {
values_mul[effect_id].set(MUL, multiply, ability.first, ability.second);
values_mul[effect_id].set(MUL, multiply, ability.ability_cfg, ability.teacher_loc);
}
}
if (const config::attribute_value *v = cfg.get("divide")) {
int divide = static_cast<int>(get_single_ability_value(*v, static_cast<double>(def), ability.second, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
int divide = static_cast<int>(get_single_ability_value(*v, static_cast<double>(def), ability, list.loc(),[&](const wfl::formula& formula, wfl::map_formula_callable& callable) {
callable.add("base_value", wfl::variant(def));
return formula.evaluate(callable).as_decimal() / 1000.0 ;
}) * 100);
Expand All @@ -1419,7 +1421,7 @@ effect::effect(const unit_ability_list& list, int def, bool backstab) :
else {
std::map<std::string,individual_effect>::iterator div_effect = values_div.find(effect_id);
if(div_effect == values_div.end() || divide > div_effect->second.value) {
values_div[effect_id].set(DIV, divide, ability.first, ability.second);
values_div[effect_id].set(DIV, divide, ability.ability_cfg, ability.teacher_loc);
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/units/map.hpp
Expand Up @@ -384,6 +384,20 @@ class unit_map
return const_cast<unit_map*>(this)->find(id);
}

template<typename T>
unit_ptr find_unit_ptr(const T& val)
{
auto res = find(val);
return res != end() ? res.get_shared_ptr() : unit_ptr();
}

template<typename T>
unit_const_ptr find_unit_ptr(const T& val) const
{
auto res = find(val);
return res != end() ? res.get_shared_ptr() : unit_ptr();
}

unit_iterator find_leader(int side);

const_unit_iterator find_leader(int side) const
Expand Down
2 changes: 1 addition & 1 deletion src/units/types.cpp
Expand Up @@ -796,7 +796,7 @@ int unit_type::resistance_against(const std::string& damage_name, bool attacker)
continue;
}

resistance_abilities.emplace_back(&cfg, map_location::null_location());
resistance_abilities.emplace_back(&cfg, map_location::null_location(), map_location::null_location());
}
}

Expand Down
24 changes: 12 additions & 12 deletions src/units/udisplay.cpp
Expand Up @@ -647,35 +647,35 @@ void unit_attack(display * disp, game_board & board,
animator.add_animation(&defender, defender_anim, def->get_location(), true, text, {255, 0, 0});

for(const unit_ability& ability : attacker.get_abilities_weapons("leadership", attack.shared_from_this(), secondary_attack)) {
if(ability.second == a) {
if(ability.teacher_loc == a) {
continue;
}

if(ability.second == b) {
if(ability.teacher_loc == b) {
continue;
}

unit_map::const_iterator leader = board.units().find(ability.second);
unit_map::const_iterator leader = board.units().find(ability.teacher_loc);
assert(leader.valid());
leader->set_facing(ability.second.get_relative_dir(a));
animator.add_animation(&*leader, "leading", ability.second,
leader->set_facing(ability.teacher_loc.get_relative_dir(a));
animator.add_animation(&*leader, "leading", ability.teacher_loc,
att->get_location(), damage, true, "", {0,0,0},
hit_type, attack.shared_from_this(), secondary_attack, swing);
}

for(const unit_ability& ability : defender.get_abilities_weapons("resistance", attack.shared_from_this(), secondary_attack)) {
if(ability.second == a) {
if(ability.teacher_loc == a) {
continue;
}

if(ability.second == b) {
if(ability.teacher_loc == b) {
continue;
}

unit_map::const_iterator helper = board.units().find(ability.second);
unit_map::const_iterator helper = board.units().find(ability.teacher_loc);
assert(helper.valid());
helper->set_facing(ability.second.get_relative_dir(b));
animator.add_animation(&*helper, "resistance", ability.second,
helper->set_facing(ability.teacher_loc.get_relative_dir(b));
animator.add_animation(&*helper, "resistance", ability.teacher_loc,
def->get_location(), damage, true, "", {0,0,0},
hit_type, attack.shared_from_this(), secondary_attack, swing);
}
Expand Down Expand Up @@ -715,15 +715,15 @@ void reset_helpers(const unit *attacker,const unit *defender)
const unit_map& units = disp->get_units();
if(attacker) {
for(const unit_ability& ability : attacker->get_abilities("leadership")) {
unit_map::const_iterator leader = units.find(ability.second);
unit_map::const_iterator leader = units.find(ability.teacher_loc);
assert(leader != units.end());
leader->anim_comp().set_standing();
}
}

if(defender) {
for(const unit_ability& ability : defender->get_abilities("resistance")) {
unit_map::const_iterator helper = units.find(ability.second);
unit_map::const_iterator helper = units.find(ability.teacher_loc);
assert(helper != units.end());
helper->anim_comp().set_standing();
}
Expand Down
2 changes: 1 addition & 1 deletion src/units/unit.cpp
Expand Up @@ -1695,7 +1695,7 @@ int unit::resistance_against(const std::string& damage_name,bool attacker,const

unit_ability_list resistance_abilities = get_abilities_weapons("resistance",loc, weapon, opp_weapon);
for(unit_ability_list::iterator i = resistance_abilities.begin(); i != resistance_abilities.end();) {
if(!resistance_filter_matches(*i->first, attacker, damage_name, 100-res)) {
if(!resistance_filter_matches(*i->ability_cfg, attacker, damage_name, 100-res)) {
i = resistance_abilities.erase(i);
} else {
++i;
Expand Down

0 comments on commit d9b4ae1

Please sign in to comment.