The Battle for Wesnoth  1.17.4+dev
builder.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2004 - 2022
3  by Philippe Plantier <ayin@anathas.org>
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  * Terrain builder.
19  */
20 
21 #include "terrain/builder.hpp"
22 
24 #include "picture.hpp"
25 #include "log.hpp"
26 #include "map/map.hpp"
27 #include "preferences/game.hpp"
29 #include "game_config_view.hpp"
30 
31 static lg::log_domain log_engine("engine");
32 #define ERR_NG LOG_STREAM(err, log_engine)
33 #define WRN_NG LOG_STREAM(warn, log_engine)
34 
35 /**
36  *
37  * These legacy map_location functions moved here from map_location.?pp.
38  * We have refactored them out of everything but this class. Hopefully
39  * the end is near...
40  *
41  // Adds an absolute location to a "delta" location
42  // This is not the mathematically correct behavior, it is neither
43  // commutative nor associative. Negative coordinates may give strange
44  // results. It is retained because terrain builder code relies in this
45  // broken behavior. Best avoid.
46  map_location legacy_negation() const;
47  map_location legacy_sum(const map_location &a) const;
48  map_location& legacy_sum_assign(const map_location &a);
49  map_location legacy_difference(const map_location &a) const;
50  *
51  */
52 
54 {
55  return map_location(-me.x, -me.y);
56 }
57 
59 {
60  bool parity = (me.x & 1) != 0;
61  me.x += a.x;
62  me.y += a.y;
63  if((a.x > 0) && (a.x % 2) && parity)
64  me.y++;
65  if((a.x < 0) && (a.x % 2) && !parity)
66  me.y--;
67 
68  return me;
69 }
70 
72 {
73  map_location ret(me);
74  legacy_sum_assign(ret, a);
75  return ret;
76 }
77 
79 {
80  return legacy_sum(me, legacy_negation(a));
81 }
82 
83 /**
84  *
85  * This file holds the terrain_builder implementation.
86  *
87  */
88 
89 terrain_builder::rule_image::rule_image(int layer, int x, int y, bool global_image, int cx, int cy, bool is_water)
90  : layer(layer)
91  , basex(x)
92  , basey(y)
93  , variants()
94  , global_image(global_image)
95  , center_x(cx)
96  , center_y(cy)
97  , is_water(is_water)
98 {
99 }
100 
102  : flags()
103  , images()
104  , images_foreground()
105  , images_background()
106  , last_tod("invalid_tod")
107  , sorted_images(false)
108 {
109 }
110 
111 void terrain_builder::tile::rebuild_cache(const std::string& tod, logs* log)
112 {
113  images_background.clear();
114  images_foreground.clear();
115 
116  if(!sorted_images) {
117  // sort images by their layer (and basey)
118  // but use stable to keep the insertion order in equal cases
119  std::stable_sort(images.begin(), images.end());
120  sorted_images = true;
121  }
122 
123  for(const rule_image_rand& ri : images) {
124  bool is_background = ri->is_background();
125  bool animate = (!ri.ri->is_water || preferences::animate_water());
126 
127  imagelist& img_list = is_background ? images_background : images_foreground;
128 
129  for(const rule_image_variant& variant : ri->variants) {
130  if(!variant.has_flag.empty()) {
131  bool has_flag_match = true;
132  for(const std::string& s : variant.has_flag) {
133  // If a flag listed in "has_flag" is not present, this variant does not match
134  if(flags.find(s) == flags.end()) {
135  has_flag_match = false;
136  break;
137  }
138  }
139 
140  if(!has_flag_match) {
141  continue;
142  }
143  }
144 
145  if(!variant.tods.empty() && variant.tods.find(tod) == variant.tods.end())
146  continue;
147 
148  // need to break parity pattern in RNG
149  /** @todo improve this */
150  unsigned int rnd = ri.rand / 7919; // just the 1000th prime
151  const animated<image::locator>& anim = variant.images[rnd % variant.images.size()];
152 
153  bool is_empty = true;
154  for(std::size_t i = 0; i < anim.get_frames_count(); ++i) {
155  if(!image::is_empty_hex(anim.get_frame(i))) {
156  is_empty = false;
157  break;
158  }
159  }
160 
161  if(is_empty)
162  continue;
163 
164  img_list.push_back(anim);
165 
166  assert(anim.get_animation_duration() != 0);
167 
168  if(variant.random_start < 0)
169  img_list.back().set_animation_time(ri.rand % img_list.back().get_animation_duration());
170  else if(variant.random_start > 0)
171  img_list.back().set_animation_time(ri.rand % variant.random_start);
172 
173  if(!animate) {
174  img_list.back().pause_animation();
175  }
176 
177  if(log) {
178  log->emplace_back(&ri, &variant);
179  }
180 
181  break; // found a matching variant
182  }
183  }
184 }
185 
187 {
188  flags.clear();
189  images.clear();
190  sorted_images = false;
191  images_foreground.clear();
192  images_background.clear();
193  last_tod = "invalid_tod";
194 }
195 
196 static unsigned int get_noise(const map_location& loc, unsigned int index)
197 {
198  unsigned int a = (loc.x + 92872973) ^ 918273;
199  unsigned int b = (loc.y + 1672517) ^ 128123;
200  unsigned int c = (index + 127390) ^ 13923787;
201  unsigned int abc = a * b * c + a * b + b * c + a * c + a + b + c;
202  return abc * abc;
203 }
204 
206 {
207  for(std::vector<tile>::iterator it = tiles_.begin(); it != tiles_.end(); ++it)
208  it->clear();
209 }
210 
212 {
213  x_ = x;
214  y_ = y;
215  std::vector<terrain_builder::tile> new_tiles((x + 4) * (y + 4));
216  tiles_.swap(new_tiles);
217  reset();
218 }
219 
221 {
222  if(loc.x < -2 || loc.y < -2 || loc.x > (x_ + 1) || loc.y > (y_ + 1)) {
223  return false;
224  }
225 
226  return true;
227 }
228 
230 {
231  assert(on_map(loc));
232 
233  return tiles_[(loc.x + 2) + (loc.y + 2) * (x_ + 4)];
234 }
235 
237 {
238  assert(on_map(loc));
239 
240  return tiles_[(loc.x + 2) + (loc.y + 2) * (x_ + 4)];
241 }
242 
243 terrain_builder::terrain_builder(const config& level, const gamemap* m, const std::string& offmap_image, bool draw_border)
245  , map_(m)
246  , tile_map_(m ? map().w() : 0, m ? map().h() : 0)
247  , terrain_by_type_()
248  , draw_border_(draw_border)
249 {
250  image::precache_file_existence("terrain/");
251 
252  if(building_rules_.empty() && rules_cfg_) {
253  // off_map first to prevent some default rule seems to block it
254  add_off_map_rule(offmap_image);
255  // parse global terrain rules
257  } else {
258  // use cached global rules but clear local rules
260  }
261 
262  // parse local rules
263  parse_config(level);
264 
265  if(m)
266  build_terrains();
267 }
268 
270 {
271  for(int x = -2; x <= map().w(); ++x) {
272  for(int y = -2; y <= map().h(); ++y) {
273  tile_map_[map_location(x, y)].rebuild_cache("");
274  }
275  }
276 }
277 
279 {
281  for(; i != building_rules_.end();) {
282  if(i->local)
283  building_rules_.erase(i++);
284  else
285  ++i;
286  }
287 }
288 
290 {
291  rules_cfg_ = &cfg;
292  // use the swap trick to clear the rules cache and get a fresh one.
293  // because simple clear() seems to cause some progressive memory degradation.
294  building_ruleset empty;
295  std::swap(building_rules_, empty);
296 }
297 
299 {
300  tile_map_.reload(map().w(), map().h());
301  terrain_by_type_.clear();
302  build_terrains();
303 }
304 
306 {
307  map_ = m;
308  reload_map();
309 }
310 
312  const map_location& loc, const std::string& tod, const TERRAIN_TYPE terrain_type)
313 {
314  if(!tile_map_.on_map(loc))
315  return nullptr;
316 
317  tile& tile_at = tile_map_[loc];
318 
319  if(tod != tile_at.last_tod) {
320  tile_at.rebuild_cache(tod);
321  tile_at.last_tod = tod;
322  }
323 
324  const imagelist& img_list = (terrain_type == BACKGROUND) ? tile_at.images_background : tile_at.images_foreground;
325 
326  if(!img_list.empty()) {
327  return &img_list;
328  }
329 
330  return nullptr;
331 }
332 
334 {
335  if(!tile_map_.on_map(loc))
336  return false;
337 
338  bool changed = false;
339 
340  tile& btile = tile_map_[loc];
341 
343  if(a.need_update())
344  changed = true;
346  }
348  if(a.need_update())
349  changed = true;
351  }
352 
353  return changed;
354 }
355 
356 /** @todo TODO: rename this function */
358 {
359  if(tile_map_.on_map(loc)) {
360  tile& btile = tile_map_[loc];
361  // btile.images.clear();
362  btile.images_foreground.clear();
363  btile.images_background.clear();
364  const std::string filename = map().get_terrain_info(loc).minimap_image();
365 
366  if(!filename.empty()) {
367  animated<image::locator> img_loc;
368  img_loc.add_frame(100, image::locator("terrain/" + filename + ".png"));
369  img_loc.start_animation(0, true);
370  btile.images_background.push_back(img_loc);
371  }
372 
373  // Combine base and overlay image if necessary
374  if(map().get_terrain_info(loc).is_combined()) {
375  const std::string filename_ovl = map().get_terrain_info(loc).minimap_image_overlay();
376 
377  if(!filename_ovl.empty()) {
378  animated<image::locator> img_loc_ovl;
379  img_loc_ovl.add_frame(100, image::locator("terrain/" + filename_ovl + ".png"));
380  img_loc_ovl.start_animation(0, true);
381  btile.images_background.push_back(img_loc_ovl);
382  }
383  }
384  }
385 }
386 
388 {
389  tile_map_.reset();
390  terrain_by_type_.clear();
391  build_terrains();
392 }
393 
394 static bool image_exists(const std::string& name)
395 {
396  bool precached = name.find("..") == std::string::npos;
397 
398  if(precached && image::precached_file_exists(name)) {
399  return true;
400  } else if(image::exists(name)) {
401  return true;
402  }
403 
404  return false;
405 }
406 
407 static std::vector<std::string> get_variations(const std::string& base, const std::string& variations)
408 {
409  /** @todo optimize this function */
410  std::vector<std::string> res;
411  if(variations.empty()) {
412  res.push_back(base);
413  return res;
414  }
415  std::string::size_type pos = base.find("@V", 0);
416  if(pos == std::string::npos) {
417  res.push_back(base);
418  return res;
419  }
420  std::vector<std::string> vars = utils::split(variations, ';', 0);
421 
422  for(const std::string& v : vars) {
423  res.push_back(base);
424  pos = 0;
425  while((pos = res.back().find("@V", pos)) != std::string::npos) {
426  res.back().replace(pos, 2, v);
427  pos += v.size();
428  }
429  }
430  return res;
431 }
432 
434 {
435  // If the rule has no constraints, it is invalid
436  if(rule.constraints.empty())
437  return false;
438 
439  // Parse images and animations data
440  // If one is not valid, return false.
441  for(terrain_constraint& constraint : rule.constraints) {
442  for(rule_image& ri : constraint.images) {
443  for(rule_image_variant& variant : ri.variants) {
444  std::vector<std::string> var_strings = get_variations(variant.image_string, variant.variations);
445  for(const std::string& var : var_strings) {
446  /** @todo improve this, 99% of terrains are not animated. */
447  std::vector<std::string> frames = utils::square_parenthetical_split(var, ',');
449 
450  for(const std::string& frame : frames) {
451  const std::vector<std::string> items = utils::split(frame, ':');
452  const std::string& str = items.front();
453 
454  const std::size_t tilde = str.find('~');
455  bool has_tilde = tilde != std::string::npos;
456  const std::string filename = "terrain/" + (has_tilde ? str.substr(0, tilde) : str);
457 
458  if(!image_exists(filename)) {
459  continue; // ignore missing frames
460  }
461 
462  const std::string modif = (has_tilde ? str.substr(tilde + 1) : "");
463 
464  int time = 100;
465  if(items.size() > 1) {
466  try {
467  time = std::stoi(items.back());
468  } catch(const std::invalid_argument&) {
469  ERR_NG << "Invalid 'time' value in terrain image builder: " << items.back() << "\n";
470  }
471  }
472  image::locator locator;
473  if(ri.global_image) {
474  locator = image::locator(filename, constraint.loc, ri.center_x, ri.center_y, modif);
475  } else {
476  locator = image::locator(filename, modif);
477  }
478  res.add_frame(time, locator);
479  }
480  if(res.get_frames_count() == 0)
481  break; // no valid images, don't register it
482 
483  res.start_animation(0, true);
484  variant.images.push_back(std::move(res));
485  }
486  if(variant.images.empty())
487  return false; // no valid images, rule is invalid
488  }
489  }
490  }
491 
492  return true;
493 }
494 
496 {
497  static const struct
498  {
499  int ii;
500  int ij;
501  int ji;
502  int jj;
503  } 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}};
504 
505  // The following array of matrices is intended to rotate the (x,y)
506  // coordinates of a point in a wesnoth hex (and wesnoth hexes are not
507  // regular hexes :) ).
508  // The base matrix for a 1-step rotation with the wesnoth tile shape
509  // is:
510  //
511  // r = s^-1 * t * s
512  //
513  // with s = [[ 1 0 ]
514  // [ 0 -sqrt(3)/2 ]]
515  //
516  // and t = [[ -1/2 sqrt(3)/2 ]
517  // [ -sqrt(3)/2 1/2 ]]
518  //
519  // With t being the rotation matrix (pi/3 rotation), and s a matrix
520  // that transforms the coordinates of the wesnoth hex to make them
521  // those of a regular hex.
522  //
523  // (demonstration left as an exercise for the reader)
524  //
525  // So we have
526  //
527  // r = [[ 1/2 -3/4 ]
528  // [ 1 1/2 ]]
529  //
530  // And the following array contains I(2), r, r^2, r^3, r^4, r^5
531  // (with r^3 == -I(2)), which are the successive rotations.
532  static const struct
533  {
534  double xx;
535  double xy;
536  double yx;
537  double yy;
538  } xyrotations[6] {
539  { 1., 0., 0., 1. },
540  { 1./2. , -3./4., 1., 1./2. },
541  { -1./2., -3./4., 1, -1./2.},
542  { -1. , 0., 0., -1. },
543  { -1./2., 3./4., -1., -1./2.},
544  { 1./2. , 3./4., -1., 1./2. },
545  };
546 
547  assert(angle >= 0);
548 
549  angle %= 6;
550 
551  // Vector i is going from n to s, vector j is going from ne to sw.
552  int vi = ret.loc.y - ret.loc.x / 2;
553  int vj = ret.loc.x;
554 
555  int ri = rotations[angle].ii * vi + rotations[angle].ij * vj;
556  int rj = rotations[angle].ji * vi + rotations[angle].jj * vj;
557 
558  ret.loc.x = rj;
559  ret.loc.y = ri + (rj >= 0 ? rj / 2 : (rj - 1) / 2);
560 
561  for(rule_imagelist::iterator itor = ret.images.begin(); itor != ret.images.end(); ++itor) {
562  double vx, vy, rx, ry;
563 
564  vx = static_cast<double>(itor->basex) - static_cast<double>(tilewidth_) / 2;
565  vy = static_cast<double>(itor->basey) - static_cast<double>(tilewidth_) / 2;
566 
567  rx = xyrotations[angle].xx * vx + xyrotations[angle].xy * vy;
568  ry = xyrotations[angle].yx * vx + xyrotations[angle].yy * vy;
569 
570  itor->basex = static_cast<int>(rx + tilewidth_ / 2);
571  itor->basey = static_cast<int>(ry + tilewidth_ / 2);
572 
573  // std::cerr << "Rotation: from " << vx << ", " << vy << " to " << itor->basex <<
574  // ", " << itor->basey << "\n";
575  }
576 }
577 
578 void terrain_builder::replace_rotate_tokens(std::string& s, int angle, const std::vector<std::string>& replacement)
579 {
580  std::string::size_type pos = 0;
581  while((pos = s.find("@R", pos)) != std::string::npos) {
582  if(pos + 2 >= s.size())
583  return;
584  unsigned i = s[pos + 2] - '0' + angle;
585  if(i >= 6)
586  i -= 6;
587  if(i >= 6) {
588  pos += 2;
589  continue;
590  }
591  const std::string& r = replacement[i];
592  s.replace(pos, 3, r);
593  pos += r.size();
594  }
595 }
596 
597 void terrain_builder::replace_rotate_tokens(rule_image& image, int angle, const std::vector<std::string>& replacement)
598 {
599  for(rule_image_variant& variant : image.variants) {
600  replace_rotate_tokens(variant, angle, replacement);
601  }
602 }
603 
605  rule_imagelist& list, int angle, const std::vector<std::string>& replacement)
606 {
607  for(rule_image& img : list) {
608  replace_rotate_tokens(img, angle, replacement);
609  }
610 }
611 
612 void terrain_builder::replace_rotate_tokens(building_rule& rule, int angle, const std::vector<std::string>& replacement)
613 {
614  for(terrain_constraint& cons : rule.constraints) {
615  // Transforms attributes
616  for(std::string& flag : cons.set_flag) {
617  replace_rotate_tokens(flag, angle, replacement);
618  }
619  for(std::string& flag : cons.no_flag) {
620  replace_rotate_tokens(flag, angle, replacement);
621  }
622  for(std::string& flag : cons.has_flag) {
623  replace_rotate_tokens(flag, angle, replacement);
624  }
625  replace_rotate_tokens(cons.images, angle, replacement);
626  }
627 
628  // replace_rotate_tokens(rule.images, angle, replacement);
629 }
630 
631 void terrain_builder::rotate_rule(building_rule& ret, int angle, const std::vector<std::string>& rot)
632 {
633  if(rot.size() != 6) {
634  ERR_NG << "invalid rotations" << std::endl;
635  return;
636  }
637 
638  for(terrain_constraint& cons : ret.constraints) {
639  rotate(cons, angle);
640  }
641 
642  // Normalize the rotation, so that it starts on a positive location
643  int minx = INT_MAX;
644  int miny = INT_MAX;
645 
646  for(const terrain_constraint& cons : ret.constraints) {
647  minx = std::min<int>(cons.loc.x, minx);
648  miny = std::min<int>(2 * cons.loc.y + (cons.loc.x & 1), miny);
649  }
650 
651  if((miny & 1) && (minx & 1) && (minx < 0))
652  miny += 2;
653  if(!(miny & 1) && (minx & 1) && (minx > 0))
654  miny -= 2;
655 
656  for(terrain_constraint& cons : ret.constraints) {
657  legacy_sum_assign(cons.loc, map_location(-minx, -((miny - 1) / 2)));
658  }
659 
660  replace_rotate_tokens(ret, angle, rot);
661 }
662 
664  const std::string& variations,
665  const std::string& tod,
666  const std::string& has_flag,
667  int random_start)
668  : image_string(image_string)
669  , variations(variations)
670  , images()
671  , tods()
672  , has_flag()
673  , random_start(random_start)
674 {
675  if(!has_flag.empty()) {
676  this->has_flag = utils::split(has_flag);
677  }
678  if(!tod.empty()) {
679  const std::vector<std::string> tod_list = utils::split(tod);
680  tods.insert(tod_list.begin(), tod_list.end());
681  }
682 }
683 
684 void terrain_builder::add_images_from_config(rule_imagelist& images, const config& cfg, bool global, int dx, int dy)
685 {
686  for(const config& img : cfg.child_range("image")) {
687  int layer = img["layer"];
688 
689  int basex = tilewidth_ / 2 + dx, basey = tilewidth_ / 2 + dy;
690  if(const config::attribute_value* base_ = img.get("base")) {
691  std::vector<std::string> base = utils::split(*base_);
692  if(base.size() >= 2) {
693  try {
694  basex = std::stoi(base[0]);
695  basey = std::stoi(base[1]);
696  } catch(const std::invalid_argument&) {
697  ERR_NG << "Invalid 'base' value in terrain image builder: " << base[0] << ", " << base[1] << "\n";
698  }
699  }
700  }
701 
702  int center_x = -1, center_y = -1;
703  if(const config::attribute_value* center_ = img.get("center")) {
704  std::vector<std::string> center = utils::split(*center_);
705  if(center.size() >= 2) {
706  try {
707  center_x = std::stoi(center[0]);
708  center_y = std::stoi(center[1]);
709  } catch(const std::invalid_argument&) {
710  ERR_NG << "Invalid 'center' value in terrain image builder: " << center[0] << ", " << center[1]
711  << "\n";
712  }
713  }
714  }
715 
716  bool is_water = img["is_water"].to_bool();
717 
718  images.push_back(rule_image(layer, basex - dx, basey - dy, global, center_x, center_y, is_water));
719 
720  // Adds the other variants of the image
721  for(const config& variant : img.child_range("variant")) {
722  const std::string& name = variant["name"];
723  const std::string& variations = img["variations"];
724  const std::string& tod = variant["tod"];
725  const std::string& has_flag = variant["has_flag"];
726 
727  // If an integer is given then assign that, but if a bool is given, then assign -1 if true and 0 if false
728  int random_start = variant["random_start"].to_bool(true) ? variant["random_start"].to_int(-1) : 0;
729 
730  images.back().variants.emplace_back(name, variations, tod, has_flag, random_start);
731  }
732 
733  // Adds the main (default) variant of the image at the end,
734  // (will be used only if previous variants don't match)
735  const std::string& name = img["name"];
736  const std::string& variations = img["variations"];
737 
738  int random_start = img["random_start"].to_bool(true) ? img["random_start"].to_int(-1) : 0;
739 
740  images.back().variants.emplace_back(name, variations, random_start);
741  }
742 }
743 
745  const map_location& loc,
747  const config& global_images)
748 {
749  terrain_constraint* cons = nullptr;
750  for(terrain_constraint& c : constraints) {
751  if(c.loc == loc) {
752  cons = &c;
753  break;
754  }
755  }
756 
757  if(!cons) {
758  // The terrain at the current location did not exist, so create it
759  constraints.emplace_back(loc);
760  cons = &constraints.back();
761  }
762 
763  if(!type.terrain.empty()) {
764  cons->terrain_types_match = type;
765  }
766 
767  int x = loc.x * tilewidth_ * 3 / 4;
768  int y = loc.y * tilewidth_ + (loc.x % 2) * tilewidth_ / 2;
769  add_images_from_config(cons->images, global_images, true, x, y);
770 
771  return *cons;
772 }
773 
775  const map_location& loc,
776  const config& cfg,
777  const config& global_images)
778 
779 {
780  terrain_constraint& constraint = add_constraints(
781  constraints, loc, t_translation::ter_match(cfg["type"].str(), t_translation::WILDCARD), global_images);
782 
783  std::vector<std::string> item_string = utils::square_parenthetical_split(cfg["set_flag"], ',', "[", "]");
784  constraint.set_flag.insert(constraint.set_flag.end(), item_string.begin(), item_string.end());
785 
786  item_string = utils::square_parenthetical_split(cfg["has_flag"], ',', "[", "]");
787  constraint.has_flag.insert(constraint.has_flag.end(), item_string.begin(), item_string.end());
788 
789  item_string = utils::square_parenthetical_split(cfg["no_flag"], ',', "[", "]");
790  constraint.no_flag.insert(constraint.no_flag.end(), item_string.begin(), item_string.end());
791 
792  item_string = utils::square_parenthetical_split(cfg["set_no_flag"], ',', "[", "]");
793  constraint.set_flag.insert(constraint.set_flag.end(), item_string.begin(), item_string.end());
794  constraint.no_flag.insert(constraint.no_flag.end(), item_string.begin(), item_string.end());
795 
796  constraint.no_draw = cfg["no_draw"].to_bool(false);
797 
798  add_images_from_config(constraint.images, cfg, false);
799 }
800 
802  const std::string& mapstring, struct building_rule& br, anchormap& anchors, const config& global_images)
803 {
805 
806  // If there is an empty map leave directly.
807  // Determine after conversion, since a
808  // non-empty string can return an empty map.
809  if(map.data.empty()) {
810  return;
811  }
812 
813  int lineno = (map.get(0, 0) == t_translation::NONE_TERRAIN) ? 1 : 0;
814  int x = lineno;
815  int y = 0;
816  for(int y_off = 0; y_off < map.w; ++y_off) {
817  for(int x_off = x; x_off < map.h; ++x_off) {
818  const t_translation::terrain_code terrain = map.get(y_off, x_off);
819 
820  if(terrain.base == t_translation::TB_DOT) {
821  // Dots are simple placeholders,
822  // which do not represent actual terrains.
823  } else if(terrain.overlay != 0) {
824  anchors.emplace(terrain.overlay, map_location(x, y));
825  } else if(terrain.base == t_translation::TB_STAR) {
826  add_constraints(br.constraints, map_location(x, y), t_translation::STAR, global_images);
827  } else {
828  ERR_NG << "Invalid terrain (" << t_translation::write_terrain_code(terrain) << ") in builder map"
829  << std::endl;
830  assert(false);
831  return;
832  }
833  x += 2;
834  }
835 
836  if(lineno % 2 == 1) {
837  ++y;
838  x = 0;
839  } else {
840  x = 1;
841  }
842  ++lineno;
843  }
844 }
845 
847 {
848  if(load_images(rule)) {
849  rules.insert(rule);
850  }
851 }
852 
853 void terrain_builder::add_rotated_rules(building_ruleset& rules, building_rule& tpl, const std::string& rotations)
854 {
855  if(rotations.empty()) {
856  // Adds the parsed built terrain to the list
857 
858  add_rule(rules, tpl);
859  } else {
860  const std::vector<std::string>& rot = utils::split(rotations, ',');
861 
862  for(std::size_t angle = 0; angle < rot.size(); ++angle) {
863  /* Only 5% of the rules have valid images, so most of
864  them will be discarded. If the ratio was higher,
865  it would be more efficient to insert a copy of the
866  template rule into the ruleset, modify it in place,
867  and remove it if invalid. But since the ratio is so
868  low, the speedup is not worth the extra multiset
869  manipulations. */
870 
871  if(rot.at(angle) == "skip") {
872  continue;
873  }
874 
875  building_rule rule = tpl;
876  rotate_rule(rule, angle, rot);
877  add_rule(rules, rule);
878  }
879  }
880 }
881 
882 void terrain_builder::parse_config(const config& cfg, bool local)
883 {
884  return parse_config(game_config_view::wrap(cfg), local);
885 }
886 
888 {
889  log_scope("terrain_builder::parse_config");
890  int n = 0;
891 
892  // Parses the list of building rules (BRs)
893  for(const config& br : cfg.child_range("terrain_graphics")) {
894  building_rule pbr; // Parsed Building rule
895  pbr.local = local;
896 
897  // add_images_from_config(pbr.images, **br);
898 
899  pbr.location_constraints = map_location(br["x"].to_int() - 1, br["y"].to_int() - 1);
900 
901  pbr.modulo_constraints = map_location(br["mod_x"].to_int(), br["mod_y"].to_int());
902 
903  pbr.probability = br["probability"].to_int(100);
904 
905  // Mapping anchor indices to anchor locations.
906  anchormap anchors;
907 
908  // Parse the map= , if there is one (and fill the anchors list)
909  parse_mapstring(br["map"], pbr, anchors, br);
910 
911  // Parses the terrain constraints (TCs)
912  for(const config& tc : br.child_range("tile")) {
913  // Adds the terrain constraint to the current built terrain's list
914  // of terrain constraints, if it does not exist.
915  map_location loc;
916  if(const config::attribute_value* v = tc.get("x")) {
917  loc.x = *v;
918  }
919  if(const config::attribute_value* v = tc.get("y")) {
920  loc.y = *v;
921  }
922  if(loc.valid()) {
923  add_constraints(pbr.constraints, loc, tc, br);
924  }
925  if(const config::attribute_value* v = tc.get("pos")) {
926  int pos = *v;
927  if(anchors.find(pos) == anchors.end()) {
928  WRN_NG << "Invalid anchor!" << std::endl;
929  continue;
930  }
931 
932  std::pair<anchormap::const_iterator, anchormap::const_iterator> range = anchors.equal_range(pos);
933 
934  for(; range.first != range.second; ++range.first) {
935  loc = range.first->second;
936  add_constraints(pbr.constraints, loc, tc, br);
937  }
938  }
939  }
940 
941  const std::vector<std::string> global_set_flag = utils::split(br["set_flag"]);
942  const std::vector<std::string> global_no_flag = utils::split(br["no_flag"]);
943  const std::vector<std::string> global_has_flag = utils::split(br["has_flag"]);
944  const std::vector<std::string> global_set_no_flag = utils::split(br["set_no_flag"]);
945 
946  for(terrain_constraint& constraint : pbr.constraints) {
947  constraint.set_flag.insert(constraint.set_flag.end(), global_set_flag.begin(), global_set_flag.end());
948  constraint.no_flag.insert(constraint.no_flag.end(), global_no_flag.begin(), global_no_flag.end());
949  constraint.has_flag.insert(constraint.has_flag.end(), global_has_flag.begin(), global_has_flag.end());
950  constraint.set_flag.insert(constraint.set_flag.end(), global_set_no_flag.begin(), global_set_no_flag.end());
951  constraint.no_flag.insert(constraint.no_flag.end(), global_set_no_flag.begin(), global_set_no_flag.end());
952  }
953 
954  // Handles rotations
955  const std::string& rotations = br["rotations"];
956 
957  pbr.precedence = br["precedence"];
958 
959  add_rotated_rules(building_rules_, pbr, rotations);
960 
961  n++;
962  if(n % 10 == 0) {
964  }
965  }
966 
967 // Debug output for the terrain rules
968 #if 0
969  std::cerr << "Built terrain rules: \n";
970 
971  building_ruleset::const_iterator rule;
972  for(rule = building_rules_.begin(); rule != building_rules_.end(); ++rule) {
973  std::cerr << ">> New rule: image_background = "
974  << "\n>> Location " << rule->second.location_constraints
975  << "\n>> Probability " << rule->second.probability
976 
977  for(constraint_set::const_iterator constraint = rule->second.constraints.begin();
978  constraint != rule->second.constraints.end(); ++constraint) {
979 
980  std::cerr << ">>>> New constraint: location = (" << constraint->second.loc
981  << "), terrain types = '" << t_translation::write_list(constraint->second.terrain_types_match.terrain) << "'\n";
982 
983  std::vector<std::string>::const_iterator flag;
984 
985  for(flag = constraint->second.set_flag.begin(); flag != constraint->second.set_flag.end(); ++flag) {
986  std::cerr << ">>>>>> Set_flag: " << *flag << "\n";
987  }
988 
989  for(flag = constraint->second.no_flag.begin(); flag != constraint->second.no_flag.end(); ++flag) {
990  std::cerr << ">>>>>> No_flag: " << *flag << "\n";
991  }
992  }
993 
994  }
995 #endif
996 }
997 
998 void terrain_builder::add_off_map_rule(const std::string& image)
999 {
1000  // Build a config object
1001  config cfg;
1002 
1003  config& item = cfg.add_child("terrain_graphics");
1004 
1005  config& tile = item.add_child("tile");
1006  tile["x"] = 0;
1007  tile["y"] = 0;
1009 
1010  config& tile_image = tile.add_child("image");
1011  tile_image["layer"] = -1000;
1012  tile_image["name"] = image;
1013 
1014  item["probability"] = 100;
1015  item["no_flag"] = "base";
1016  item["set_flag"] = "base";
1017 
1018  // Parse the object
1020 }
1021 
1023  const map_location& loc,
1024  const terrain_constraint* type_checked) const
1025 {
1026  // Don't match if the location isn't a multiple of mod_x and mod_y
1027  if(rule.modulo_constraints.x > 0 && (loc.x % rule.modulo_constraints.x != 0)) {
1028  return false;
1029  }
1030  if(rule.modulo_constraints.y > 0 && (loc.y % rule.modulo_constraints.y != 0)) {
1031  return false;
1032  }
1033 
1034  if(rule.location_constraints.valid() && rule.location_constraints != loc) {
1035  return false;
1036  }
1037 
1038  if(rule.probability != 100) {
1039  unsigned int random = get_noise(loc, rule.get_hash()) % 100;
1040  if(random > static_cast<unsigned int>(rule.probability)) {
1041  return false;
1042  }
1043  }
1044 
1045  for(const terrain_constraint& cons : rule.constraints) {
1046  // Translated location
1047  const map_location tloc = legacy_sum(loc, cons.loc);
1048 
1049  if(!tile_map_.on_map(tloc)) {
1050  return false;
1051  }
1052 
1053  // std::cout << "testing..." << builder_letter(map().get_terrain(tloc))
1054 
1055  // check if terrain matches except if we already know that it does
1056  if(&cons != type_checked && !terrain_matches(map().get_terrain(tloc), cons.terrain_types_match)) {
1057  return false;
1058  }
1059 
1060  const std::set<std::string>& flags = tile_map_[tloc].flags;
1061 
1062  for(const std::string& s : cons.no_flag) {
1063  // If a flag listed in "no_flag" is present, the rule does not match
1064  if(flags.find(s) != flags.end()) {
1065  return false;
1066  }
1067  }
1068  for(const std::string& s : cons.has_flag) {
1069  // If a flag listed in "has_flag" is not present, this rule does not match
1070  if(flags.find(s) == flags.end()) {
1071  return false;
1072  }
1073  }
1074  }
1075 
1076  return true;
1077 }
1078 
1080 {
1081  unsigned int rand_seed = get_noise(loc, rule.get_hash());
1082 
1083  for(const terrain_constraint& constraint : rule.constraints) {
1084  const map_location tloc = legacy_sum(loc, constraint.loc);
1085  if(!tile_map_.on_map(tloc)) {
1086  return;
1087  }
1088 
1089  tile& btile = tile_map_[tloc];
1090 
1091  if(!constraint.no_draw) {
1092  for(const rule_image& img : constraint.images) {
1093  btile.images.emplace_back(&img, rand_seed);
1094  }
1095  }
1096 
1097  // Sets flags
1098  for(const std::string& flag : constraint.set_flag) {
1099  btile.flags.insert(flag);
1100  }
1101  }
1102 }
1103 
1104 // copied from text_surface::hash()
1105 // but keep it separated because the needs are different
1106 // and changing it will modify the map random variations
1107 static unsigned int hash_str(const std::string& str)
1108 {
1109  unsigned int h = 0;
1110  for(std::string::const_iterator it = str.begin(), it_end = str.end(); it != it_end; ++it)
1111  h = ((h << 9) | (h >> (sizeof(int) * 8 - 9))) ^ (*it);
1112  return h;
1113 }
1114 
1116 {
1117  if(hash_ != DUMMY_HASH)
1118  return hash_;
1119 
1120  for(const terrain_constraint& constraint : constraints) {
1121  for(const rule_image& ri : constraint.images) {
1122  for(const rule_image_variant& variant : ri.variants) {
1123  // we will often hash the same string, but that seems fast enough
1124  hash_ += hash_str(variant.image_string);
1125  }
1126  }
1127  }
1128 
1129  // don't use the reserved dummy hash
1130  if(hash_ == DUMMY_HASH)
1131  hash_ = 105533; // just a random big prime number
1132 
1133  return hash_;
1134 }
1135 
1137 {
1138  log_scope("terrain_builder::build_terrains");
1139 
1140  // Builds the terrain_by_type_ cache
1141  for(int x = -2; x <= map().w(); ++x) {
1142  for(int y = -2; y <= map().h(); ++y) {
1143  const map_location loc(x, y);
1145 
1146  terrain_by_type_[t].push_back(loc);
1147 
1148  // Flag all hexes according to whether they're on the border or not,
1149  // to make it easier for WML to draw the borders
1150  if(draw_border_&& !map().on_board(loc)) {
1151  tile_map_[loc].flags.insert("_border");
1152  } else {
1153  tile_map_[loc].flags.insert("_board");
1154  }
1155  }
1156  }
1157 
1158  for(const building_rule& rule : building_rules_) {
1159  // Find the constraint that contains the less terrain of all terrain rules.
1160  // We will keep a track of the matching terrains of this constraint
1161  // and later try to apply the rule only on them
1162  std::size_t min_size = INT_MAX;
1163  t_translation::ter_list min_types = t_translation::ter_list(); // <-- This must be explicitly initialized, just
1164  // as min_constraint is, at start of loop, or we
1165  // get a null pointer dereference when we go
1166  // through on later times.
1167  const terrain_constraint* min_constraint = nullptr;
1168 
1169  for(const terrain_constraint& constraint : rule.constraints) {
1170  const t_translation::ter_match& match = constraint.terrain_types_match;
1171  t_translation::ter_list matching_types;
1172  std::size_t constraint_size = 0;
1173 
1174  for(terrain_by_type_map::iterator type_it = terrain_by_type_.begin(); type_it != terrain_by_type_.end();
1175  ++type_it) {
1176  const t_translation::terrain_code t = type_it->first;
1177  if(terrain_matches(t, match)) {
1178  const std::size_t match_size = type_it->second.size();
1179  constraint_size += match_size;
1180  if(constraint_size >= min_size) {
1181  break; // not a minimum, bail out
1182  }
1183  matching_types.push_back(t);
1184  }
1185  }
1186 
1187  if(constraint_size < min_size) {
1188  min_size = constraint_size;
1189  min_types = matching_types;
1190  min_constraint = &constraint;
1191  if(min_size == 0) {
1192  // a constraint is never matched on this map
1193  // we break with a empty type list
1194  break;
1195  }
1196  }
1197  }
1198 
1199  assert(min_constraint != nullptr);
1200 
1201  // NOTE: if min_types is not empty, we have found a valid min_constraint;
1202  for(t_translation::ter_list::const_iterator t = min_types.begin(); t != min_types.end(); ++t) {
1203  const std::vector<map_location>* locations = &terrain_by_type_[*t];
1204 
1205  for(std::vector<map_location>::const_iterator itor = locations->begin(); itor != locations->end(); ++itor) {
1206  const map_location loc = legacy_difference(*itor, min_constraint->loc);
1207 
1208  if(rule_matches(rule, loc, min_constraint)) {
1209  apply_rule(rule, loc);
1210  }
1211  }
1212  }
1213  }
1214 }
1215 
1217 {
1218  if(tile_map_.on_map(loc))
1219  return &(tile_map_[loc]);
1220  return nullptr;
1221 }
void rebuild_terrain(const map_location &loc)
Performs a "quick-rebuild" of the terrain in a given location.
Definition: builder.cpp:357
void reload_map()
Updates internals that cache map size.
Definition: builder.cpp:298
std::size_t get_frames_count() const
The in-memory representation of a [terrain_graphics] WML rule.
Definition: builder.hpp:407
void precache_file_existence(const std::string &subdir)
Precache the existence of files in a binary path subdirectory (e.g.
Definition: picture.cpp:1076
terrain_by_type_map terrain_by_type_
A map representing all locations whose terrain is of a given type.
Definition: builder.hpp:857
tile * get_tile(const map_location &loc)
Definition: builder.cpp:1216
static const game_config_view * rules_cfg_
Config used to parse global terrain rules.
Definition: builder.hpp:866
const terrain_code NONE_TERRAIN
Definition: translation.hpp:58
map_location modulo_constraints
Used to constrain locations to ones with coordinates that are multiples of the "mod_x" and "mod_y" pa...
Definition: builder.hpp:437
void reset()
Resets the whole tile map.
Definition: builder.cpp:205
The in-memory representation of a [tile] WML rule inside of a [terrain_graphics] WML rule...
Definition: builder.hpp:279
void add_rule(building_ruleset &rules, building_rule &rule)
Adds a rule to a ruleset.
Definition: builder.cpp:846
tile & operator[](const map_location &loc)
Returns a reference to the tile which is at the position pointed by loc.
Definition: builder.cpp:229
Variant for storing WML attributes.
bool no_draw
Whether to actually draw the images onto this hex or not.
Definition: builder.hpp:310
bool precached_file_exists(const std::string &file)
Definition: picture.cpp:1085
void add_off_map_rule(const std::string &image)
Adds a builder rule for the _off^_usr tile, this tile only has 1 image.
Definition: builder.cpp:998
static game_config_view wrap(const config &cfg)
#define a
config_array_view child_range(config_key_type key) const
bool load_images(building_rule &rule)
Load images and tests for validity of a rule.
Definition: builder.cpp:433
std::vector< terrain_constraint > constraint_set
The list of constraints attached to a terrain_graphics WML rule.
Definition: builder.hpp:402
child_itors child_range(config_key_type key)
Definition: config.cpp:344
Represent a rule_image applied with a random seed.
Definition: builder.hpp:345
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...
Definition: builder.cpp:744
imagelist images_background
The list of images which are behind the unit sprites, attached to this tile.
Definition: builder.hpp:380
static void progress(loading_stage stage=loading_stage::none)
int precedence
Ordering relation between the rules.
Definition: builder.hpp:449
bool need_update() const
std::multimap< int, map_location > anchormap
Definition: builder.hpp:717
void rebuild_cache_all()
Definition: builder.cpp:269
static building_ruleset building_rules_
Parsed terrain rules.
Definition: builder.hpp:863
const std::vector< std::string > items
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:98
std::vector< terrain_code > data
Definition: translation.hpp:92
const int tilewidth_
The tile width used when using basex and basey.
Definition: builder.hpp:397
#define h
static map_location & legacy_sum_assign(map_location &me, const map_location &a)
Definition: builder.cpp:58
bool animate_water()
Definition: general.cpp:827
static map_location legacy_difference(const map_location &me, const map_location &a)
Definition: builder.cpp:78
static lg::log_domain log_engine("engine")
t_translation::ter_match terrain_types_match
Definition: builder.hpp:304
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...
Definition: builder.cpp:853
void add_frame(int duration, const T &value, bool force_change=false)
Adds a frame to an animation.
int random_start
Specify the allowed amount of random shift (in milliseconds) applied to the animation start time...
Definition: builder.hpp:223
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...
Definition: builder.cpp:1079
static unsigned int get_noise(const map_location &loc, unsigned int index)
Definition: builder.cpp:196
#define WRN_NG
Definition: builder.cpp:33
void rebuild_all()
Performs a complete rebuild of the list of terrain graphics attached to a map.
Definition: builder.cpp:387
static const unsigned int DUMMY_HASH
Definition: builder.hpp:70
void rebuild_cache(const std::string &tod, logs *log=nullptr)
Rebuilds the whole image cache, for a given time-of-day.
Definition: builder.cpp:111
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.
Definition: builder.cpp:578
int probability
The probability of this rule to match, when all conditions are met.
Definition: builder.hpp:444
Represents a tile of the game map, with all associated builder-specific parameters: flags...
Definition: builder.hpp:321
#define b
void change_map(const gamemap *m)
Definition: builder.cpp:305
int get_animation_duration() const
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
Definition: picture.cpp:1025
rule_image_variant(const std::string &image_string, const std::string &variations, int random_start=-1)
Constructor for the normal default case.
Definition: builder.hpp:169
const gamemap * map_
A pointer to the gamemap class used in the current level.
Definition: builder.hpp:840
int w() const
Effective map width.
Definition: map.hpp:50
const T & get_frame(std::size_t n) const
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.
Definition: builder.cpp:1022
const terrain_code STAR
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:302
bool valid() const
Definition: location.hpp:89
tilemap tile_map_
The tile_map_ for the current level, which is filled by the build_terrains_ method to contain "tiles"...
Definition: builder.hpp:847
static bool image_exists(const std::string &name)
Definition: builder.cpp:394
#define ERR_NG
Definition: builder.cpp:32
Encapsulates the map of the game.
Definition: map.hpp:171
std::set< std::string > tods
The Time of Day associated to this variant (if any)
Definition: builder.hpp:217
TERRAIN_TYPE
Used as a parameter for the get_terrain_at function.
Definition: builder.hpp:52
const ter_layer TB_STAR
void flush_local_rules()
Definition: builder.cpp:278
std::vector< rule_image_variant > variants
A list of variants for this image.
Definition: builder.hpp:256
std::vector< rule_image_rand > images
The list of rule_images and random seeds associated to this tile.
Definition: builder.hpp:369
const ter_layer TB_DOT
void swap(config &lhs, config &rhs)
Implement non-member swap function for std::swap (calls config::swap).
Definition: config.cpp:1456
std::vector< log_details > logs
Definition: builder.hpp:328
bool local
Indicate if the rule is only for this scenario.
Definition: builder.hpp:454
const terrain_code OFF_MAP_USER
Generic locator abstracting the location of an image.
Definition: picture.hpp:60
std::string write_terrain_code(const terrain_code &tcode)
Writes a single terrain code to a string.
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.
Definition: builder.hpp:790
Encapsulates the map of the game.
Definition: location.hpp:38
void rotate_rule(building_rule &rule, int angle, const std::vector< std::string > &angle_name)
Rotates a template rule to a given angle.
Definition: builder.cpp:631
bool update_animation(const map_location &loc)
Updates the animation at a given tile.
Definition: builder.cpp:333
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...
Definition: builder.hpp:261
std::size_t i
Definition: function.cpp:967
std::string last_tod
The time-of-day to which the image caches correspond.
Definition: builder.hpp:384
void rotate(terrain_constraint &constraint, int angle)
"Rotates" a constraint from a rule.
Definition: builder.cpp:495
std::vector< std::string > set_flag
Definition: builder.hpp:305
Game configuration data as global variables.
Definition: build_info.cpp:60
void update_last_draw_time(double acceleration=0)
static map_location::DIRECTION s
std::set< std::string > flags
The list of flags present in this tile.
Definition: builder.hpp:342
rule_image(int layer, int x, int y, bool global_image=false, int center_x=-1, int center_y=-1, bool is_water=false)
This file holds the terrain_builder implementation.
Definition: builder.cpp:89
std::vector< rule_image > rule_imagelist
A shorthand notation for a vector of rule_images.
Definition: builder.hpp:273
ter_map read_builder_map(const std::string &str)
Reads a builder map.
void start_animation(int start_time, bool cycles=false)
Starts an animation cycle.
#define log_scope(description)
Definition: log.hpp:218
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...
Definition: builder.cpp:801
const std::string & minimap_image() const
Definition: terrain.hpp:45
std::string write_list(const ter_list &list)
Writes a list of terrains to a string, only writes the new format.
bool on_map(const map_location &loc) const
Tests if a location is on the map.
Definition: builder.cpp:220
int w
std::vector< std::string > has_flag
Definition: builder.hpp:219
Definitions for the terrain builder.
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.
Definition: unicode.cpp:72
int center_x
The position where the center of the image base should be.
Definition: builder.hpp:265
void reload(int x, int y)
Rebuilds the map to a new set of dimensions.
Definition: builder.cpp:211
Represents terrains which are to be drawn behind unit sprites.
Definition: builder.hpp:53
Each terrain_graphics rule is associated a set of images, which are applied on the terrain if the rul...
Definition: builder.hpp:233
std::vector< std::string > has_flag
Definition: builder.hpp:307
terrain_code & get(int x, int y)
Definition: translation.hpp:89
config & add_child(config_key_type key)
Definition: config.cpp:514
static map_location legacy_negation(const map_location &me)
These legacy map_location functions moved here from map_location.
Definition: builder.cpp:53
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...
Definition: builder.hpp:75
void build_terrains()
Calculates the list of terrains, and fills the tile_map_ member, from the gamemap and the building_ru...
Definition: builder.cpp:1136
tile()
Constructor for the tile() structure.
Definition: builder.cpp:101
std::multiset< building_rule > building_ruleset
A set of building rules.
Definition: builder.hpp:531
terrain_builder(const config &level, const gamemap *map, const std::string &offmap_image, bool draw_border)
Constructor for the terrain_builder class.
Definition: builder.cpp:243
constraint_set constraints
The set of [tile] constraints of this rule.
Definition: builder.hpp:423
void parse_global_config(const game_config_view &cfg)
Definition: builder.hpp:764
bool sorted_images
Indicates if &#39;images&#39; is sorted.
Definition: builder.hpp:387
double t
Definition: astarsearch.cpp:65
std::vector< std::string > split(const config_attribute_value &val)
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...
Definition: builder.cpp:684
unsigned int tile_size
Definition: game_config.cpp:69
bool is_empty_hex(const locator &i_locator)
Checks if an image is empty after hex masking.
Definition: picture.cpp:984
const gamemap & map() const
Definition: builder.hpp:100
map_location location_constraints
The location on which this map may match.
Definition: builder.hpp:430
std::vector< animated< image::locator > > images
An animated image locator built according to the image string.
Definition: builder.hpp:214
Functions to load and save images from/to disk.
Standard logging facilities (interface).
std::vector< terrain_code > ter_list
Definition: translation.hpp:77
const ter_layer WILDCARD
Definition: translation.hpp:39
std::string image_string
A string representing either the filename for an image, or a list of images, with an optional timing ...
Definition: builder.hpp:203
std::string variations
A semi-solon separated list of string used to replace.
Definition: builder.hpp:208
void parse_config(const config &cfg, bool local=true)
Parses a configuration object containing [terrain_graphics] rules, and fills the building_rules_ memb...
Definition: builder.cpp:882
unsigned int get_hash() const
Definition: builder.cpp:1115
static unsigned int hash_str(const std::string &str)
Definition: builder.cpp:1107
static map_location legacy_sum(const map_location &me, const map_location &a)
Definition: builder.cpp:71
imagelist images_foreground
The list of images which are in front of the unit sprites, attached to this tile. ...
Definition: builder.hpp:375
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
static void set_terrain_rules_cfg(const game_config_view &cfg)
Set the config where we will parse the global terrain rules.
Definition: builder.cpp:289
mock_char c
void clear()
Clears all data in this tile, and resets the cache.
Definition: builder.cpp:186
static std::vector< std::string > get_variations(const std::string &base, const std::string &variations)
Definition: builder.cpp:407
static map_location::DIRECTION n
int h() const
Effective map height.
Definition: map.hpp:53
const std::string & minimap_image_overlay() const
Definition: terrain.hpp:46
This structure can be used for matching terrain strings.
bool draw_border_
Whether the map border should be drawn.
Definition: builder.hpp:860
std::vector< std::string > no_flag
Definition: builder.hpp:306
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
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::pair< std::string, unsigned > item
Definition: help_impl.hpp:410
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 ...
Definition: builder.cpp:311