The Battle for Wesnoth  1.13.10+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 - 2017 by Guorui Xi <kevin.xgr@gmail.com>
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 "random.hpp"
27 #include "recall_list_manager.hpp"
28 #include "resources.hpp"
29 #include "team.hpp"
30 #include "units/unit.hpp"
31 #include "units/helper.hpp"
32 #include "units/ptr.hpp"
33 #include "units/types.hpp"
34 
35 namespace ai {
36 
37 static lg::log_domain log_ai_sim_actions("ai/sim_actions");
38 #define DBG_AI_SIM_ACTIONS LOG_STREAM(debug, log_ai_sim_actions)
39 #define LOG_AI_SIM_ACTIONS LOG_STREAM(info, log_ai_sim_actions)
40 #define WRN_AI_SIM_ACTIONS LOG_STREAM(warn, log_ai_sim_actions)
41 #define ERR_AI_SIM_ACTIONS LOG_STREAM(err, log_ai_sim_actions)
42 
43 void helper_check_village(const map_location& loc, int side);
44 void helper_place_unit(const unit& u, const map_location& loc);
45 void helper_advance_unit(const map_location& loc);
46 
47 bool simulated_attack(const map_location& attacker_loc, const map_location& defender_loc, double attacker_hp, double defender_hp){
48  LOG_AI_SIM_ACTIONS << "Simulated attack" << std::endl;
49 
51  unit_map::iterator defend_unit = resources::gameboard->units().find(defender_loc);
52 
53  LOG_AI_SIM_ACTIONS << attack_unit->type_name() << " at " << attacker_loc << " attack "
54  << defend_unit->type_name() << " at " << defender_loc << std::endl;
55  LOG_AI_SIM_ACTIONS << "attacker's hp before attack: " << attack_unit->hitpoints() << std::endl;
56  LOG_AI_SIM_ACTIONS << "defender's hp before attack: " << defend_unit->hitpoints() << std::endl;
57 
58  attack_unit->set_hitpoints(static_cast<int>(attacker_hp));
59  defend_unit->set_hitpoints(static_cast<int>(defender_hp));
60 
61  LOG_AI_SIM_ACTIONS << "attacker's hp after attack: " << attack_unit->hitpoints() << std::endl;
62  LOG_AI_SIM_ACTIONS << "defender's hp after attack: " << defend_unit->hitpoints() << std::endl;
63 
64  int attacker_xp = defend_unit->level();
65  int defender_xp = attack_unit->level();
66  bool attacker_died = false;
67  bool defender_died = false;
68  if(attack_unit->hitpoints() <= 0){
69  attacker_xp = 0;
70  defender_xp = game_config::kill_xp(attack_unit->level());
71  (resources::gameboard->units()).erase(attacker_loc);
72  attacker_died = true;
73  }
74 
75  if(defend_unit->hitpoints() <= 0){
76  defender_xp = 0;
77  attacker_xp = game_config::kill_xp(defend_unit->level());
78  (resources::gameboard->units()).erase(defender_loc);
79  defender_died = true;
80  }
81 
82  if(!attacker_died){
83  attack_unit->set_experience(attack_unit->experience()+attacker_xp);
84  helper_advance_unit(attacker_loc);
85  simulated_stopunit(attacker_loc, true, true);
86  }
87 
88  if(!defender_died){
89  defend_unit->set_experience(defend_unit->experience()+defender_xp);
90  helper_advance_unit(defender_loc);
91  simulated_stopunit(defender_loc, true, true);
92  }
93 
94  return true;
95 }
96 
97 bool simulated_move(int side, const map_location& from, const map_location& to, int steps, map_location& unit_location){
98  LOG_AI_SIM_ACTIONS << "Simulated move" << std::endl;
99 
100  // In simulation, AI should not know if there is a enemy's ambusher.
101  std::pair<unit_map::unit_iterator, bool> unit_move = resources::gameboard->units().move(from, to);
102  bool is_ok = unit_move.second;
103  if(!is_ok){
104  unit_location = to; // This happened because in some CAs like get_village_phase and move_leader_to_keep phase,
105  // if the destination is already occupied will not be checked before execute. Just silent
106  // errors in ai/actions and tell rca the game state isn't changed.
107  return false;
108  }
109  unit_map::unit_iterator move_unit = unit_move.first;
110  move_unit->set_movement(move_unit->movement_left()-steps); // Following original logic, remove_movement_ will be considered outside.
111 
112  unit_location = move_unit->get_location(); // For check_after.
113 
114  LOG_AI_SIM_ACTIONS << move_unit->type_name() << " move from " << from << " to " << to << std::endl;
115 
116  if(resources::gameboard->map().is_village(to)){
117  helper_check_village(to, side);
118  }
119 
120  return true;
121 }
122 
123 bool simulated_recall(int side, const std::string& unit_id, const map_location& recall_location){
124  LOG_AI_SIM_ACTIONS << "Simulated recall" << std::endl;
125 
126  team own_team = resources::gameboard->get_team(side);
128 
129  helper_place_unit(*recall_unit, recall_location);
130 
131  own_team.spend_gold(recall_unit->recall_cost()<0 ? own_team.recall_cost() : recall_unit->recall_cost());
132 
133  LOG_AI_SIM_ACTIONS << "recall " << recall_unit->type_name() << " at "
134  << recall_location << " spend " << own_team.recall_cost() << " gold" << std::endl;
135 
136  return true;
137 }
138 
139 bool simulated_recruit(int side, const unit_type* u, const map_location& recruit_location){
140  LOG_AI_SIM_ACTIONS << "Simulated recruit" << std::endl;
141 
142  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.
143  helper_place_unit(recruit_unit, recruit_location);
144 
146 
147  LOG_AI_SIM_ACTIONS << "recruit " << u->type_name() << " at "
148  << recruit_location << " spend " << u->cost() << " gold" << std::endl;
149 
150  return true;
151 }
152 
153 bool simulated_stopunit(const map_location& unit_location, bool remove_movement, bool remove_attacks){
154  LOG_AI_SIM_ACTIONS << "Simulated stopunit" << std::endl;
155 
156  unit_map::iterator stop_unit = resources::gameboard->units().find(unit_location);
157  bool changed = false;
158  if(remove_movement){
159  stop_unit->set_movement(0, true);
160  LOG_AI_SIM_ACTIONS << "remove (" << stop_unit->get_location() << ") " << stop_unit->type_name() << "'s movement" << std::endl;
161  changed = true;
162  }
163  if(remove_attacks){
164  stop_unit->set_attacks(0);
165  LOG_AI_SIM_ACTIONS << "remove (" << stop_unit->get_location() << ") " << stop_unit->type_name() << "'s attacks" << std::endl;
166  changed = true;
167  }
168 
169  return changed;
170 }
171 
173  LOG_AI_SIM_ACTIONS << "Simulated synced_command" << std::endl;
174 
175  DBG_AI_SIM_ACTIONS << "Trigger dummy synced_command_result::do_execute()" << std::endl;
176 
177  return false;
178 }
179 
180 // Helper functions.
181 void helper_check_village(const map_location& loc, int side){
182  std::vector<team> &teams = resources::gameboard->teams();
183  team *t = unsigned(side - 1) < teams.size() ? &teams[side - 1] : nullptr;
184  if(t && t->owns_village(loc)){
185  return;
186  }
187 
188  bool has_leader = resources::gameboard->units().find_leader(side).valid();
189 
190  // Strip the village off all other sides.
191  int old_owner_side = 0;
192  for(std::vector<team>::iterator i = teams.begin(); i != teams.end(); ++i){
193  int i_side = i - teams.begin() + 1;
194  if(!t || has_leader || t->is_enemy(i_side)){
195  if(i->owns_village(loc)){
196  old_owner_side = i_side;
197  i->lose_village(loc);
198  DBG_AI_SIM_ACTIONS << "side " << i_side << " losts village at " << loc << std::endl;
199  }
200  }
201  }
202 
203  // Get the village if have leader.
204  if (!t) return;
205 
206  if(has_leader){
207  t->get_village(loc, old_owner_side, nullptr);
208  DBG_AI_SIM_ACTIONS << "side " << side << " gets village at " << loc << std::endl;
209  }
210 }
211 
212 void helper_place_unit(const unit& u, const map_location& loc){
213  unit_ptr new_unit(new unit(u));
214  new_unit->set_movement(0, true);
215  new_unit->set_attacks(0);
216  new_unit->heal_fully();
217  new_unit->set_location(loc);
218 
219  std::pair<unit_map::iterator, bool> add_result = resources::gameboard->units().insert(new_unit);
220  assert(add_result.second);
221  unit_map::iterator& new_unit_itor = add_result.first;
222 
223  if(resources::gameboard->map().is_village(loc)){
224  helper_check_village(loc, new_unit_itor->side());
225  }
226 }
227 
229  // Choose advanced unit type randomly.
230  // First check if the unit has enough experience and can advance.
231  // Then get all possible options, include modification advancements, like {AMLA DEFAULT} in cfg.
232  // And then randomly choose one to advanced to.
233 
235 
236  if(!unit_helper::will_certainly_advance(advance_unit))
237  return;
238 
239  const std::vector<std::string>& options = advance_unit->advances_to();
240  std::vector<config> mod_options = advance_unit->get_modification_advances();
241  int options_num = unit_helper::number_of_possible_advances(*advance_unit);
242 
243  size_t advance_choice = randomness::generator->get_random_int(0, options_num-1);
244  unit_ptr advanced_unit(new unit(*advance_unit));
245 
246  if(advance_choice < options.size()){
247  std::string advance_unit_typename = options[advance_choice];
248  const unit_type *advanced_type = unit_types.find(advance_unit_typename);
249  if(!advanced_type) {
250  ERR_AI_SIM_ACTIONS << "Simulating advancing to unknown unit type: " << advance_unit_typename;
251  assert(false && "simulating to unknown unit type");
252  }
253  advanced_unit->set_experience(advanced_unit->experience_overflow());
254  advanced_unit->advance_to(*advanced_type);
255  advanced_unit->heal_fully();
256  advanced_unit->set_state(unit::STATE_POISONED, false);
257  advanced_unit->set_state(unit::STATE_SLOWED, false);
258  advanced_unit->set_state(unit::STATE_PETRIFIED, false);
259  }else{
260  const config &mod_option = mod_options[advance_choice-options.size()];
261  advanced_unit->set_experience(advanced_unit->experience_overflow());
262  advanced_unit->add_modification("advancement", mod_option);
263  }
264 
265  resources::gameboard->units().replace(loc, advanced_unit);
266  LOG_AI_SIM_ACTIONS << advance_unit->type_name() << " at " << loc << " advanced to " << advanced_unit->type_name() << std::endl;
267 }
268 
269 }// End namespace
int kill_xp(int level)
Definition: game_config.hpp:48
bool recall_unit(const std::string &id, team &current_team, const map_location &loc, const map_location &from, map_location::DIRECTION facing, bool show, bool use_undo)
Recalls the unit with the indicated ID for the provided team.
Definition: create.cpp:736
bool simulated_synced_command()
virtual const unit_map & units() const
Definition: game_board.hpp:97
std::vector< char_t > string
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:137
This class represents a single unit of a specific type.
Definition: unit.hpp:100
void helper_place_unit(const unit &u, const map_location &loc)
umap_retval_pair_t insert(unit_ptr p)
Inserts the unit pointed to by p into the map.
Definition: map.cpp:135
unit_iterator find_leader(int side)
Definition: map.cpp:329
bool owns_village(const map_location &loc) const
Definition: team.hpp:184
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:30
bool is_enemy(int n) const
Definition: team.hpp:241
The unit is poisoned - it loses health each turn.
Definition: unit.hpp:721
unit_type_data unit_types
Definition: types.cpp:1455
The unit is petrified - it cannot move or be attacked.
Definition: unit.hpp:722
virtual const std::vector< team > & teams() const
Definition: game_board.hpp:92
#define DBG_AI_SIM_ACTIONS
bool simulated_attack(const map_location &attacker_loc, const map_location &defender_loc, double attacker_hp, double defender_hp)
-file sdl_utils.hpp
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.
A single unit type that the player may recruit.
Definition: types.hpp:43
umap_retval_pair_t replace(const map_location &l, unit_ptr p)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:225
const config & options()
Definition: game.cpp:570
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:44
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
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:704
team & get_team(int i)
Definition: game_board.hpp:94
int recall_cost() const
Definition: team.hpp:192
bool simulated_recall(int side, const std::string &unit_id, const map_location &recall_location)
static lg::log_domain log_ai_sim_actions("ai/sim_actions")
The unit is slowed - it moves slower and does less damage.
Definition: unit.hpp:720
game_board * gameboard
Definition: resources.cpp:20
void erase(const std::string &key)
Definition: general.cpp:222
umap_retval_pair_t move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
Definition: map.cpp:94
void spend_gold(const int amount)
Definition: team.hpp:207
int cost() const
Definition: types.hpp:159
Encapsulates the map of the game.
Definition: location.hpp:40
void advance_unit(map_location loc, const advancement_option &advance_to, bool fire_event)
Function which will advance the unit at loc to 'advance_to'.
void helper_check_village(const map_location &loc, int side)
#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:933
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:25
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
Definition: random.hpp:51
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:57
game_events::pump_result_t 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:424
boost::intrusive_ptr< unit > unit_ptr
Definition: ptr.hpp:29
double t
Definition: astarsearch.cpp:64
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:1537
bool simulated_recruit(int side, const unit_type *u, const map_location &recruit_location)
Standard logging facilities (interface).
#define LOG_AI_SIM_ACTIONS
recall_list_manager & recall_list()
Definition: team.hpp:214
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:1273
unit_iterator find(size_t id)
Definition: map.cpp:311
bool valid() const
Definition: map.hpp:276
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
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:481
Implement simulated actions.