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