33 #define ERR_NG LOG_STREAM(err, log_engine)
34 #define WRN_NG LOG_STREAM(warn, log_engine)
36 using namespace std::chrono_literals;
63 bool parity = (me.
x & 1) != 0;
66 if((a.
x > 0) && (a.
x % 2) && parity)
68 if((a.
x < 0) && (a.
x % 2) && !parity)
94 images_background.clear();
95 images_foreground.clear();
100 std::stable_sort(images.begin(), images.end());
101 sorted_images =
true;
105 bool is_background = ri->is_background();
106 bool animate = (!ri.ri->is_water ||
prefs::get().animate_water());
108 imagelist& img_list = is_background ? images_background : images_foreground;
112 bool has_flag_match =
true;
113 for(
const std::string&
s : variant.
has_flag) {
115 if(flags.find(
s) == flags.end()) {
116 has_flag_match =
false;
121 if(!has_flag_match) {
126 if(!variant.
tods.empty() && variant.
tods.find(tod) == variant.
tods.end())
131 unsigned int rnd = ri.rand / 7919;
134 bool is_empty =
true;
145 img_list.push_back(anim);
150 img_list.back().set_animation_time(std::chrono::milliseconds{ri.rand} % img_list.back().get_animation_duration());
152 img_list.back().set_animation_time(std::chrono::milliseconds{ri.rand} % variant.
random_start);
156 img_list.back().pause_animation();
160 log->emplace_back(&ri, &variant);
172 sorted_images =
false;
173 images_foreground.clear();
174 images_background.clear();
175 last_tod =
"invalid_tod";
180 unsigned int a = (loc.
x + 92872973) ^ 918273;
181 unsigned int b = (loc.
y + 1672517) ^ 128123;
182 unsigned int c = (
index + 127390) ^ 13923787;
183 unsigned int abc = a *
b *
c + a *
b +
b *
c + a *
c + a +
b +
c;
188 : tiles_((x + 4) * (y + 4))
205 std::vector<terrain_builder::tile> new_tiles(
static_cast<size_t>(x + 4) * (y + 4));
206 tiles_.swap(new_tiles);
212 if(loc.
x < -2 || loc.
y < -2 || loc.
x > (x_ + 1) || loc.
y > (y_ + 1)) {
223 return tiles_[(loc.
x + 2) + (loc.
y + 2) * (x_ + 4)];
230 return tiles_[(loc.
x + 2) + (loc.
y + 2) * (x_ + 4)];
261 for(
int x = -2; x <=
map().
w(); ++x) {
262 for(
int y = -2; y <=
map().
h(); ++y) {
316 if(!img_list.empty()) {
328 bool changed =
false;
364 if(
map().get_terrain_info(loc).is_combined()) {
367 if(!filename_ovl.empty()) {
386 bool precached = name.find(
"..") == std::string::npos;
397 static std::vector<std::string>
get_variations(
const std::string& base,
const std::string& variations)
400 std::vector<std::string> res;
401 if(variations.empty()) {
405 std::string::size_type pos = base.find(
"@V", 0);
406 if(pos == std::string::npos) {
410 std::vector<std::string> vars =
utils::split(variations,
';', 0);
412 for(
const std::string& v : vars) {
415 while((pos = res.back().find(
"@V", pos)) != std::string::npos) {
416 res.back().replace(pos, 2, v);
435 for(
const std::string& var : var_strings) {
440 for(
const std::string& frame : frames) {
441 const std::vector<std::string> items =
utils::split(frame,
':');
442 const std::string& str = items.front();
444 const std::size_t tilde = str.find(
'~');
445 bool has_tilde = tilde != std::string::npos;
446 const std::string
filename =
"terrain/" + (has_tilde ? str.substr(0, tilde) : str);
452 const std::string modif = (has_tilde ? str.substr(tilde + 1) :
"");
455 if(items.size() > 1) {
457 time = std::chrono::milliseconds{std::stoi(items.back())};
458 }
catch(
const std::invalid_argument&) {
459 ERR_NG <<
"Invalid 'time' value in terrain image builder: " << items.back();
472 variant.
images.push_back(std::move(res));
474 if(variant.
images.empty())
491 } rotations[6] {{1, 0, 0, 1}, {1, 1, -1, 0}, {0, 1, -1, -1}, {-1, 0, 0, -1}, {-1, -1, 1, 0}, {0, -1, 1, 1}};
528 { 1./2. , -3./4., 1., 1./2. },
529 { -1./2., -3./4., 1, -1./2.},
530 { -1. , 0., 0., -1. },
531 { -1./2., 3./4., -1., -1./2.},
532 { 1./2. , 3./4., -1., 1./2. },
543 int ri = rotations[angle].ii * vi + rotations[angle].ij * vj;
544 int rj = rotations[angle].ji * vi + rotations[angle].jj * vj;
547 ret.
loc.
y = ri + (rj >= 0 ? rj / 2 : (rj - 1) / 2);
550 double vx, vy, rx, ry;
552 vx =
static_cast<double>(itor->basex) -
static_cast<double>(
tilewidth_) / 2;
553 vy =
static_cast<double>(itor->basey) -
static_cast<double>(
tilewidth_) / 2;
555 rx = xyrotations[angle].xx * vx + xyrotations[angle].xy * vy;
556 ry = xyrotations[angle].yx * vx + xyrotations[angle].yy * vy;
558 itor->basex =
static_cast<int>(rx +
tilewidth_ / 2);
559 itor->basey =
static_cast<int>(ry +
tilewidth_ / 2);
565 std::string::size_type pos = 0;
566 while((pos =
s.find(
"@R", pos)) != std::string::npos) {
567 if(pos + 2 >=
s.size())
569 unsigned i =
s[pos + 2] -
'0' + angle;
576 const std::string& r = replacement[
i];
577 s.replace(pos, 3, r);
590 rule_imagelist& list,
int angle,
const std::vector<std::string>& replacement)
618 if(rot.size() != 6) {
619 ERR_NG <<
"invalid rotations";
628 int minx = std::numeric_limits<int>::max();
629 int miny = std::numeric_limits<int>::max();
632 minx = std::min<int>(cons.
loc.
x, minx);
633 miny = std::min<int>(2 * cons.
loc.
y + (cons.
loc.
x & 1), miny);
636 if((miny & 1) && (minx & 1) && (minx < 0))
638 if(!(miny & 1) && (minx & 1) && (minx > 0))
649 const std::string& variations,
650 const std::chrono::milliseconds& random_start)
651 : image_string(image_string)
652 , variations(variations)
656 , random_start(random_start)
661 const std::string& variations,
662 const std::string& tod,
663 const std::string& has_flag,
664 const std::chrono::milliseconds& random_start)
665 : image_string(image_string)
666 , variations(variations)
670 , random_start(random_start)
676 const std::vector<std::string> tod_list =
utils::split(tod);
677 tods.insert(tod_list.begin(), tod_list.end());
684 int layer =
img[
"layer"].to_int();
689 if(base.size() >= 2) {
691 basex = std::stoi(base[0]);
692 basey = std::stoi(base[1]);
693 }
catch(
const std::invalid_argument&) {
694 ERR_NG <<
"Invalid 'base' value in terrain image builder: " << base[0] <<
", " << base[1];
699 int center_x = -1, center_y = -1;
701 std::vector<std::string> center =
utils::split(*center_);
702 if(center.size() >= 2) {
704 center_x = std::stoi(center[0]);
705 center_y = std::stoi(center[1]);
706 }
catch(
const std::invalid_argument&) {
707 ERR_NG <<
"Invalid 'center' value in terrain image builder: " << center[0] <<
", " << center[1];
712 bool is_water =
img[
"is_water"].to_bool();
714 images.AGGREGATE_EMPLACE(layer, basex - dx, basey - dy, global, center_x, center_y, is_water);
717 for(
const config& variant :
img.child_range(
"variant")) {
718 const std::string& name = variant[
"name"];
719 const std::string& variations =
img[
"variations"];
720 const std::string& tod = variant[
"tod"];
721 const std::string& has_flag = variant[
"has_flag"];
724 int random_start = variant[
"random_start"].to_bool(
true) ? variant[
"random_start"].to_int(-1) : 0;
726 images.back().variants.emplace_back(name, variations, tod, has_flag, std::chrono::milliseconds{random_start});
731 const std::string& name =
img[
"name"];
732 const std::string& variations =
img[
"variations"];
734 int random_start =
img[
"random_start"].to_bool(
true) ?
img[
"random_start"].to_int(-1) : 0;
736 images.back().variants.emplace_back(name, variations, std::chrono::milliseconds{random_start});
743 const config& global_images)
755 constraints.AGGREGATE_EMPLACE(loc);
756 cons = &constraints.back();
759 if(!
type.terrain.empty()) {
773 const config& global_images)
780 constraint.
set_flag.insert(constraint.
set_flag.end(), item_string.begin(), item_string.end());
783 constraint.
has_flag.insert(constraint.
has_flag.end(), item_string.begin(), item_string.end());
786 constraint.
no_flag.insert(constraint.
no_flag.end(), item_string.begin(), item_string.end());
789 constraint.
set_flag.insert(constraint.
set_flag.end(), item_string.begin(), item_string.end());
790 constraint.
no_flag.insert(constraint.
no_flag.end(), item_string.begin(), item_string.end());
792 constraint.
no_draw = cfg[
"no_draw"].to_bool(
false);
812 for(
int y_off = 0; y_off <
map.
w; ++y_off) {
813 for(
int x_off = x; x_off <
map.
h; ++x_off) {
819 }
else if(terrain.
overlay != 0) {
831 if(lineno % 2 == 1) {
850 if(rotations.empty()) {
855 const std::vector<std::string>& rot =
utils::split(rotations,
',');
857 for(std::size_t angle = 0; angle < rot.size(); ++angle) {
866 if(rot.at(angle) ==
"skip") {
884 log_scope(
"terrain_builder::parse_config");
907 for(
const config& tc :
br.child_range(
"tile")) {
921 int pos = v->to_int();
922 if(anchors.find(pos) == anchors.end()) {
923 WRN_NG <<
"Invalid anchor!";
927 std::pair<anchormap::const_iterator, anchormap::const_iterator> range = anchors.equal_range(pos);
929 for(; range.first != range.second; ++range.first) {
930 loc = range.first->second;
936 const std::vector<std::string> global_set_flag =
utils::split(
br[
"set_flag"]);
937 const std::vector<std::string> global_no_flag =
utils::split(
br[
"no_flag"]);
938 const std::vector<std::string> global_has_flag =
utils::split(
br[
"has_flag"]);
939 const std::vector<std::string> global_set_no_flag =
utils::split(
br[
"set_no_flag"]);
942 constraint.
set_flag.insert(constraint.
set_flag.end(), global_set_flag.begin(), global_set_flag.end());
943 constraint.
no_flag.insert(constraint.
no_flag.end(), global_no_flag.begin(), global_no_flag.end());
944 constraint.
has_flag.insert(constraint.
has_flag.end(), global_has_flag.begin(), global_has_flag.end());
945 constraint.
set_flag.insert(constraint.
set_flag.end(), global_set_no_flag.begin(), global_set_no_flag.end());
946 constraint.
no_flag.insert(constraint.
no_flag.end(), global_set_no_flag.begin(), global_set_no_flag.end());
950 const std::string& rotations =
br[
"rotations"];
966 building_ruleset::const_iterator rule;
968 PLAIN_LOG <<
">> New rule: image_background = "
969 <<
"\n>> Location " << rule->second.location_constraints
970 <<
"\n>> Probability " << rule->second.probability
972 for(constraint_set::const_iterator constraint = rule->second.constraints.begin();
973 constraint != rule->second.constraints.end(); ++constraint) {
975 PLAIN_LOG <<
">>>> New constraint: location = (" << constraint->second.loc
978 std::vector<std::string>::const_iterator
flag;
980 for(
flag = constraint->second.set_flag.begin();
flag != constraint->second.set_flag.end(); ++
flag) {
984 for(
flag = constraint->second.no_flag.begin();
flag != constraint->second.no_flag.end(); ++
flag) {
1005 config& tile_image =
tile.add_child(
"image");
1006 tile_image[
"layer"] = -1000;
1007 tile_image[
"name"] =
image;
1009 item[
"probability"] = 100;
1010 item[
"no_flag"] =
"base";
1011 item[
"set_flag"] =
"base";
1035 if(random >
static_cast<unsigned int>(rule.
probability)) {
1055 const std::set<std::string>& flags =
tile_map_[tloc].flags;
1057 for(
const std::string&
s : cons.
no_flag) {
1059 if(flags.find(
s) != flags.end()) {
1063 for(
const std::string&
s : cons.
has_flag) {
1065 if(flags.find(
s) == flags.end()) {
1088 btile.
images.AGGREGATE_EMPLACE(&
img, rand_seed);
1105 for(std::string::const_iterator it = str.begin(), it_end = str.end(); it != it_end; ++it)
1106 h = ((
h << 9) | (
h >> (
sizeof(
int) * 8 - 9))) ^ (*it);
1116 for(
const rule_image& ri : constraint.images) {
1133 log_scope(
"terrain_builder::build_terrains");
1136 for(
int x = -2; x <=
map().
w(); ++x) {
1137 for(
int y = -2; y <=
map().
h(); ++y) {
1157 std::size_t
min_size = std::numeric_limits<int>::max();
1167 std::size_t constraint_size = 0;
1173 const std::size_t match_size = type_it->second.size();
1174 constraint_size += match_size;
1178 matching_types.push_back(
t);
1184 min_types = matching_types;
1185 min_constraint = &constraint;
1194 assert(min_constraint !=
nullptr);
1197 for(t_translation::ter_list::const_iterator
t = min_types.begin();
t != min_types.end(); ++
t) {
1200 for(std::vector<map_location>::const_iterator itor = locations->begin(); itor != locations->end(); ++itor) {
static map_location legacy_negation(const map_location &me)
These legacy map_location functions moved here from map_location.
static lg::log_domain log_engine("engine")
static std::vector< std::string > get_variations(const std::string &base, const std::string &variations)
static unsigned int hash_str(const std::string &str)
static unsigned int get_noise(const map_location &loc, unsigned int index)
static map_location & legacy_sum_assign(map_location &me, const map_location &a)
static map_location legacy_sum(const map_location &me, const map_location &a)
static bool image_exists(const std::string &name)
static map_location legacy_difference(const map_location &me, const map_location &a)
Definitions for the terrain builder.
const T & get_frame(std::size_t n) const
void start_animation(const std::chrono::milliseconds &start_time, bool cycles=false)
Starts an animation cycle.
void add_frame(const std::chrono::milliseconds &duration, const T &value, bool force_change=false)
Adds a frame to an animation.
void update_last_draw_time(double acceleration=0)
std::size_t get_frames_count() const
std::chrono::milliseconds get_animation_duration() const
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
child_itors child_range(config_key_type key)
config & add_child(config_key_type key)
A class grating read only view to a vector of config objects, viewed as one config with all children ...
static game_config_view wrap(const config &cfg)
config_array_view child_range(config_key_type key) const
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
int w() const
Effective map width.
int h() const
Effective map height.
bool empty() const
Tell if the map is of 0 size.
Encapsulates the map of the game.
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
static void progress(loading_stage stage=loading_stage::none)
Report what is being loaded to the loading screen.
Generic locator abstracting the location of an image.
tile & operator[](const map_location &loc)
Returns a reference to the tile which is at the position pointed by loc.
bool on_map(const map_location &loc) const
Tests if a location is on the map.
void reset()
Resets the whole tile map.
tilemap(int x, int y)
Constructs a tilemap of dimensions x * y.
void reload(int x, int y)
Rebuilds the map to a new set of dimensions.
void parse_mapstring(const std::string &mapstring, struct building_rule &br, anchormap &anchors, const config &global_images)
Parses a map string (the map= element of a [terrain_graphics] rule, and adds constraints from this ma...
std::vector< animated< image::locator > > imagelist
A shorthand typedef for a list of animated image locators, the base data type returned by the get_ter...
std::multiset< building_rule > building_ruleset
A set of building rules.
void parse_config(const config &cfg, bool local=true)
Parses a configuration object containing [terrain_graphics] rules, and fills the building_rules_ memb...
tile * get_tile(const map_location &loc)
void add_rule(building_ruleset &rules, building_rule &rule)
Adds a rule to a ruleset.
terrain_constraint & add_constraints(constraint_set &constraints, const map_location &loc, const t_translation::ter_match &type, const config &global_images)
Creates a rule constraint object which matches a given list of terrains, and adds it to the list of c...
void rotate_rule(building_rule &rule, int angle, const std::vector< std::string > &angle_name)
Rotates a template rule to a given angle.
bool draw_border_
Whether the map border should be drawn.
void add_off_map_rule(const std::string &image)
Adds a builder rule for the _off^_usr tile, this tile only has 1 image.
void build_terrains()
Calculates the list of terrains, and fills the tile_map_ member, from the gamemap and the building_ru...
void add_images_from_config(rule_imagelist &images, const config &cfg, bool global, int dx=0, int dy=0)
Parses a "config" object, which should contains [image] children, and adds the corresponding parsed r...
void rebuild_terrain(const map_location &loc)
Performs a "quick-rebuild" of the terrain in a given location.
bool update_animation(const map_location &loc)
Updates the animation at a given tile.
static building_ruleset building_rules_
Parsed terrain rules.
const gamemap & map() const
static const unsigned int DUMMY_HASH
bool rule_matches(const building_rule &rule, const map_location &loc, const terrain_constraint *type_checked) const
Checks whether a rule matches a given location in the map.
void change_map(const gamemap *m)
static void set_terrain_rules_cfg(const game_config_view &cfg)
Set the config where we will parse the global terrain rules.
std::vector< terrain_constraint > constraint_set
The list of constraints attached to a terrain_graphics WML rule.
const int tilewidth_
The tile width used when using basex and basey.
const gamemap * map_
A pointer to the gamemap class used in the current level.
bool terrain_matches(const t_translation::terrain_code &tcode, const t_translation::ter_list &terrains) const
Checks whether a terrain code matches a given list of terrain codes.
const imagelist * get_terrain_at(const map_location &loc, const std::string &tod, TERRAIN_TYPE const terrain_type)
Returns a vector of strings representing the images to load & blit together to get the built content ...
bool load_images(building_rule &rule)
Load images and tests for validity of a rule.
tilemap tile_map_
The tile_map_ for the current level, which is filled by the build_terrains_ method to contain "tiles"...
void apply_rule(const building_rule &rule, const map_location &loc)
Applies a rule at a given location: applies the result of a matching rule at a given location: attach...
void rotate(terrain_constraint &constraint, int angle)
"Rotates" a constraint from a rule.
void rebuild_all()
Performs a complete rebuild of the list of terrain graphics attached to a map.
std::multimap< int, map_location > anchormap
void add_rotated_rules(building_ruleset &rules, building_rule &tpl, const std::string &rotations)
Adds a set of rules to a ruleset, from a template rule which spans 6 rotations (or less if some of th...
TERRAIN_TYPE
Used as a parameter for the get_terrain_at function.
@ BACKGROUND
Represents terrains which are to be drawn behind unit sprites.
std::vector< rule_image > rule_imagelist
A shorthand notation for a vector of rule_images.
terrain_by_type_map terrain_by_type_
A map representing all locations whose terrain is of a given type.
static const game_config_view * rules_cfg_
Config used to parse global terrain rules.
void parse_global_config(const game_config_view &cfg)
void reload_map()
Updates internals that cache map size.
void replace_rotate_tokens(std::string &s, int angle, const std::vector< std::string > &replacement)
Replaces, in a given string, rotation tokens with their values.
terrain_builder(const config &level, const gamemap *map, const std::string &offmap_image, bool draw_border)
Constructor for the terrain_builder class.
const std::string & minimap_image() const
const std::string & minimap_image_overlay() const
void swap(config &lhs, config &rhs)
Implement non-member swap function for std::swap (calls config::swap).
Standard logging facilities (interface).
#define log_scope(description)
Game configuration data as global variables.
Functions to load and save images from/to disk.
bool is_empty_hex(const locator &i_locator)
Checks if an image is empty after hex masking.
bool precached_file_exists(const std::string &file)
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
void precache_file_existence(const std::string &subdir)
Precache the existence of files in a binary path subdirectory (e.g.
static const std::string br
std::string img(const std::string &src, const std::string &align, const bool floating)
std::vector< terrain_code > ter_list
ter_map read_builder_map(const std::string &str)
Reads a builder map.
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
const terrain_code OFF_MAP_USER
std::string write_list(const ter_list &list)
Writes a list of terrains to a string, only writes the new format.
const terrain_code NONE_TERRAIN
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::vector< std::string > square_parenthetical_split(const std::string &val, const char separator, const std::string &left, const std::string &right, const int flags)
Similar to parenthetical_split, but also expands embedded square brackets.
std::vector< std::string > split(const config_attribute_value &val)
std::string::const_iterator iterator
std::string filename
Filename.
Encapsulates the map of the game.
This structure can be used for matching terrain strings.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
The in-memory representation of a [terrain_graphics] WML rule.
int precedence
Ordering relation between the rules.
map_location modulo_constraints
Used to constrain locations to ones with coordinates that are multiples of the "mod_x" and "mod_y" pa...
map_location location_constraints
The location on which this map may match.
int probability
The probability of this rule to match, when all conditions are met.
unsigned int get_hash() const
constraint_set constraints
The set of [tile] constraints of this rule.
std::vector< std::string > has_flag
rule_image_variant(const std::string &image_string, const std::string &variations, const std::chrono::milliseconds &random_start=std::chrono::milliseconds{-1})
Constructor for the normal default case.
std::chrono::milliseconds random_start
Specify the allowed amount of random shift (in milliseconds) applied to the animation start time,...
std::vector< animated< image::locator > > images
An animated image locator built according to the image string.
std::set< std::string > tods
The Time of Day associated to this variant (if any)
std::string image_string
A string representing either the filename for an image, or a list of images, with an optional timing ...
std::string variations
A semi-solon separated list of string used to replace.
Each terrain_graphics rule is associated a set of images, which are applied on the terrain if the rul...
bool global_image
Set to true if the image was defined as a child of the [terrain_graphics] tag, set to false if it was...
std::vector< rule_image_variant > variants
A list of variants for this image.
int center_x
The position where the center of the image base should be.
The in-memory representation of a [tile] WML rule inside of a [terrain_graphics] WML rule.
t_translation::ter_match terrain_types_match
std::vector< std::string > set_flag
std::vector< std::string > has_flag
bool no_draw
Whether to actually draw the images onto this hex or not.
std::vector< std::string > no_flag
Represent a rule_image applied with a random seed.
Represents a tile of the game map, with all associated builder-specific parameters: flags,...
std::string last_tod
The time-of-day to which the image caches correspond.
std::vector< rule_image_rand > images
The list of rule_images and random seeds associated to this tile.
std::vector< log_details > logs
void clear()
Clears all data in this tile, and resets the cache.
void rebuild_cache(const std::string &tod, logs *log=nullptr)
Rebuilds the whole image cache, for a given time-of-day.
imagelist images_background
The list of images which are behind the unit sprites, attached to this tile.
imagelist images_foreground
The list of images which are in front of the unit sprites, attached to this tile.
std::set< std::string > flags
The list of flags present in this tile.
static map_location::direction n
static map_location::direction s