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