The Battle for Wesnoth  1.17.23+dev
unit_creator.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2023
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();
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();
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();
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;
206  //if id is not empty, delete units with this ID from recall list
208  post_create(loc,*(board_->units().find(loc)),animate,fire_event);
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;
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 }
Various functions related to moving units.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
bool has_attribute(config_key_type key) const
Definition: config.cpp:159
void remove_attribute(config_key_type key)
Definition: config.cpp:164
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:691
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3147
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:707
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:101
Game board class.
Definition: game_board.hpp:53
virtual const unit_map & units() const override
Definition: game_board.hpp:113
virtual const gamemap & map() const override
Definition: game_board.hpp:103
game_events::wml_event_pump & pump()
Definition: manager.cpp:259
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:402
map_location special_location(const std::string &id) const
Definition: map.cpp:312
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:385
bool is_village(const map_location &loc) const
Definition: map.cpp:66
void add(const unit_ptr &ptr, int pos=-1)
Add a unit to the list.
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id.
void erase_if_matches_id(const std::string &unit_id)
Erase any unit with this id.
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:76
int side() const
Definition: team.hpp:176
recall_list_manager & recall_list()
Definition: team.hpp:203
unit_creator & allow_invalidate(bool b)
unit_creator & allow_get_village(bool b)
unit_creator(team &tm, const map_location &start_pos, game_board *board=nullptr)
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)
map_location find_location(const config &cfg, const unit *pass_check=nullptr)
finds a suitable location for unit
unit_creator & allow_discover(bool b)
void post_create(const map_location &loc, const unit &new_unit, bool anim, bool fire_event)
unit_creator & allow_show(bool b)
unit_creator & allow_rename_side(bool b)
const map_location start_pos_
unit_creator & allow_add_to_recall(bool b)
game_board * board_
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:215
unit_iterator find(std::size_t id)
Definition: map.cpp:301
unit_iterator find_leader(int side)
Definition: map.cpp:319
This class represents a single unit of a specific type.
Definition: unit.hpp:135
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:203
A variable-expanding proxy for the config class.
Definition: variable.hpp:45
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:30
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1938
int side() const
The side this unit belongs to.
Definition: unit.hpp:345
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
Standard logging facilities (interface).
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
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:81
bool fire_event(const ui_event event, const std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&... params)
Helper function for fire_event.
@ VACANT_ANY
Definition: pathfind.hpp:39
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,...
Definition: pathfind.cpp:54
std::set< std::string > & encountered_units()
Definition: game.cpp:916
game_board * gameboard
Definition: resources.cpp:21
game_data * gamedata
Definition: resources.cpp:23
game_events::manager * game_events
Definition: resources.cpp:25
game_lua_kernel * lua_kernel
Definition: resources.cpp:26
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:803
std::vector< std::string > split(const config_attribute_value &val)
This module contains various pathfinding functions and utilities.
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
Define the game's event mechanism.
Encapsulates the map of the game.
Definition: location.hpp:38
bool valid() const
Definition: location.hpp:89
static const map_location & null_location()
Definition: location.hpp:81
bool valid() const
Definition: map.hpp:274
Display units performing various actions: moving, attacking, and dying.
static lg::log_domain log_engine("engine")
#define DBG_NG
#define LOG_NG
Various functions related to the creation of units (recruits, recalls, and placed units).
#define b