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