00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "global.hpp"
00019
00020 #include "array.hpp"
00021 #include "builder.hpp"
00022 #include "config.hpp"
00023 #include "log.hpp"
00024 #include "pathutils.hpp"
00025 #include "terrain.hpp"
00026 #include "util.hpp"
00027 #include "serialization/string_utils.hpp"
00028
00029 #include <cassert>
00030 #include <climits>
00031
00032 #define ERR_NG LOG_STREAM(err, engine)
00033 #define DEBUG_NG LOG_STREAM(info, engine)
00034
00035
00036
00037
00038
00039 static const int TILEWIDTH = 72;
00040
00041
00042
00043
00044
00045 static const int UNITPOS = 36 + 18;
00046
00047
00048
00049 static const int BASE_Y_INTERVAL = 100000;
00050
00051 terrain_builder::rule_image::rule_image(int layer, int x, int y, bool global_image, int cx, int cy) :
00052 layer(layer),
00053 basex(x),
00054 basey(y),
00055 variants(),
00056 global_image(global_image),
00057 center_x(cx),
00058 center_y(cy)
00059 {}
00060
00061 terrain_builder::tile::tile() :
00062 flags(),
00063 images(),
00064 images_foreground(),
00065 images_background(),
00066 last_tod("invalid_tod")
00067 {}
00068
00069 void terrain_builder::tile::add_image_to_cache(const std::string &tod, ordered_ri_list::const_iterator itor)
00070 {
00071 rule_image_variantlist::const_iterator tod_variant =
00072 itor->second->variants.find(tod);
00073
00074 if(tod_variant == itor->second->variants.end())
00075 tod_variant = itor->second->variants.find("");
00076
00077 if(tod_variant != itor->second->variants.end()) {
00078
00079 int layer = itor->first / BASE_Y_INTERVAL;
00080 int basey = itor->first % BASE_Y_INTERVAL;
00081
00082 if (basey < 0)
00083 basey += BASE_Y_INTERVAL/2;
00084 else
00085 basey -= BASE_Y_INTERVAL/2;
00086
00087 if(layer < 0 || (layer == 0 && basey < UNITPOS)) {
00088 images_background.push_back(tod_variant->second.image);
00089 } else {
00090 images_foreground.push_back(tod_variant->second.image);
00091 }
00092 }
00093 }
00094
00095 void terrain_builder::tile::rebuild_cache(const std::string &tod)
00096 {
00097 images_background.clear();
00098 images_foreground.clear();
00099
00100 ordered_ri_list::const_iterator itor;
00101 for(itor = images.begin(); itor != images.end(); ++itor) {
00102 add_image_to_cache(tod, itor);
00103 }
00104 }
00105
00106 void terrain_builder::tile::clear()
00107 {
00108 flags.clear();
00109 images.clear();
00110 images_foreground.clear();
00111 images_background.clear();
00112 last_tod = "invalid_tod";
00113 }
00114
00115 void terrain_builder::tilemap::reset()
00116 {
00117 for(std::vector<tile>::iterator it = map_.begin(); it != map_.end(); ++it)
00118 it->clear();
00119 }
00120
00121 bool terrain_builder::tilemap::on_map(const gamemap::location &loc) const
00122 {
00123 if(loc.x < -2 || loc.y < -2 || loc.x > (x_ + 1) || loc.y > (y_ + 1)) {
00124 return false;
00125 }
00126
00127 return true;
00128
00129 }
00130
00131 terrain_builder::tile& terrain_builder::tilemap::operator[](const gamemap::location &loc)
00132 {
00133 assert(on_map(loc));
00134
00135 return map_[(loc.x + 2) + (loc.y + 2) * (x_ + 4)];
00136 }
00137
00138 const terrain_builder::tile& terrain_builder::tilemap::operator[] (const gamemap::location &loc) const
00139 {
00140 assert(on_map(loc));
00141
00142 return map_[(loc.x + 2) + (loc.y + 2) * (x_ + 4)];
00143 }
00144
00145 terrain_builder::terrain_builder(const config& cfg, const config& level,
00146 const gamemap& map, const std::string& offmap_image) :
00147 map_(map),
00148 tile_map_(map.w(), map.h()),
00149 terrain_by_type_(),
00150 building_rules_()
00151 {
00152
00153
00154
00155
00156 parse_config(cfg);
00157 parse_config(level);
00158 add_off_map_rule(offmap_image);
00159
00160 build_terrains();
00161 }
00162
00163 const terrain_builder::imagelist *terrain_builder::get_terrain_at(const gamemap::location &loc,
00164 const std::string &tod, const ADJACENT_TERRAIN_TYPE terrain_type)
00165 {
00166 if(!tile_map_.on_map(loc))
00167 return NULL;
00168
00169 tile& tile_at = tile_map_[loc];
00170
00171 if(tod != tile_at.last_tod) {
00172 tile_at.rebuild_cache(tod);
00173 tile_at.last_tod = tod;
00174 }
00175
00176 if(terrain_type == ADJACENT_BACKGROUND) {
00177 if(!tile_at.images_background.empty())
00178 return &tile_at.images_background;
00179 }
00180
00181 if(terrain_type == ADJACENT_FOREGROUND) {
00182 if(!tile_at.images_foreground.empty())
00183 return &tile_at.images_foreground;
00184 }
00185
00186 return NULL;
00187 }
00188
00189 bool terrain_builder::update_animation(const gamemap::location &loc)
00190 {
00191 if(!tile_map_.on_map(loc))
00192 return false;
00193
00194 imagelist& bg = tile_map_[loc].images_background;
00195 imagelist& fg = tile_map_[loc].images_foreground;
00196 bool changed = false;
00197
00198 imagelist::iterator itor = bg.begin();
00199 for(; itor != bg.end(); ++itor) {
00200 if(itor->need_update())
00201 changed = true;
00202 itor->update_last_draw_time();
00203 }
00204
00205 itor = fg.begin();
00206 for(; itor != fg.end(); ++itor) {
00207 if(itor->need_update())
00208 changed = true;
00209 itor->update_last_draw_time();
00210 }
00211
00212 return changed;
00213 }
00214
00215
00216 void terrain_builder::rebuild_terrain(const gamemap::location &loc)
00217 {
00218 if (tile_map_.on_map(loc)) {
00219 tile& btile = tile_map_[loc];
00220
00221 btile.images_foreground.clear();
00222 btile.images_background.clear();
00223 const std::string filename =
00224 map_.get_terrain_info(map_.get_terrain(loc)).minimap_image();
00225 animated<image::locator> img_loc;
00226 img_loc.add_frame(100,image::locator("terrain/" + filename + ".png"));
00227 img_loc.start_animation(0, true);
00228 btile.images_background.push_back(img_loc);
00229
00230
00231 if(map_.get_terrain_info(map_.get_terrain(loc)).is_combined()) {
00232 const std::string filename_ovl =
00233 map_.get_terrain_info(map_.get_terrain(loc)).minimap_image_overlay();
00234 animated<image::locator> img_loc_ovl;
00235 img_loc_ovl.add_frame(100,image::locator("terrain/" + filename_ovl + ".png"));
00236 img_loc_ovl.start_animation(0, true);
00237 btile.images_background.push_back(img_loc_ovl);
00238 }
00239 }
00240 }
00241
00242 void terrain_builder::rebuild_all()
00243 {
00244 tile_map_.reset();
00245 terrain_by_type_.clear();
00246 build_terrains();
00247 }
00248
00249 bool terrain_builder::rule_valid(const building_rule &rule) const
00250 {
00251
00252 if(rule.constraints.empty())
00253 return false;
00254
00255
00256
00257 rule_imagelist::const_iterator image;
00258 constraint_set::const_iterator constraint;
00259 rule_image_variantlist::const_iterator variant;
00260
00261 for(constraint = rule.constraints.begin();
00262 constraint != rule.constraints.end(); ++constraint) {
00263 for(image = constraint->second.images.begin();
00264 image != constraint->second.images.end();
00265 ++image) {
00266
00267 for(variant = image->variants.begin(); variant != image->variants.end(); ++variant) {
00268 std::string s = variant->second.image_string;
00269 s = s.substr(0, s.find_first_of(",:"));
00270
00271 if(!image::exists("terrain/" + s + ".png"))
00272 return false;
00273 }
00274 }
00275 }
00276
00277 return true;
00278 }
00279
00280 bool terrain_builder::start_animation(building_rule &rule)
00281 {
00282 rule_imagelist::iterator image;
00283 constraint_set::iterator constraint;
00284 rule_image_variantlist::iterator variant;
00285
00286 for(constraint = rule.constraints.begin();
00287 constraint != rule.constraints.end(); ++constraint) {
00288
00289 for(image = constraint->second.images.begin();
00290 image != constraint->second.images.end();
00291 ++image) {
00292
00293 for(variant = image->variants.begin(); variant != image->variants.end(); ++variant) {
00294
00295 animated<image::locator>::anim_description image_vector;
00296 std::vector<std::string> items = utils::split(variant->second.image_string);
00297 std::vector<std::string>::const_iterator itor = items.begin();
00298 for(; itor != items.end(); ++itor) {
00299 const std::vector<std::string>& items = utils::split(*itor, ':');
00300 std::string str;
00301 int time;
00302
00303 if(items.size() > 1) {
00304 str = items.front();
00305 time = atoi(items.back().c_str());
00306 } else {
00307 str = *itor;
00308 time = 100;
00309 }
00310 if(image->global_image) {
00311 image_vector.push_back(animated<image::locator>::frame_description(time,image::locator("terrain/" + str + ".png",constraint->second.loc, image->center_x, image->center_y)));
00312 } else {
00313 image_vector.push_back(animated<image::locator>::frame_description(time,image::locator("terrain/" + str + ".png")));
00314 }
00315
00316 }
00317
00318 animated<image::locator> th(image_vector);
00319
00320 variant->second.image = th;
00321 variant->second.image.start_animation(0, true);
00322 }
00323 }
00324 }
00325
00326 return true;
00327 }
00328
00329 terrain_builder::terrain_constraint terrain_builder::rotate(const terrain_builder::terrain_constraint &constraint, int angle)
00330 {
00331 static const struct { int ii; int ij; int ji; int jj; } rotations[6] =
00332 { { 1, 0, 0, 1 }, { 1, 1, -1, 0 }, { 0, 1, -1, -1 },
00333 { -1, 0, 0, -1 }, { -1, -1, 1, 0 }, { 0, -1, 1, 1 } };
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 static const struct {
00363 double xx;
00364 double xy;
00365 double yx;
00366 double yy;
00367 } xyrotations[6] = {
00368 { 1., 0., 0., 1. },
00369 { 1./2. , -3./4., 1., 1./2. },
00370 { -1./2., -3./4., 1, -1./2.},
00371 { -1. , 0., 0., -1. },
00372 { -1./2., 3./4., -1., -1./2.},
00373 { 1./2. , 3./4., -1., 1./2. },
00374 };
00375
00376 assert(angle >= 0);
00377
00378 angle %= 6;
00379 terrain_constraint ret = constraint;
00380
00381
00382 int vi = ret.loc.y - ret.loc.x/2;
00383 int vj = ret.loc.x;
00384
00385 int ri = rotations[angle].ii * vi + rotations[angle].ij * vj;
00386 int rj = rotations[angle].ji * vi + rotations[angle].jj * vj;
00387
00388 ret.loc.x = rj;
00389 ret.loc.y = ri + (rj >= 0 ? rj/2 : (rj-1)/2);
00390
00391 for (rule_imagelist::iterator itor = ret.images.begin();
00392 itor != ret.images.end(); ++itor) {
00393
00394 double vx, vy, rx, ry;
00395
00396 vx = double(itor->basex) - double(TILEWIDTH)/2;
00397 vy = double(itor->basey) - double(TILEWIDTH)/2;
00398
00399 rx = xyrotations[angle].xx * vx + xyrotations[angle].xy * vy;
00400 ry = xyrotations[angle].yx * vx + xyrotations[angle].yy * vy;
00401
00402 itor->basex = int(rx + TILEWIDTH/2);
00403 itor->basey = int(ry + TILEWIDTH/2);
00404
00405
00406
00407 }
00408
00409 return ret;
00410 }
00411
00412 void terrain_builder::replace_token(std::string &s, const std::string &token, const std::string &replacement)
00413 {
00414 size_t pos;
00415
00416 if(token.empty()) {
00417 ERR_NG << "empty token in replace_token\n";
00418 return;
00419 }
00420 while((pos = s.find(token)) != std::string::npos) {
00421 s.replace(pos, token.size(), replacement);
00422 }
00423 }
00424
00425 void terrain_builder::replace_token(terrain_builder::rule_image &image, const std::string &token, const std::string &replacement)
00426 {
00427 rule_image_variantlist::iterator itor;
00428
00429 for(itor = image.variants.begin(); itor != image.variants.end(); ++itor) {
00430 replace_token(itor->second, token, replacement);
00431 }
00432 }
00433
00434 void terrain_builder::replace_token(terrain_builder::rule_imagelist &list, const std::string &token, const std::string &replacement)
00435 {
00436 rule_imagelist::iterator itor;
00437
00438 for(itor = list.begin(); itor != list.end(); ++itor) {
00439 replace_token(*itor, token, replacement);
00440 }
00441 }
00442
00443 void terrain_builder::replace_token(terrain_builder::building_rule &rule, const std::string &token, const std::string& replacement)
00444 {
00445 constraint_set::iterator cons;
00446
00447 for(cons = rule.constraints.begin(); cons != rule.constraints.end(); ++cons) {
00448
00449 std::vector<std::string>::iterator flag;
00450
00451 for(flag = cons->second.set_flag.begin(); flag != cons->second.set_flag.end(); flag++) {
00452 replace_token(*flag, token, replacement);
00453 }
00454 for(flag = cons->second.no_flag.begin(); flag != cons->second.no_flag.end(); flag++) {
00455 replace_token(*flag, token, replacement);
00456 }
00457 for(flag = cons->second.has_flag.begin(); flag != cons->second.has_flag.end(); flag++) {
00458 replace_token(*flag, token, replacement);
00459 }
00460 replace_token(cons->second.images, token, replacement);
00461 }
00462
00463
00464 }
00465
00466 terrain_builder::building_rule terrain_builder::rotate_rule(const terrain_builder::building_rule &rule,
00467 int angle, const std::vector<std::string>& rot)
00468 {
00469 building_rule ret;
00470 if(rot.size() != 6) {
00471 ERR_NG << "invalid rotations\n";
00472 return ret;
00473 }
00474 ret.location_constraints = rule.location_constraints;
00475 ret.probability = rule.probability;
00476 ret.precedence = rule.precedence;
00477
00478 constraint_set tmp_cons;
00479 constraint_set::const_iterator cons;
00480 for(cons = rule.constraints.begin(); cons != rule.constraints.end(); ++cons) {
00481 const terrain_constraint &rcons = rotate(cons->second, angle);
00482
00483 tmp_cons[rcons.loc] = rcons;
00484 }
00485
00486
00487 int minx = INT_MAX;
00488 int miny = INT_MAX;
00489
00490 constraint_set::iterator cons2;
00491 for(cons2 = tmp_cons.begin(); cons2 != tmp_cons.end(); ++cons2) {
00492 minx = minimum<int>(cons2->second.loc.x, minx);
00493 miny = minimum<int>(2*cons2->second.loc.y + (cons2->second.loc.x & 1), miny);
00494 }
00495
00496 if((miny & 1) && (minx & 1) && (minx < 0))
00497 miny += 2;
00498 if(!(miny & 1) && (minx & 1) && (minx > 0))
00499 miny -= 2;
00500
00501 for(cons2 = tmp_cons.begin(); cons2 != tmp_cons.end(); ++cons2) {
00502
00503 cons2->second.loc += gamemap::location(-minx, -((miny-1)/2));
00504 ret.constraints[cons2->second.loc] = cons2->second;
00505 }
00506
00507 for(int i = 0; i < 6; ++i) {
00508 int a = (angle+i) % 6;
00509 std::string token = "@R";
00510 push_back(token,'0' + i);
00511 replace_token(ret, token, rot[a]);
00512 }
00513
00514 return ret;
00515 }
00516
00517 void terrain_builder::add_images_from_config(rule_imagelist& images, const config &cfg, bool global, int dx, int dy)
00518 {
00519 const config::child_list& cimages = cfg.get_children("image");
00520
00521
00522 for(config::child_list::const_iterator img = cimages.begin(); img != cimages.end(); ++img) {
00523
00524 const std::string &name = (**img)["name"];
00525 const int layer = lexical_cast_default<int>((**img)["layer"], 0);
00526
00527 int basex = 0, basey = 0;
00528 if((**img)["base"].empty()) {
00529 basex = TILEWIDTH / 2 + dx;
00530 basey = TILEWIDTH / 2 + dy;
00531 } else {
00532 std::vector<std::string> base = utils::split((**img)["base"]);
00533
00534 if(base.size() >= 2) {
00535 basex = atoi(base[0].c_str());
00536 basey = atoi(base[1].c_str());
00537 }
00538 }
00539
00540 int center_x = -1, center_y = -1;
00541 if( !(**img)["center"].empty()) {
00542 std::vector<std::string> center = utils::split((**img)["center"]);
00543
00544 if(center.size() >= 2) {
00545 center_x = atoi(center[0].c_str());
00546 center_y = atoi(center[1].c_str());
00547 }
00548 }
00549
00550 images.push_back(rule_image(layer, basex - dx, basey - dy, global, center_x, center_y));
00551
00552
00553 images.back().variants.insert(std::pair<std::string, rule_image_variant>("", rule_image_variant(name,"")));
00554
00555
00556 const config::child_list& variants = (**img).get_children("variant");
00557
00558 for(config::child_list::const_iterator variant = variants.begin();
00559 variant != variants.end(); ++variant) {
00560 const std::string &name = (**variant)["name"];
00561 const std::string &tod = (**variant)["tod"];
00562
00563 images.back().variants.insert(std::pair<std::string, rule_image_variant>(tod, rule_image_variant(name,tod)));
00564
00565 }
00566 }
00567 }
00568
00569 void terrain_builder::add_constraints(
00570 terrain_builder::constraint_set& constraints,
00571 const gamemap::location& loc,
00572 const t_translation::t_match& type, const config& global_images)
00573 {
00574 if(constraints.find(loc) == constraints.end()) {
00575
00576 constraints[loc] = terrain_constraint(loc);
00577 }
00578
00579 if(!type.terrain.empty()) {
00580 constraints[loc].terrain_types_match = type;
00581 }
00582
00583 int x = loc.x * TILEWIDTH * 3 / 4;
00584 int y = loc.y * TILEWIDTH + (loc.x % 2) * TILEWIDTH / 2;
00585 add_images_from_config(constraints[loc].images, global_images, true, x, y);
00586 }
00587
00588 void terrain_builder::add_constraints(terrain_builder::constraint_set &constraints,
00589 const gamemap::location& loc, const config& cfg, const config& global_images)
00590
00591 {
00592 add_constraints(constraints, loc, t_translation::t_match(cfg["type"], t_translation::WILDCARD), global_images);
00593
00594 terrain_constraint& constraint = constraints[loc];
00595
00596 std::vector<std::string> item_string = utils::split(cfg["set_flag"]);
00597 constraint.set_flag.insert(constraint.set_flag.end(),
00598 item_string.begin(), item_string.end());
00599
00600 item_string = utils::split(cfg["has_flag"]);
00601 constraint.has_flag.insert(constraint.has_flag.end(),
00602 item_string.begin(), item_string.end());
00603
00604 item_string = utils::split(cfg["no_flag"]);
00605 constraint.no_flag.insert(constraint.no_flag.end(),
00606 item_string.begin(), item_string.end());
00607
00608 add_images_from_config(constraint.images, cfg, false);
00609 }
00610
00611 void terrain_builder::parse_mapstring(const std::string &mapstring,
00612 struct building_rule &br, anchormap& anchors,
00613 const config& global_images)
00614 {
00615
00616 const t_translation::t_map map = t_translation::read_builder_map(mapstring);
00617
00618
00619
00620
00621 if(map.empty()) {
00622 return;
00623 }
00624
00625 int lineno = (map[0][0] == t_translation::NONE_TERRAIN) ? 1 : 0;
00626 int x = lineno;
00627 int y = 0;
00628 for(size_t y_off = 0; y_off < map.size(); ++y_off) {
00629 for(size_t x_off = x; x_off < map[y_off].size(); ++x_off) {
00630
00631 const t_translation::t_terrain terrain = map[y_off][x_off];
00632
00633 if(terrain.base == t_translation::TB_DOT) {
00634
00635
00636 } else if (terrain.overlay != 0 ) {
00637 anchors.insert(std::pair<int, gamemap::location>(terrain.overlay, gamemap::location(x, y)));
00638 } else if (terrain.base == t_translation::TB_STAR) {
00639 add_constraints(br.constraints, gamemap::location(x, y), t_translation::STAR, global_images);
00640 } else {
00641 ERR_NG << "Invalid terrain (" << t_translation::write_terrain_code(terrain) << ") in builder map\n";
00642 assert(false);
00643 return;
00644 }
00645 x += 2;
00646 }
00647
00648 if(lineno % 2 == 1) {
00649 ++y;
00650 x = 0;
00651 } else {
00652 x = 1;
00653 }
00654 ++lineno;
00655 }
00656 }
00657
00658 void terrain_builder::add_rule(building_ruleset& rules, building_rule &rule)
00659 {
00660 if(rule_valid(rule)) {
00661 start_animation(rule);
00662 rules.insert(std::pair<int, building_rule>(rule.precedence, rule));
00663 }
00664 }
00665
00666 void terrain_builder::add_rotated_rules(building_ruleset& rules, building_rule& tpl, const std::string &rotations)
00667 {
00668 if(rotations.empty()) {
00669
00670
00671 add_rule(rules, tpl);
00672 } else {
00673 const std::vector<std::string>& rot = utils::split(rotations, ',');
00674
00675 for(size_t angle = 0; angle < rot.size(); angle++) {
00676 building_rule rule = rotate_rule(tpl, angle, rot);
00677 add_rule(rules, rule);
00678 }
00679 }
00680 }
00681
00682 void terrain_builder::parse_config(const config &cfg)
00683 {
00684 log_scope("terrain_builder::parse_config");
00685
00686
00687 const config::child_list& brs = cfg.get_children("terrain_graphics");
00688
00689 for(config::child_list::const_iterator br = brs.begin(); br != brs.end(); ++br) {
00690 building_rule pbr;
00691
00692
00693
00694 if(!((**br)["x"].empty() || (**br)["y"].empty()))
00695 pbr.location_constraints = gamemap::location(atoi((**br)["x"].c_str())-1, atoi((**br)["y"].c_str())-1);
00696
00697 pbr.probability = (**br)["probability"].empty() ? -1 : atoi((**br)["probability"].c_str());
00698 pbr.precedence = (**br)["precedence"].empty() ? 0 : atoi((**br)["precedence"].c_str());
00699
00700
00701 anchormap anchors;
00702
00703
00704 parse_mapstring((**br)["map"], pbr, anchors, **br);
00705
00706
00707 config::child_list tcs((*br)->get_children("tile"));
00708
00709 for(config::child_list::const_iterator tc = tcs.begin(); tc != tcs.end(); tc++) {
00710
00711
00712 gamemap::location loc;
00713 if((**tc)["x"].size()) {
00714 loc.x = atoi((**tc)["x"].c_str());
00715 }
00716 if((**tc)["y"].size()) {
00717 loc.y = atoi((**tc)["y"].c_str());
00718 }
00719 if(!(**tc)["loc"].empty()) {
00720 std::vector<std::string> sloc = utils::split((**tc)["loc"]);
00721 if(sloc.size() == 2) {
00722 loc.x = atoi(sloc[0].c_str());
00723 loc.y = atoi(sloc[1].c_str());
00724 }
00725 }
00726 if(loc.valid()) {
00727 add_constraints(pbr.constraints, loc, **tc, **br);
00728 }
00729 if((**tc)["pos"].size()) {
00730 int pos = atoi((**tc)["pos"].c_str());
00731 if(anchors.find(pos) == anchors.end()) {
00732 LOG_STREAM(warn, engine) << "Invalid anchor!\n";
00733 continue;
00734 }
00735
00736 std::pair<anchormap::const_iterator, anchormap::const_iterator> range =
00737 anchors.equal_range(pos);
00738
00739 for(; range.first != range.second; range.first++) {
00740 loc = range.first->second;
00741 add_constraints(pbr.constraints, loc, **tc, **br);
00742 }
00743 }
00744 }
00745
00746 const std::string global_set_flag = (**br)["set_flag"];
00747 const std::string global_no_flag = (**br)["no_flag"];
00748 const std::string global_has_flag = (**br)["has_flag"];
00749
00750 for(constraint_set::iterator constraint = pbr.constraints.begin(); constraint != pbr.constraints.end();
00751 constraint++) {
00752
00753 if(global_set_flag.size())
00754 constraint->second.set_flag.push_back(global_set_flag);
00755
00756 if(global_no_flag.size())
00757 constraint->second.no_flag.push_back(global_no_flag);
00758
00759 if(global_has_flag.size())
00760 constraint->second.has_flag.push_back(global_has_flag);
00761
00762 }
00763
00764
00765 const std::string rotations = (**br)["rotations"];
00766
00767 add_rotated_rules(building_rules_, pbr, rotations);
00768
00769 }
00770
00771
00772 #if 0
00773 std::cerr << "Built terrain rules: \n";
00774
00775 building_ruleset::const_iterator rule;
00776 for(rule = building_rules_.begin(); rule != building_rules_.end(); ++rule) {
00777 std::cerr << ">> New rule: image_background = "
00778 << "\n>> Location " << rule->second.location_constraints
00779 << "\n>> Probability " << rule->second.probability
00780 << "\n>> Precedence " << rule->second.precedence << '\n';
00781
00782 for(constraint_set::const_iterator constraint = rule->second.constraints.begin();
00783 constraint != rule->second.constraints.end(); ++constraint) {
00784
00785 std::cerr << ">>>> New constraint: location = (" << constraint->second.loc
00786 << "), terrain types = '" << t_translation::write_list(constraint->second.terrain_types_match.terrain) << "'\n";
00787
00788 std::vector<std::string>::const_iterator flag;
00789
00790 for(flag = constraint->second.set_flag.begin(); flag != constraint->second.set_flag.end(); ++flag) {
00791 std::cerr << ">>>>>> Set_flag: " << *flag << "\n";
00792 }
00793
00794 for(flag = constraint->second.no_flag.begin(); flag != constraint->second.no_flag.end(); ++flag) {
00795 std::cerr << ">>>>>> No_flag: " << *flag << "\n";
00796 }
00797 }
00798
00799 }
00800 #endif
00801
00802 }
00803
00804 void terrain_builder::add_off_map_rule(const std::string& image)
00805 {
00806
00807 config cfg;
00808
00809 cfg.add_child("terrain_graphics");
00810 config *item = cfg.child("terrain_graphics");
00811
00812 (*item).add_child("tile");
00813 config *tile = (*item).child("tile");
00814 (*tile)["x"] = "0";
00815 (*tile)["y"] = "0";
00816 (*tile)["type"] = t_translation::write_terrain_code(t_translation::OFF_MAP_USER);
00817
00818 (*tile).add_child("image");
00819 config *tile_image = (*tile).child("image");
00820 (*tile_image)["layer"] = "-1000";
00821 (*tile_image)["name"] = image;
00822
00823 (*item)["probability"] = "100";
00824 (*item)["no_flag"] = "base";
00825 (*item)["set_flag"] = "base";
00826
00827
00828 parse_config(cfg);
00829 }
00830
00831 bool terrain_builder::rule_matches(const terrain_builder::building_rule &rule,
00832 const gamemap::location &loc, const int rule_index, const constraint_set::const_iterator type_checked) const
00833 {
00834 if(rule.location_constraints.valid() && rule.location_constraints != loc) {
00835 return false;
00836 }
00837
00838 if(rule.probability != -1) {
00839 unsigned int a = (loc.x + 92872973) ^ 918273;
00840 unsigned int b = (loc.y + 1672517) ^ 128123;
00841 unsigned int c = (rule_index + 127390) ^ 13923787;
00842 unsigned int abc = a*b*c + a*b + b*c + a*c + a + b + c;
00843 unsigned int random = (abc*abc) % 100;
00844
00845 if(random > static_cast<unsigned int>(rule.probability)) {
00846 return false;
00847 }
00848 }
00849
00850 for(constraint_set::const_iterator cons = rule.constraints.begin();
00851 cons != rule.constraints.end(); ++cons) {
00852
00853
00854 const gamemap::location tloc = loc + cons->second.loc;
00855
00856 if(!tile_map_.on_map(tloc)) {
00857 return false;
00858 }
00859
00860
00861
00862
00863 if(cons != type_checked &&
00864 !terrain_matches(map_.get_terrain(tloc), cons->second.terrain_types_match)) {
00865 return false;
00866 }
00867
00868 const tile& btile = tile_map_[tloc];
00869
00870 std::vector<std::string>::const_iterator itor;
00871 for(itor = cons->second.no_flag.begin(); itor != cons->second.no_flag.end(); ++itor) {
00872
00873
00874 if(btile.flags.find(*itor) != btile.flags.end()) {
00875 return false;
00876 }
00877 }
00878 for(itor = cons->second.has_flag.begin(); itor != cons->second.has_flag.end(); ++itor) {
00879
00880
00881 if(btile.flags.find(*itor) == btile.flags.end()) {
00882 return false;
00883 }
00884 }
00885 }
00886
00887 return true;
00888 }
00889
00890 void terrain_builder::apply_rule(const terrain_builder::building_rule &rule, const gamemap::location &loc)
00891 {
00892 for(constraint_set::const_iterator constraint = rule.constraints.begin();
00893 constraint != rule.constraints.end(); ++constraint) {
00894
00895 rule_imagelist::const_iterator img;
00896 const gamemap::location tloc = loc + constraint->second.loc;
00897 if(!tile_map_.on_map(tloc)) {
00898 return;
00899 }
00900
00901 tile& btile = tile_map_[tloc];
00902
00903
00904
00905
00906 for(img = constraint->second.images.begin(); img != constraint->second.images.end(); ++img) {
00907 btile.images.insert(std::pair<int, const rule_image*>(
00908 img->layer*BASE_Y_INTERVAL + BASE_Y_INTERVAL/2 + img->basey, &*img));
00909 }
00910
00911
00912 for(std::vector<std::string>::const_iterator itor = constraint->second.set_flag.begin();
00913 itor != constraint->second.set_flag.end(); itor++) {
00914 btile.flags.insert(*itor);
00915 }
00916
00917 }
00918 }
00919
00920 void terrain_builder::build_terrains()
00921 {
00922 log_scope("terrain_builder::build_terrains");
00923
00924
00925 for(int x = -2; x <= map_.w(); ++x) {
00926 for(int y = -2; y <= map_.h(); ++y) {
00927 const gamemap::location loc(x,y);
00928 const t_translation::t_terrain t = map_.get_terrain(loc);
00929
00930 terrain_by_type_[t].push_back(loc);
00931 }
00932 }
00933
00934 int rule_index = 0;
00935 building_ruleset::const_iterator r;
00936
00937 for(r = building_rules_.begin(); r != building_rules_.end(); ++r) {
00938
00939 const building_rule& rule = r->second;
00940
00941
00942
00943
00944 size_t min_size = INT_MAX;
00945 t_translation::t_list min_types;
00946 constraint_set::const_iterator min_constraint = rule.constraints.end();
00947
00948 for(constraint_set::const_iterator constraint = rule.constraints.begin();
00949 constraint != rule.constraints.end(); ++constraint) {
00950
00951 const t_translation::t_match& match = constraint->second.terrain_types_match;
00952 t_translation::t_list matching_types;
00953 size_t constraint_size = 0;
00954
00955 for (terrain_by_type_map::iterator type_it = terrain_by_type_.begin();
00956 type_it != terrain_by_type_.end(); type_it++) {
00957
00958 const t_translation::t_terrain t = type_it->first;
00959 if (terrain_matches(t, match)) {
00960 const size_t match_size = type_it->second.size();
00961 constraint_size += match_size;
00962 if (constraint_size >= min_size) {
00963 break;
00964 }
00965 matching_types.push_back(t);
00966 }
00967 }
00968
00969 if (constraint_size < min_size) {
00970 min_size = constraint_size;
00971 min_types = matching_types;
00972 min_constraint = constraint;
00973 if (min_size == 0) {
00974
00975
00976 break;
00977 }
00978 }
00979 }
00980
00981
00982 for(t_translation::t_list::const_iterator t = min_types.begin();
00983 t != min_types.end(); ++t) {
00984
00985 const std::vector<gamemap::location>* locations = &terrain_by_type_[*t];
00986
00987 for(std::vector<gamemap::location>::const_iterator itor = locations->begin();
00988 itor != locations->end(); ++itor) {
00989 const gamemap::location loc = *itor - min_constraint->second.loc;
00990
00991 if(rule_matches(rule, loc, rule_index, min_constraint)) {
00992 apply_rule(rule, loc);
00993 }
00994 }
00995 }
00996
00997 rule_index++;
00998 }
00999 }