add a my_attacks FAI variable with all possible attacks patch by benetnash

This commit is contained in:
Jérémy Rosen 2009-04-11 14:35:15 +00:00
parent 6fc2fb1504
commit 9f39e5fe7c
3 changed files with 72 additions and 0 deletions

View file

@ -35,6 +35,7 @@ Version 1.7.0-svn:
are not incapacitated (for example, it now ignores stoned units )
* Implemented FR #13348: added timeofday_modifier function to formula AI
* Added attacks_left attribute to unit callable
* New variable: my_attacks with all possible attacks
* Graphics:
* New type of animation : "recruiting" used by leaders when recruiting
units

View file

@ -803,6 +803,11 @@
[entry]
name = "J.R. Blain (Cowboy)"
[/entry]
[entry]
name = "Jan Polak (benetnash)"
comment = "Formula AI contributions"
email = "benetnash_AT_icpnet.pl"
[/entry]
[entry]
name = "Jan Zvánovec (jaz)"
[/entry]

View file

@ -875,6 +875,67 @@ public:
int defender_weapon() const { return bc_.get_defender_stats().attack_num; }
};
class attack_map_callable : public formula_callable {
public:
typedef std::multimap<map_location, map_location> move_map;
attack_map_callable(const formula_ai& ai, const move_map& srcdst, const unit_map& units)
: srcdst_(srcdst), units_(units), ai_(ai)
{}
private:
const move_map& srcdst_;
const unit_map& units_;
const formula_ai& ai_;
variant get_value(const std::string& key) const {
if(key == "attacks") {
std::vector<variant> vars;
for(move_map::const_iterator i = srcdst_.begin(); i != srcdst_.end(); ++i) {
/* for each possible move check all adjacent tiles for enemies */
if(units_.count(i->second) == 0) {
collect_possible_attacks(vars, i->first, i->second);
}
}
/* special case, when unit moved toward enemy and can only attack */
for(unit_map::const_iterator i = ai_.get_info().units.begin(); i != ai_.get_info().units.end(); ++i) {
if((i->second.side() == ai_.get_side()) && (i->second.attacks_left() > 0)) {
collect_possible_attacks(vars, i->first, i->first);
}
}
return variant(&vars);
} else {
return variant();
}
}
void get_inputs(std::vector<game_logic::formula_input>* inputs) const {
inputs->push_back(game_logic::formula_input("attacks", game_logic::FORMULA_READ_ONLY));
}
/* add to vars all attacks on enemy units around <attack_position> tile. attacker_location is tile where unit is currently standing. It's moved to attack_position first and then performs attack.*/
void collect_possible_attacks(std::vector<variant>& vars, map_location attacker_location, map_location attack_position) const {
map_location adj[6];
get_adjacent_tiles(attack_position, adj);
for(int n = 0; n != 6; ++n) {
/* if adjacent tile is outside the board */
if (! ai_.get_info().map.on_board(adj[n]))
continue;
unit_map::const_iterator unit = units_.find(adj[n]);
/* if tile is empty */
if (unit == units_.end())
continue;
/* if tile is occupied by friendly or stoned/invisible unit */
if (! ai_.current_team().is_enemy(unit->second.side()) ||
unit->second.incapacitated() ||
unit->second.invisible(unit->first, units_, ai_.get_info().teams) )
continue;
/* add attacks with default weapon */
attack_callable* item = new attack_callable(ai_, attacker_location, attack_position, adj[n], -1);
vars.push_back(variant(item));
}
}
};
class attack_function : public function_expression {
public:
explicit attack_function(const args_list& args, const formula_ai& ai)
@ -2390,6 +2451,10 @@ variant formula_ai::get_value(const std::string& key) const
prepare_move();
return variant(new move_map_callable(srcdst_, dstsrc_, get_info().units));
} else if(key == "my_attacks")
{
prepare_move();
return variant(new attack_map_callable(*this, srcdst_, get_info().units));
} else if(key == "enemy_moves")
{
prepare_move();
@ -2452,6 +2517,7 @@ void formula_ai::get_inputs(std::vector<formula_input>* inputs) const
inputs->push_back(game_logic::formula_input("allies", FORMULA_READ_ONLY));
inputs->push_back(game_logic::formula_input("enemies", FORMULA_READ_ONLY));
inputs->push_back(game_logic::formula_input("my_moves", FORMULA_READ_ONLY));
inputs->push_back(game_logic::formula_input("my_attacks", FORMULA_READ_ONLY));
inputs->push_back(game_logic::formula_input("enemy_moves", FORMULA_READ_ONLY));
inputs->push_back(game_logic::formula_input("my_leader", FORMULA_READ_ONLY));
inputs->push_back(game_logic::formula_input("my_recruits", FORMULA_READ_ONLY));