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