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().apply_time_offset(std::chrono::milliseconds{ri.rand} % img_list.back().get_animation_duration());
152 img_list.back().apply_time_offset(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<std::size_t
>(x + 4) * (y + 4));
206 tiles_.swap(new_tiles);
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) {
313 if(!img_list.empty()) {
325 bool changed =
false;
363 if(
map().get_terrain_info(
loc).is_combined()) {
366 if(!filename_ovl.empty()) {
385 bool precached = name.find(
"..") == std::string::npos;
396 static std::vector<std::string>
get_variations(
const std::string& base,
const std::string& variations)
399 std::vector<std::string> res;
400 if(variations.empty()) {
404 std::string::size_type pos = base.find(
"@V", 0);
405 if(pos == std::string::npos) {
409 std::vector<std::string> vars =
utils::split(variations,
';', 0);
411 for(
const std::string& v : vars) {
414 while((pos = res.back().find(
"@V", pos)) != std::string::npos) {
415 res.back().replace(pos, 2, v);
434 for(
const std::string& var : var_strings) {
439 for(
const std::string& frame : frames) {
440 const std::vector<std::string> items =
utils::split(frame,
':');
441 const std::string& str = items.front();
443 const std::size_t tilde = str.find(
'~');
444 bool has_tilde = tilde != std::string::npos;
445 const std::string
filename =
"terrain/" + (has_tilde ? str.substr(0, tilde) : str);
451 const std::string modif = (has_tilde ? str.substr(tilde + 1) :
"");
454 if(items.size() > 1) {
456 time = std::chrono::milliseconds{
std::stoi(items.back())};
457 }
catch(
const std::invalid_argument&) {
458 ERR_NG <<
"Invalid 'time' value in terrain image builder: " << items.back();
471 variant.
images.push_back(std::move(res));
473 if(variant.
images.empty())
490 } 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}};
527 { 1./2. , -3./4., 1., 1./2. },
528 { -1./2., -3./4., 1, -1./2.},
529 { -1. , 0., 0., -1. },
530 { -1./2., 3./4., -1., -1./2.},
531 { 1./2. , 3./4., -1., 1./2. },
542 int ri = rotations[angle].ii * vi + rotations[angle].ij * vj;
543 int rj = rotations[angle].ji * vi + rotations[angle].jj * vj;
546 ret.
loc.
y = ri + (rj >= 0 ? rj / 2 : (rj - 1) / 2);
549 double vx, vy, rx, ry;
551 vx =
static_cast<double>(itor->basex) -
static_cast<double>(
tilewidth_) / 2;
552 vy =
static_cast<double>(itor->basey) -
static_cast<double>(
tilewidth_) / 2;
554 rx = xyrotations[angle].xx * vx + xyrotations[angle].xy * vy;
555 ry = xyrotations[angle].yx * vx + xyrotations[angle].yy * vy;
557 itor->basex =
static_cast<int>(rx +
tilewidth_ / 2);
558 itor->basey =
static_cast<int>(ry +
tilewidth_ / 2);
564 std::string::size_type pos = 0;
565 while((pos =
s.find(
"@R", pos)) != std::string::npos) {
566 if(pos + 2 >=
s.size())
568 unsigned i =
s[pos + 2] -
'0' + angle;
575 const std::string& r = replacement[
i];
576 s.replace(pos, 3, r);
589 rule_imagelist& list,
int angle,
const std::vector<std::string>& replacement)
617 if(rot.size() != 6) {
618 ERR_NG <<
"invalid rotations";
627 int minx = std::numeric_limits<int>::max();
628 int miny = std::numeric_limits<int>::max();
631 minx = std::min<int>(cons.
loc.
x, minx);
632 miny = std::min<int>(2 * cons.
loc.
y + (cons.
loc.
x & 1), miny);
635 if((miny & 1) && (minx & 1) && (minx < 0))
637 if(!(miny & 1) && (minx & 1) && (minx > 0))
648 const std::string& variations,
649 const std::chrono::milliseconds& random_start)
650 : image_string(image_string)
651 , variations(variations)
655 , random_start(random_start)
660 const std::string& variations,
661 const std::string& tod,
662 const std::string& has_flag,
663 const std::chrono::milliseconds& random_start)
664 : image_string(image_string)
665 , variations(variations)
669 , random_start(random_start)
675 const std::vector<std::string> tod_list =
utils::split(tod);
676 tods.insert(tod_list.begin(), tod_list.end());
683 int layer =
img[
"layer"].to_int();
688 if(base.size() >= 2) {
692 }
catch(
const std::invalid_argument&) {
693 ERR_NG <<
"Invalid 'base' value in terrain image builder: " << base[0] <<
", " << base[1];
698 int center_x = -1, center_y = -1;
700 std::vector<std::string> center =
utils::split(*center_);
701 if(center.size() >= 2) {
705 }
catch(
const std::invalid_argument&) {
706 ERR_NG <<
"Invalid 'center' value in terrain image builder: " << center[0] <<
", " << center[1];
711 bool is_water =
img[
"is_water"].to_bool();
713 images.AGGREGATE_EMPLACE(layer, basex - dx, basey - dy, global, center_x, center_y, is_water);
716 for(
const config& variant :
img.child_range(
"variant")) {
717 const std::string& name = variant[
"name"];
718 const std::string& variations =
img[
"variations"];
719 const std::string& tod = variant[
"tod"];
720 const std::string& has_flag = variant[
"has_flag"];
723 int random_start = variant[
"random_start"].to_bool(
true) ? variant[
"random_start"].to_int(-1) : 0;
725 images.back().variants.emplace_back(name, variations, tod, has_flag, std::chrono::milliseconds{random_start});
730 const std::string& name =
img[
"name"];
731 const std::string& variations =
img[
"variations"];
733 int random_start =
img[
"random_start"].to_bool(
true) ?
img[
"random_start"].to_int(-1) : 0;
735 images.back().variants.emplace_back(name, variations, std::chrono::milliseconds{random_start});
742 const config& global_images)
754 constraints.AGGREGATE_EMPLACE(
loc);
755 cons = &constraints.back();
758 if(!
type.terrain.empty()) {
772 const config& global_images)
779 constraint.
set_flag.insert(constraint.
set_flag.end(), item_string.begin(), item_string.end());
782 constraint.
has_flag.insert(constraint.
has_flag.end(), item_string.begin(), item_string.end());
785 constraint.
no_flag.insert(constraint.
no_flag.end(), item_string.begin(), item_string.end());
788 constraint.
set_flag.insert(constraint.
set_flag.end(), item_string.begin(), item_string.end());
789 constraint.
no_flag.insert(constraint.
no_flag.end(), item_string.begin(), item_string.end());
791 constraint.
no_draw =
cfg[
"no_draw"].to_bool(
false);
811 for(
int y_off = 0; y_off <
map.
w; ++y_off) {
812 for(
int x_off = x; x_off <
map.
h; ++x_off) {
818 }
else if(terrain.
overlay != 0) {
830 if(lineno % 2 == 1) {
849 if(rotations.empty()) {
854 const std::vector<std::string>& rot =
utils::split(rotations,
',');
856 for(std::size_t angle = 0; angle < rot.size(); ++angle) {
865 if(rot.at(angle) ==
"skip") {
883 log_scope(
"terrain_builder::parse_config");
920 int pos = v->to_int();
921 if(anchors.find(pos) == anchors.end()) {
922 WRN_NG <<
"Invalid anchor!";
926 auto range = anchors.equal_range(pos);
928 for(; range.first != range.second; ++range.first) {
929 loc = range.first->second;
935 const std::vector<std::string> global_set_flag =
utils::split(br[
"set_flag"]);
936 const std::vector<std::string> global_no_flag =
utils::split(br[
"no_flag"]);
937 const std::vector<std::string> global_has_flag =
utils::split(br[
"has_flag"]);
938 const std::vector<std::string> global_set_no_flag =
utils::split(br[
"set_no_flag"]);
941 constraint.
set_flag.insert(constraint.
set_flag.end(), global_set_flag.begin(), global_set_flag.end());
942 constraint.
no_flag.insert(constraint.
no_flag.end(), global_no_flag.begin(), global_no_flag.end());
943 constraint.
has_flag.insert(constraint.
has_flag.end(), global_has_flag.begin(), global_has_flag.end());
944 constraint.
set_flag.insert(constraint.
set_flag.end(), global_set_no_flag.begin(), global_set_no_flag.end());
945 constraint.
no_flag.insert(constraint.
no_flag.end(), global_set_no_flag.begin(), global_set_no_flag.end());
949 const std::string& rotations = br[
"rotations"];
965 building_ruleset::const_iterator rule;
967 PLAIN_LOG <<
">> New rule: image_background = "
968 <<
"\n>> Location " << rule->second.location_constraints
969 <<
"\n>> Probability " << rule->second.probability
971 for(constraint_set::const_iterator constraint = rule->second.constraints.begin();
972 constraint != rule->second.constraints.end(); ++constraint) {
974 PLAIN_LOG <<
">>>> New constraint: location = (" << constraint->second.loc
977 std::vector<std::string>::const_iterator
flag;
979 for(
flag = constraint->second.set_flag.begin();
flag != constraint->second.set_flag.end(); ++
flag) {
983 for(
flag = constraint->second.no_flag.begin();
flag != constraint->second.no_flag.end(); ++
flag) {
1004 config& tile_image =
tile.add_child(
"image");
1005 tile_image[
"layer"] = -1000;
1006 tile_image[
"name"] =
image;
1008 item[
"probability"] = 100;
1009 item[
"no_flag"] =
"base";
1010 item[
"set_flag"] =
"base";
1034 if(random >
static_cast<unsigned int>(rule.
probability)) {
1054 const std::set<std::string>& flags =
tile_map_[tloc].flags;
1056 for(
const std::string&
s : cons.
no_flag) {
1058 if(flags.find(
s) != flags.end()) {
1062 for(
const std::string&
s : cons.
has_flag) {
1064 if(flags.find(
s) == flags.end()) {
1087 btile.
images.AGGREGATE_EMPLACE(&
img, rand_seed);
1104 for(std::string::const_iterator it = str.begin(), it_end = str.end(); it != it_end; ++it)
1105 h = ((
h << 9) | (
h >> (
sizeof(
int) * 8 - 9))) ^ (*it);
1115 for(
const rule_image& ri : constraint.images) {
1132 log_scope(
"terrain_builder::build_terrains");
1135 for(
int x = -2; x <=
map().
w(); ++x) {
1136 for(
int y = -2; y <=
map().
h(); ++y) {
1156 std::size_t min_size = std::numeric_limits<int>::max();
1166 std::size_t constraint_size = 0;
1172 const std::size_t match_size = type_it->second.size();
1173 constraint_size += match_size;
1174 if(constraint_size >= min_size) {
1177 matching_types.push_back(
t);
1181 if(constraint_size < min_size) {
1182 min_size = constraint_size;
1183 min_types = matching_types;
1184 min_constraint = &constraint;
1193 assert(min_constraint !=
nullptr);
1196 for(
const auto&
t : min_types) {
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 add_frame(const std::chrono::milliseconds &duration, const T &value, bool force_change=false)
Appends a frame, starting where the previous one ends (or at start_time, if first).
void start_animation(const std::chrono::milliseconds &start_time_offset, bool cycles=false)
Anchors the timeline to the current tick, then begins playback.
bool need_update() const
True once the current tick has reached the current frame's end, meaning advance_to_current_frame() ha...
std::size_t get_frames_count() const
std::chrono::milliseconds get_animation_duration() const
get_end_time() minus get_begin_time(): how long one pass through all frames takes.
void advance_to_current_frame()
Moves current_frame_index_ forward to match the current tick, one frame at a time (or in whole cycles...
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
config & add_child(std::string_view key)
child_itors child_range(std::string_view 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)
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
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.
std::string img(const std::string &src, const std::string &align, bool floating)
Generates a Help markup tag corresponding to an image.
constexpr terrain_code NONE_TERRAIN
constexpr ter_layer WILDCARD
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.
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
int stoi(std::string_view str)
Same interface as std::stoi and meant as a drop in replacement, except:
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