The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
simulated_actions.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by Guorui Xi <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * Implement simulated actions
17  * @file
18  */
19 
20 #include "ai/simulated_actions.hpp"
21 
22 #include "game_board.hpp"
23 #include "game_config.hpp"
24 #include "log.hpp"
25 #include "map/map.hpp"
26 #include "recall_list_manager.hpp"
27 #include "resources.hpp"
28 #include "team.hpp"
29 #include "units/unit.hpp"
30 #include "units/helper.hpp"
31 #include "units/ptr.hpp"
32 #include "units/types.hpp"
33 
34 namespace ai {
35 
36 static lg::log_domain log_ai_sim_actions("ai/sim_actions");
37 #define DBG_AI_SIM_ACTIONS LOG_STREAM(debug, log_ai_sim_actions)
38 #define LOG_AI_SIM_ACTIONS LOG_STREAM(info, log_ai_sim_actions)
39 #define WRN_AI_SIM_ACTIONS LOG_STREAM(warn, log_ai_sim_actions)
40 #define ERR_AI_SIM_ACTIONS LOG_STREAM(err, log_ai_sim_actions)
41 
42 void helper_check_village(const map_location& loc, int side);
43 void helper_place_unit(const unit& u, const map_location& loc);
44 void helper_advance_unit(const map_location& loc);
45 
46 bool simulated_attack(const map_location& attacker_loc, const map_location& defender_loc, double attacker_hp, double defender_hp){
47  LOG_AI_SIM_ACTIONS << "Simulated attack" << std::endl;
48 
50  unit_map::iterator defend_unit = resources::units->find(defender_loc);
51 
52  LOG_AI_SIM_ACTIONS << attack_unit->type_name() << " at " << attacker_loc << " attack "
53  << defend_unit->type_name() << " at " << defender_loc << std::endl;
54  LOG_AI_SIM_ACTIONS << "attacker's hp before attack: " << attack_unit->hitpoints() << std::endl;
55  LOG_AI_SIM_ACTIONS << "defender's hp before attack: " << defend_unit->hitpoints() << std::endl;
56 
57  attack_unit->set_hitpoints(static_cast<int>(attacker_hp));
58  defend_unit->set_hitpoints(static_cast<int>(defender_hp));
59 
60  LOG_AI_SIM_ACTIONS << "attacker's hp after attack: " << attack_unit->hitpoints() << std::endl;
61  LOG_AI_SIM_ACTIONS << "defender's hp after attack: " << defend_unit->hitpoints() << std::endl;
62 
63  int attacker_xp = defend_unit->level();
64  int defender_xp = attack_unit->level();
65  bool attacker_died = false;
66  bool defender_died = false;
67  if(attack_unit->hitpoints() <= 0){
68  attacker_xp = 0;
69  defender_xp = game_config::kill_xp(attack_unit->level());
70  (*resources::units).erase(attacker_loc);
71  attacker_died = true;
72  }
73 
74  if(defend_unit->hitpoints() <= 0){
75  defender_xp = 0;
76  attacker_xp = game_config::kill_xp(defend_unit->level());
77  (*resources::units).erase(defender_loc);
78  defender_died = true;
79  }
80 
81  if(!attacker_died){
82  attack_unit->set_experience(attack_unit->experience()+attacker_xp);
83  helper_advance_unit(attacker_loc);
84  simulated_stopunit(attacker_loc, true, true);
85  }
86 
87  if(!defender_died){
88  defend_unit->set_experience(defend_unit->experience()+defender_xp);
89  helper_advance_unit(defender_loc);
90  simulated_stopunit(defender_loc, true, true);
91  }
92 
93  return true;
94 }
95 
96 bool simulated_move(int side, const map_location& from, const map_location& to, int steps, map_location& unit_location){
97  LOG_AI_SIM_ACTIONS << "Simulated move" << std::endl;
98 
99  // In simulation, AI should not know if there is a enemy's ambusher.
100  std::pair<unit_map::unit_iterator, bool> unit_move = resources::units->move(from, to);
101  bool is_ok = unit_move.second;
102  if(!is_ok){
103  unit_location = to; // This happened because in some CAs like get_village_phase and move_leader_to_keep phase,
104  // if the destination is already occupied will not be checked before execute. Just silent
105  // errors in ai/actions and tell rca the game state isn't changed.
106  return false;
107  }
108  unit_map::unit_iterator move_unit = unit_move.first;
109  move_unit->set_movement(move_unit->movement_left()-steps); // Following original logic, remove_movement_ will be considered outside.
110 
111  unit_location = move_unit->get_location(); // For check_after.
112 
113  LOG_AI_SIM_ACTIONS << move_unit->type_name() << " move from " << from << " to " << to << std::endl;
114 
115  if(resources::gameboard->map().is_village(to)){
116  helper_check_village(to, side);
117  }
118 
119  return true;
120 }
121 
122 bool simulated_recall(int side, const std::string& unit_id, const map_location& recall_location){
123  LOG_AI_SIM_ACTIONS << "Simulated recall" << std::endl;
124 
125  team own_team = (*resources::teams)[side-1];
127 
128  helper_place_unit(*recall_unit, recall_location);
129 
130  own_team.spend_gold(recall_unit->recall_cost()<0 ? own_team.recall_cost() : recall_unit->recall_cost());
131 
132  LOG_AI_SIM_ACTIONS << "recall " << recall_unit->type_name() << " at "
133  << recall_location << " spend " << own_team.recall_cost() << " gold" << std::endl;
134 
135  return true;
136 }
137 
138 bool simulated_recruit(int side, const unit_type* u, const map_location& recruit_location){
139  LOG_AI_SIM_ACTIONS << "Simulated recruit" << std::endl;
140 
141  const unit recruit_unit(*u, side, false); // Random traits, name and gender are not needed. This will cause "duplicate id conflicts" inside unit_map::insert(), but engine will manage this issue correctly.
142  helper_place_unit(recruit_unit, recruit_location);
143 
144  (*resources::teams)[side-1].spend_gold(u->cost());
145 
146  LOG_AI_SIM_ACTIONS << "recruit " << u->type_name() << " at "
147  << recruit_location << " spend " << u->cost() << " gold" << std::endl;
148 
149  return true;
150 }
151 
152 bool simulated_stopunit(const map_location& unit_location, bool remove_movement, bool remove_attacks){
153  LOG_AI_SIM_ACTIONS << "Simulated stopunit" << std::endl;
154 
155  unit_map::iterator stop_unit = resources::units->find(unit_location);
156  bool changed = false;
157  if(remove_movement){
158  stop_unit->set_movement(0, true);
159  LOG_AI_SIM_ACTIONS << "remove (" << stop_unit->get_location() << ") " << stop_unit->type_name() << "'s movement" << std::endl;
160  changed = true;
161  }
162  if(remove_attacks){
163  stop_unit->set_attacks(0);
164  LOG_AI_SIM_ACTIONS << "remove (" << stop_unit->get_location() << ") " << stop_unit->type_name() << "'s attacks" << std::endl;
165  changed = true;
166  }
167 
168  return changed;
169 }
170 
172  LOG_AI_SIM_ACTIONS << "Simulated synced_command" << std::endl;
173 
174  DBG_AI_SIM_ACTIONS << "Trigger dummy synced_command_result::do_execute()" << std::endl;
175 
176  return false;
177 }
178 
179 // Helper functions.
180 void helper_check_village(const map_location& loc, int side){
181  std::vector<team> &teams = *resources::teams;
182  team *t = unsigned(side - 1) < teams.size() ? &teams[side - 1] : nullptr;
183  if(t && t->owns_village(loc)){
184  return;
185  }
186 
187  bool has_leader = resources::units->find_leader(side).valid();
188 
189  // Strip the village off all other sides.
190  int old_owner_side = 0;
191  for(std::vector<team>::iterator i = teams.begin(); i != teams.end(); ++i){
192  int i_side = i - teams.begin() + 1;
193  if(!t || has_leader || t->is_enemy(i_side)){
194  if(i->owns_village(loc)){
195  old_owner_side = i_side;
196  i->lose_village(loc);
197  DBG_AI_SIM_ACTIONS << "side " << i_side << " losts village at " << loc << std::endl;
198  }
199  }
200  }
201 
202  // Get the village if have leader.
203  if (!t) return;
204 
205  if(has_leader){
206  t->get_village(loc, old_owner_side, nullptr);
207  DBG_AI_SIM_ACTIONS << "side " << side << " gets village at " << loc << std::endl;
208  }
209 }
210 
211 void helper_place_unit(const unit& u, const map_location& loc){
212  unit new_unit = u;
213  new_unit.set_movement(0, true);
214  new_unit.set_attacks(0);
215  new_unit.heal_all();
216 
217  std::pair<unit_map::iterator, bool> add_result = resources::units->add(loc, new_unit);
218  assert(add_result.second);
219  unit_map::iterator& new_unit_itor = add_result.first;
220 
221  if(resources::gameboard->map().is_village(loc)){
222  helper_check_village(loc, new_unit_itor->side());
223  }
224 }
225 
227  // Choose advanced unit type randomly.
228  // First check if the unit has enough experience and can advance.
229  // Then get all possible options, include modification advancements, like {AMLA DEFAULT} in cfg.
230  // And then randomly choose one to advanced to.
231 
233 
234  if(!unit_helper::will_certainly_advance(advance_unit))
235  return;
236 
237  const std::vector<std::string>& options = advance_unit->advances_to();
238  std::vector<config> mod_options = advance_unit->get_modification_advances();
239  int options_num = unit_helper::number_of_possible_advances(*advance_unit);
240 
241  size_t advance_choice = rand() % options_num;
242  unit advanced_unit(*advance_unit);
243 
244  if(advance_choice < options.size()){
245  std::string advance_unit_typename = options[advance_choice];
246  const unit_type *advanced_type = unit_types.find(advance_unit_typename);
247  if(!advanced_type) {
248  ERR_AI_SIM_ACTIONS << "Simulating advancing to unknown unit type: " << advance_unit_typename;
249  assert(false && "simulating to unknown unit type");
250  }
251  advanced_unit.set_experience(advanced_unit.experience() - advanced_unit.max_experience());
252  advanced_unit.advance_to(*advanced_type);
253  advanced_unit.heal_all();
254  advanced_unit.set_state(unit::STATE_POISONED, false);
255  advanced_unit.set_state(unit::STATE_SLOWED, false);
256  advanced_unit.set_state(unit::STATE_PETRIFIED, false);
257  }else{
258  const config &mod_option = mod_options[advance_choice-options.size()];
259  advanced_unit.set_experience(advanced_unit.experience()-advanced_unit.max_experience());
260  advanced_unit.add_modification("advancement", mod_option);
261  }
262 
263  resources::units->replace(loc, advanced_unit);
264  LOG_AI_SIM_ACTIONS << advance_unit->type_name() << " at " << loc << " advanced to " << advanced_unit.type_name() << std::endl;
265 }
266 
267 }// End namespace
int kill_xp(int level)
Definition: game_config.hpp:45
void advance_unit(map_location loc, const std::string &advance_to, const bool &fire_event, const config *mod_option)
Function which will advance the unit at loc to 'advance_to'.
Definition: attack.cpp:1573
bool simulated_synced_command()
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:112
Definition: unit.hpp:95
const t_string & type_name() const
The unit type name.
Definition: unit.hpp:153
int experience() const
Definition: unit.hpp:171
void helper_place_unit(const unit &u, const map_location &loc)
unit_iterator find_leader(int side)
Definition: map.cpp:297
bool owns_village(const map_location &loc) const
Definition: team.hpp:190
bool will_certainly_advance(const unit_map::iterator &u)
Encapsulates the logic for deciding whether an iterator u points to a unit that can advance...
Definition: helper.cpp:31
bool is_enemy(int n) const
Definition: team.hpp:247
void advance_to(const unit_type &t, bool use_traits=false)
Advances this unit to another type.
Definition: unit.cpp:904
unit_type_data unit_types
Definition: types.cpp:1314
#define DBG_AI_SIM_ACTIONS
void set_state(const std::string &state, bool value)
Definition: unit.cpp:1337
bool simulated_attack(const map_location &attacker_loc, const map_location &defender_loc, double attacker_hp, double defender_hp)
-file sdl_utils.hpp
GLdouble GLdouble t
Definition: glew.h:1366
unit_ptr extract_if_matches_id(const std::string &unit_id)
Find a unit by id, and extract from this object if found. Null if not found.
static std::vector< team > *& teams
Definition: team.cpp:50
const config & options()
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:50
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:57
void recruit_unit(const unit_type &u_type, int side_num, const map_location &loc, const map_location &from, bool show, bool use_undo)
Recruits a unit of the given type for the given side.
Definition: create.cpp:699
int recall_cost() const
Definition: team.hpp:198
bool simulated_recall(int side, const std::string &unit_id, const map_location &recall_location)
std::vector< team > * teams
Definition: resources.cpp:29
static lg::log_domain log_ai_sim_actions("ai/sim_actions")
void heal_all()
Definition: unit.hpp:241
game_board * gameboard
Definition: resources.cpp:20
void spend_gold(const int amount)
Definition: team.hpp:213
std::pair< unit_iterator, bool > replace(const map_location &l, const unit &u)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:207
std::pair< unit_iterator, bool > add(const map_location &l, const unit &u)
Adds a copy of unit u at location l of the map.
Definition: map.cpp:70
int cost() const
Definition: types.hpp:134
Encapsulates the map of the game.
Definition: location.hpp:38
void helper_check_village(const map_location &loc, int side)
void add_modification(const std::string &type, const config &modification, bool no_add=false)
Definition: unit.cpp:2133
#define ERR_AI_SIM_ACTIONS
void helper_advance_unit(const map_location &loc)
bool simulated_stopunit(const map_location &unit_location, bool remove_movement, bool remove_attacks)
size_t i
Definition: function.cpp:1057
void set_movement(int moves, bool unit_action=false)
Set the unit's remaining movement to moves.
Definition: unit.cpp:1148
int number_of_possible_advances(const unit &u)
Determines the total number of available advancements (of any kind) for a given unit.
Definition: helper.cpp:26
std::pair< unit_iterator, bool > move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
Definition: map.cpp:79
int max_experience() const
Definition: unit.hpp:172
bool simulated_move(int side, const map_location &from, const map_location &to, int steps, map_location &unit_location)
void attack_unit(const map_location &attacker, const map_location &defender, int attack_with, int defend_with, bool update_display)
Performs an attack.
Definition: attack.cpp:1384
bool simulated_recruit(int side, const unit_type *u, const map_location &recruit_location)
Standard logging facilities (interface).
#define LOG_AI_SIM_ACTIONS
bool recall_unit(const std::string &id, team &current_team, const map_location &loc, const map_location &from, bool show, bool use_undo)
Recalls the unit with the indicated ID for the provided team.
Definition: create.cpp:731
recall_list_manager & recall_list()
Definition: team.hpp:220
void set_attacks(int left)
Definition: unit.hpp:233
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1155
unit_iterator find(size_t id)
Definition: map.cpp:285
bool valid() const
Definition: map.hpp:229
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
void set_experience(int xp)
Definition: unit.hpp:173
GLsizei const GLcharARB ** string
Definition: glew.h:4503
unit_map * units
Definition: resources.cpp:35
void move_unit(const std::vector< map_location > &path, unit_ptr u, bool animate, map_location::DIRECTION dir, bool force_scroll)
Display a unit moving along a given path.
Definition: udisplay.cpp:486
bool get_village(const map_location &, const int owner_side, game_data *fire_event)
Acquires a village from owner_side. Pointer fire_event should be the game_data for the game if it is ...
Definition: team.cpp:377
Implement simulated actions.