The Battle for Wesnoth  1.19.0-dev
unit_creator.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
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 "game_board.hpp"
28 #include "game_events/pump.hpp"
29 #include "preferences/game.hpp"
30 #include "game_data.hpp" // for resources::gamedata conversion variable_set
31 #include "game_version.hpp"
32 #include "log.hpp"
33 #include "map/map.hpp"
34 #include "pathfind/pathfind.hpp"
35 #include "resources.hpp" // for resources::gamedata
36 #include "team.hpp" //for team
37 #include "units/unit.hpp" // for unit
38 #include "units/udisplay.hpp" // for unit_display
39 #include "deprecation.hpp"
40 
41 static lg::log_domain log_engine("engine");
42 #define DBG_NG LOG_STREAM(debug, log_engine)
43 #define LOG_NG LOG_STREAM(info, log_engine)
44 #define WARN_NG LOG_STREAM(warn, log_engine)
45 #define ERR_NG LOG_STREAM(err, log_engine)
46 
48  : add_to_recall_(false)
49  , discover_(false)
50  , get_village_(false)
51  , invalidate_(false)
52  , rename_side_(false)
53  , show_(false)
54  , start_pos_(start_pos)
55  , team_(tm)
56  , board_(board ? board : resources::gameboard)
57 {
58 }
59 
60 
62 {
63  show_ = b;
64  return *this;
65 }
66 
67 
69 {
70  get_village_ = b;
71  return *this;
72 }
73 
74 
76 {
77  rename_side_ = b;
78  return *this;
79 }
80 
82 {
83  invalidate_ = b;
84  return *this;
85 }
86 
87 
89 {
90  discover_ = b;
91  return *this;
92 }
93 
94 
96 {
97  add_to_recall_ = b;
98  return *this;
99 }
100 
101 
102 map_location unit_creator::find_location(const config &cfg, const unit* pass_check)
103 {
104 
105  DBG_NG << "finding location for unit with id=["<<cfg["id"]<<"] placement=["<<cfg["placement"]<<"] x=["<<cfg["x"]<<"] y=["<<cfg["y"]<<"] for side " << team_.side();
106 
107  std::vector<std::string> placements = utils::split(cfg["placement"]);
108 
109  placements.push_back("map");
110  placements.push_back("recall");
111 
112  bool pass = cfg["passable"].to_bool(false);
113  bool vacant = !cfg["overwrite"].to_bool(false);
114 
115  for (const std::string& place : placements)
116  {
117  map_location loc;
118 
119  if ( place == "recall" ) {
121  }
122 
123  else if ( place == "leader" || place == "leader_passable" ) {
125  //todo: take 'leader in recall list' possibility into account
126  if (leader.valid()) {
127  loc = leader->get_location();
128  } else {
129  loc = start_pos_;
130  }
131  if(place == "leader_passable") {
132  deprecated_message("placement=leader_passable", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Please use placement=leader and passable=yes instead");
133  pass = true;
134  }
135  }
136 
137  // "map", "map_passable", and "map_overwrite".
138  else if(place == "map" || place == "map_passable" || place == "map_overwrite") {
139  if(cfg.has_attribute("location_id")) {
140  loc = board_->map().special_location(cfg["location_id"]);
141  }
142  if(!loc.valid()) {
143  loc = map_location(cfg, resources::gamedata);
144  }
145  if(place == "map_passable") {
146  deprecated_message("placement=map_passable", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Please use placement=map and passable=yes instead");
147  pass = true;
148  } else if(place == "map_overwrite") {
149  deprecated_message("placement=map_overwrite", DEP_LEVEL::PREEMPTIVE, {1, 15, 0}, "Please use placement=map and overwrite=yes instead");
150  vacant = false;
151  }
152  }
153 
154  if(loc.valid() && board_->map().on_board(loc)) {
155  if(vacant) {
157  pass ? pass_check : nullptr, nullptr, board_);
158  }
159  if(loc.valid() && board_->map().on_board(loc)) {
160  return loc;
161  }
162  }
163  }
164 
166 
167 }
168 
169 
170 void unit_creator::add_unit(const config &cfg, const vconfig* vcfg)
171 {
172  config temp_cfg(cfg);
173  temp_cfg["side"] = team_.side();
174 
175  const std::string& id =(cfg)["id"];
176  bool animate = temp_cfg["animate"].to_bool();
177  bool fire_event = temp_cfg["fire_event"].to_bool(true);
178  temp_cfg.remove_attribute("animate");
179 
180  unit_ptr recall_list_element = team_.recall_list().find_if_matches_id(id);
181 
182  if ( !recall_list_element ) {
183  //make the new unit
184  unit_ptr new_unit = unit::create(temp_cfg, true, vcfg);
185  map_location loc = find_location(temp_cfg, new_unit.get());
186  if ( loc.valid() ) {
187  //add the new unit to map
188  board_->units().replace(loc, new_unit);
189  LOG_NG << "inserting unit for side " << new_unit->side();
190  post_create(loc,*(board_->units().find(loc)),animate,fire_event);
191  }
192  else if ( add_to_recall_ ) {
193  //add to recall list
194  team_.recall_list().add(new_unit);
195  DBG_NG << "inserting unit with id=["<<id<<"] on recall list for side " << new_unit->side();
196  preferences::encountered_units().insert(new_unit->type_id());
197  }
198  } else {
199  //get unit from recall list
200  map_location loc = find_location(temp_cfg, recall_list_element.get());
201  if ( loc.valid() ) {
202  board_->units().replace(loc, recall_list_element);
203  LOG_NG << "inserting unit from recall list for side " << recall_list_element->side()<< " with id="<< id;
204  //if id is not empty, delete units with this ID from recall list
206  post_create(loc,*(board_->units().find(loc)),animate,fire_event);
207  }
208  else if ( add_to_recall_ ) {
209  LOG_NG << "wanted to insert unit on recall list, but recall list for side " << (cfg)["side"] << "already contains id=" <<id;
210  return;
211  }
212  }
213 }
214 
215 
216 void unit_creator::post_create(const map_location &loc, const unit &new_unit, bool anim, bool fire_event)
217 {
218 
219  if (discover_) {
220  preferences::encountered_units().insert(new_unit.type_id());
221  }
222 
223  bool show = show_ && (display::get_singleton() !=nullptr) && !display::get_singleton()->fogged(loc);
224  bool animate = show && anim;
225 
226  if (get_village_) {
227  assert(resources::gameboard);
228  if (board_->map().is_village(loc)) {
229  actions::get_village(loc, new_unit.side());
230  }
231  }
232 
233  // Only fire the events if it's safe; it's not if we're in the middle of play_controller::reset_gamestate()
234  if (fire_event && resources::lua_kernel != nullptr) {
235  resources::game_events->pump().fire("unit_placed", loc);
236  }
237 
238  if (display::get_singleton()!=nullptr) {
239 
240  if (invalidate_ ) {
242  }
243 
244  if (animate) {
246  }
247  }
248 }
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:159
bool has_attribute(config_key_type key) const
Definition: config.cpp:155
void remove_attribute(config_key_type key)
Definition: config.cpp:160
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:687
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:3137
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:702
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:95
Game board class.
Definition: game_board.hpp:46
virtual const unit_map & units() const override
Definition: game_board.hpp:106
virtual const gamemap & map() const override
Definition: game_board.hpp:96
game_events::wml_event_pump & pump()
Definition: manager.cpp:253
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:399
map_location special_location(const std::string &id) const
Definition: map.cpp:311
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:384
bool is_village(const map_location &loc) const
Definition: map.cpp:65
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:74
int side() const
Definition: team.hpp:174
recall_list_manager & recall_list()
Definition: team.hpp:201
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:216
unit_iterator find(std::size_t id)
Definition: map.cpp:302
unit_iterator find_leader(int side)
Definition: map.cpp:320
This class represents a single unit of a specific type.
Definition: unit.hpp:133
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition: unit.hpp:201
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:29
Interfaces for manipulating version numbers of engine, add-ons, etc.
const std::string & type_id() const
The id of this unit's type.
Definition: unit.cpp:1949
int side() const
The side this unit belongs to.
Definition: unit.hpp:343
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:207
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:139
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:79
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:913
game_board * gameboard
Definition: resources.cpp:20
game_data * gamedata
Definition: resources.cpp:22
game_events::manager * game_events
Definition: resources.cpp:24
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
void unit_recruited(const map_location &loc, const map_location &leader_loc)
Definition: udisplay.cpp:800
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:273
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