The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
unit_creator.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
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
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"
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
41static 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{
71 return *this;
72}
73
74
76{
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{
98 return *this;
99}
100
101
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 {
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::FOR_REMOVAL, {1, 21, 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()) {
144 }
145 if(place == "map_passable") {
146 deprecated_message("placement=map_passable", DEP_LEVEL::FOR_REMOVAL, {1, 21, 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::FOR_REMOVAL, {1, 21, 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) {
156 loc = find_vacant_tile(loc, pathfind::VACANT_ANY,
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
170void 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 prefs::get().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
216void unit_creator::post_create(const map_location &loc, const unit &new_unit, bool anim, bool fire_event)
217{
218
219 if (discover_) {
220 prefs::get().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}
map_location loc
Definition move.cpp:172
Various functions related to moving units.
#define DBG_NG
#define LOG_NG
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
void remove_attribute(std::string_view key)
Definition config.cpp:162
const attribute_value * get(std::string_view key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition config.cpp:665
bool has_attribute(std::string_view key) const
Definition config.cpp:157
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition display.cpp:2927
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition display.cpp:669
static display * get_singleton()
Returns the display object if a display object exists.
Definition display.hpp:102
Game board class.
virtual const gamemap & map() const override
virtual const unit_map & units() const override
game_events::wml_event_pump & pump()
Definition manager.cpp:257
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:274
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition map.cpp:347
bool is_village(const map_location &loc) const
Definition map.cpp:60
static prefs & get()
std::set< std::string > & encountered_units()
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:182
recall_list_manager & recall_list()
Definition team.hpp:242
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_
unit_iterator find(std::size_t id)
Definition map.cpp:302
umap_retval_pair_t replace(const map_location &l, const unit_ptr &p)
Works like unit_map::add; but l is emptied first, if needed.
Definition map.cpp:216
unit_iterator find_leader(int side)
Definition map.cpp:320
This class represents a single unit of a specific type.
Definition unit.hpp:39
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
Definition unit.hpp:107
A variable-expanding proxy for the config class.
Definition variable.hpp:45
Definitions for the interface to Wesnoth Markup Language (WML).
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
map_display and display: classes which take care of displaying the map and game-data on the screen.
const config * cfg
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:1964
int side() const
The side this unit belongs to.
Definition unit.hpp:249
std::string id
Text to match against addon_info.tags()
Definition manager.cpp:199
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:221
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:798
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:46
bool valid() const
Definition location.hpp:111
static const map_location & null_location()
Definition location.hpp:103
bool valid() const
Definition map.hpp:273
Display units performing various actions: moving, attacking, and dying.
static lg::log_domain log_engine("engine")
Various functions related to the creation of units (recruits, recalls, and placed units).
#define b