The Battle for Wesnoth  1.17.0-dev
unit_creator.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2021
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Recruiting, recalling.
19  */
20 
21 #include "actions/unit_creator.hpp"
22 
23 #include "actions/move.hpp" //for actions::get_village
24 
25 #include "config.hpp"
26 #include "display.hpp"
27 #include "filter_context.hpp"
28 #include "game_board.hpp"
29 #include "game_events/pump.hpp"
30 #include "preferences/game.hpp"
31 #include "game_data.hpp" // for resources::gamedata conversion variable_set
32 #include "gettext.hpp"
33 #include "log.hpp"
34 #include "map/map.hpp"
35 #include "pathfind/pathfind.hpp"
36 #include "resources.hpp" // for resources::gamedata
37 #include "team.hpp" //for team
38 #include "units/unit.hpp" // for unit
39 #include "units/udisplay.hpp" // for unit_display
40 #include "variable.hpp" // for vconfig
41 #include "deprecation.hpp"
42 
43 static lg::log_domain log_engine("engine");
44 #define DBG_NG LOG_STREAM(debug, log_engine)
45 #define LOG_NG LOG_STREAM(info, log_engine)
46 #define WARN_NG LOG_STREAM(warn, log_engine)
47 #define ERR_NG LOG_STREAM(err, log_engine)
48 
50  : add_to_recall_(false)
51  , discover_(false)
52  , get_village_(false)
53  , invalidate_(false)
54  , rename_side_(false)
55  , show_(false)
56  , start_pos_(start_pos)
57  , team_(tm)
58  , board_(board ? board : resources::gameboard)
59 {
60 }
61 
62 
64 {
65  show_ = b;
66  return *this;
67 }
68 
69 
71 {
72  get_village_ = b;
73  return *this;
74 }
75 
76 
78 {
79  rename_side_ = b;
80  return *this;
81 }
82 
84 {
85  invalidate_ = b;
86  return *this;
87 }
88 
89 
91 {
92  discover_ = b;
93  return *this;
94 }
95 
96 
98 {
99  add_to_recall_ = b;
100  return *this;
101 }
102 
103 
104 map_location unit_creator::find_location(const config &cfg, const unit* pass_check)
105 {
106 
107  DBG_NG << "finding location for unit with id=["<<cfg["id"]<<"] placement=["<<cfg["placement"]<<"] x=["<<cfg["x"]<<"] y=["<<cfg["y"]<<"] for side " << team_.side() << "\n";
108 
109  std::vector<std::string> placements = utils::split(cfg["placement"]);
110 
111  placements.push_back("map");
112  placements.push_back("recall");
113 
114  bool pass = cfg["passable"].to_bool(false);
115  bool vacant = !cfg["overwrite"].to_bool(false);
116 
117  for (const std::string& place : placements)
118  {
119  map_location loc;
120 
121  if ( place == "recall" ) {
123  }
124 
125  else if ( place == "leader" || place == "leader_passable" ) {
127  //todo: take 'leader in recall list' possibility into account
128  if (leader.valid()) {
129  loc = leader->get_location();
130  } else {
131  loc = start_pos_;
132  }
133  if(place == "leader_passable") {
134  deprecated_message("placement=leader_passable", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Please use placement=leader and passable=yes instead");
135  pass = true;
136  }
137  }
138 
139  // "map", "map_passable", and "map_overwrite".
140  else if(place == "map" || place == "map_passable" || place == "map_overwrite") {
141  if(cfg.has_attribute("location_id")) {
142  loc = board_->map().special_location(cfg["location_id"]);
143  }
144  if(!loc.valid()) {
145  loc = map_location(cfg, resources::gamedata);
146  }
147  if(place == "map_passable") {
148  deprecated_message("placement=map_passable", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Please use placement=map and passable=yes instead");
149  pass = true;
150  } else if(place == "map_overwrite") {
151  deprecated_message("placement=map_overwrite", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Please use placement=map and overwrite=yes instead");
152  vacant = false;
153  }
154  }
155 
156  if(loc.valid() && board_->map().on_board(loc)) {
157  if(vacant) {
159  pass ? pass_check : nullptr, nullptr, board_);
160  }
161  if(loc.valid() && board_->map().on_board(loc)) {
162  return loc;
163  }
164  }
165  }
166 
168 
169 }
170 
171 
172 void unit_creator::add_unit(const config &cfg, const vconfig* vcfg)
173 {
174  config temp_cfg(cfg);
175  temp_cfg["side"] = team_.side();
176 
177  const std::string& id =(cfg)["id"];
178  bool animate = temp_cfg["animate"].to_bool();
179  bool fire_event = temp_cfg["fire_event"].to_bool(true);
180  temp_cfg.remove_attribute("animate");
181 
182  unit_ptr recall_list_element = team_.recall_list().find_if_matches_id(id);
183 
184  if ( !recall_list_element ) {
185  //make the new unit
186  unit_ptr new_unit = unit::create(temp_cfg, true, vcfg);
187  map_location loc = find_location(temp_cfg, new_unit.get());
188  if ( loc.valid() ) {
189  //add the new unit to map
190  board_->units().replace(loc, new_unit);
191  LOG_NG << "inserting unit for side " << new_unit->side() << "\n";
192  post_create(loc,*(board_->units().find(loc)),animate,fire_event);
193  }
194  else if ( add_to_recall_ ) {
195  //add to recall list
196  team_.recall_list().add(new_unit);
197  DBG_NG << "inserting unit with id=["<<id<<"] on recall list for side " << new_unit->side() << "\n";
198  preferences::encountered_units().insert(new_unit->type_id());
199  }
200  } else {
201  //get unit from recall list
202  map_location loc = find_location(temp_cfg, recall_list_element.get());
203  if ( loc.valid() ) {
204  board_->units().replace(loc, recall_list_element);
205  LOG_NG << "inserting unit from recall list for side " << recall_list_element->side()<< " with id="<< id << "\n";
206  post_create(loc,*(board_->units().find(loc)),animate,fire_event);
207  //if id is not empty, delete units with this ID from recall list
209  }
210  else if ( add_to_recall_ ) {
211  LOG_NG << "wanted to insert unit on recall list, but recall list for side " << (cfg)["side"] << "already contains id=" <<id<<"\n";
212  return;
213  }
214  }
215 }
216 
217 
218 void unit_creator::post_create(const map_location &loc, const unit &new_unit, bool anim, bool fire_event)
219 {
220 
221  if (discover_) {
222  preferences::encountered_units().insert(new_unit.type_id());
223  }
224 
225  bool show = show_ && (display::get_singleton() !=nullptr) && !display::get_singleton()->fogged(loc);
226  bool animate = show && anim;
227 
228  if (get_village_) {
229  assert(resources::gameboard);
230  if (board_->map().is_village(loc)) {
231  actions::get_village(loc, new_unit.side());
232  }
233  }
234 
235  // Only fire the events if it's safe; it's not if we're in the middle of play_controller::reset_gamestate()
236  if (fire_event && resources::lua_kernel != nullptr) {
237  resources::game_events->pump().fire("unit_placed", loc);
238  }
239 
240  if (display::get_singleton()!=nullptr) {
241 
242  if (invalidate_ ) {
244  }
245 
246  if (animate) {
248  }
249  }
250 }
unit_creator & allow_rename_side(bool b)
Game board class.
Definition: game_board.hpp:51
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:92
virtual const unit_map & units() const override
Definition: game_board.hpp:112
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3026
This class represents a single unit of a specific type.
Definition: unit.hpp:121
const std::string & type_id() const
The id of this unit&#39;s type.
Definition: unit.cpp:1801
static lg::log_domain log_engine("engine")
unit_creator & allow_invalidate(bool b)
unit_creator & allow_show(bool b)
unit_iterator find_leader(int side)
Definition: map.cpp:328
bool has_attribute(config_key_type key) const
Definition: config.cpp:211
map_location find_vacant_tile(const map_location &loc, VACANT_TILE_TYPE vacancy, const unit *pass_check, const team *shroud_check, const game_board *board)
Function that will find a location on the board that is as near to loc as possible, but which is unoccupied by any units.
Definition: pathfind.cpp:55
unit_creator & allow_discover(bool b)
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:780
virtual const gamemap & map() const override
Definition: game_board.hpp:102
void remove_attribute(config_key_type key)
Definition: config.cpp:217
Definitions for the interface to Wesnoth Markup Language (WML).
unit_creator & allow_add_to_recall(bool b)
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
map_location special_location(const std::string &id) const
Definition: map.cpp:312
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:190
game_data * gamedata
Definition: resources.cpp:23
#define b
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:224
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:72
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id.
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:30
#define LOG_NG
bool valid() const
Definition: location.hpp:89
game_board * gameboard
Definition: resources.cpp:21
const map_location start_pos_
map_display and display: classes which take care of displaying the map and game-data on the screen...
game_events::manager * game_events
Definition: resources.cpp:25
void erase_if_matches_id(const std::string &unit_id)
Erase any unit with this id.
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:745
Encapsulates the map of the game.
Definition: location.hpp:38
Various functions related to moving units.
unit_iterator find(std::size_t id)
Definition: map.cpp:310
bool fire_event(const ui_event event, std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
unit_creator & allow_get_village(bool b)
Various functions related to the creation of units (recruits, recalls, and placed units)...
Define the game&#39;s event mechanism.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:385
void post_create(const map_location &loc, const unit &new_unit, bool anim, bool fire_event)
std::set< std::string > & encountered_units()
Definition: game.cpp:930
pump_result_t fire(const std::string &event, const entity_location &loc1=entity_location::null_entity, const entity_location &loc2=entity_location::null_entity, const config &data=config())
Function to fire an event.
Definition: pump.cpp:481
bool is_village(const map_location &loc) const
Definition: map.cpp:66
void add_unit(const config &cfg, const vconfig *vcfg=nullptr)
adds a unit on map without firing any events (so, usable during team construction in gamestatus) ...
game_events::pump_result_t get_village(const map_location &loc, int side, bool *action_timebonus, bool fire_event)
Makes it so the village at the given location is owned by the given side.
Definition: move.cpp:140
map_location find_location(const config &cfg, const unit *pass_check=nullptr)
finds a suitable location for unit
std::vector< std::string > split(const config_attribute_value &val)
void add(const unit_ptr &ptr, int pos=-1)
Add a unit to the list.
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:801
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
Standard logging facilities (interface).
recall_list_manager & recall_list()
Definition: team.hpp:227
static const map_location & null_location()
Definition: location.hpp:81
game_lua_kernel * lua_kernel
Definition: resources.cpp:26
int side() const
The side this unit belongs to.
Definition: unit.hpp:334
game_events::wml_event_pump & pump()
Definition: manager.cpp:230
unit_creator(team &tm, const map_location &start_pos, game_board *board=nullptr)
int side() const
Definition: team.hpp:200
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
bool valid() const
Definition: map.hpp:274
This module contains various pathfinding functions and utilities.
game_board * board_
Display units performing various actions: moving, attacking, and dying.
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
Definition: tooltip.cpp:140
#define DBG_NG