Skip to content

Instantly share code, notes, and snippets.

@tung
Created July 31, 2014 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tung/a214008a21acba8ab026 to your computer and use it in GitHub Desktop.
Save tung/a214008a21acba8ab026 to your computer and use it in GitHub Desktop.
Cataclysm 2 map.cpp coverage (20 steps left with 24-row and 55-row terminal windows)
-: 0:Source:map.cpp
-: 0:Graph:obj/map.gcno
-: 0:Data:obj/map.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include "field.h"
-: 2:#include "map.h"
-: 3:#include "rng.h"
-: 4:#include "globals.h"
-: 5:#include "monster.h"
-: 6:#include "game.h"
-: 7:#include "attack.h"
-: 8:#include "entity.h"
-: 9:#include "enum.h"
-: 10:#include "worldmap.h"
-: 11:#include "files.h" // For SAVE_DIR
-: 12:#include <fstream>
-: 13:#include <sstream>
-: 14:
1454376: 15:Furniture::Furniture()
-: 16:{
1454376: 17: type = NULL;
1454376: 18: uid = -1;
1454376: 19:}
-: 20:
1454376: 21:Furniture::~Furniture()
-: 22:{
1454376: 23:}
-: 24:
306: 25:void Furniture::set_type(Furniture_type* t)
-: 26:{
306: 27: type = t;
306: 28: if (type) {
306: 29: hp = type->hp;
-: 30: }
306: 31:}
-: 32:
306: 33:void Furniture::set_uid(int id)
-: 34:{
306: 35: uid = id;
306: 36:}
-: 37:
29811: 38:bool Furniture::is_real()
-: 39:{
29811: 40: return (type);
-: 41:}
-: 42:
#####: 43:int Furniture::get_uid()
-: 44:{
#####: 45: return uid;
-: 46:}
-: 47:
#####: 48:glyph Furniture::get_glyph()
-: 49:{
#####: 50: if (!type) {
#####: 51: return glyph();
-: 52: }
#####: 53: glyph ret = type->sym;
#####: 54: if (is_smashable() && hp > 0 && hp < type->hp) {
#####: 55: int percent = (100 * hp) / type->hp;
#####: 56: if (percent >= 80) {
#####: 57: ret = ret.hilite(c_green);
#####: 58: } else if (percent >= 40) {
#####: 59: ret = ret.hilite(c_brown);
-: 60: } else {
#####: 61: ret = ret.hilite(c_red);
-: 62: }
-: 63: }
#####: 64: return ret;
-: 65:}
-: 66:
#####: 67:int Furniture::move_cost()
-: 68:{
#####: 69: if (!type) {
#####: 70: return 100;
-: 71: }
#####: 72: return type->move_cost;
-: 73:}
-: 74:
#####: 75:int Furniture::get_height()
-: 76:{
#####: 77: if (!type) {
#####: 78: return 0;
-: 79: }
#####: 80: return type->height;
-: 81:}
-: 82:
#####: 83:int Furniture::get_weight()
-: 84:{
#####: 85: if (!type) {
#####: 86: return 0;
-: 87: }
#####: 88: return type->weight;
-: 89:}
-: 90:
#####: 91:std::string Furniture::get_name()
-: 92:{
#####: 93: if (!type) {
#####: 94: return "";
-: 95: }
#####: 96: return type->get_name();
-: 97:}
-: 98:
#####: 99:bool Furniture::has_flag(Terrain_flag flag)
-: 100:{
#####: 101: return (type && type->has_flag(flag));
-: 102:}
-: 103:
#####: 104:bool Furniture::is_smashable()
-: 105:{
#####: 106: return (type && type->smashable);
-: 107:}
-: 108:
#####: 109:std::string Furniture::smash(Damage_set dam)
-: 110:{
#####: 111: if (!is_smashable()) { // This verifies that terrain != NULL
#####: 112: return "";
-: 113: }
#####: 114: Terrain_smash smash = type->smash;
#####: 115: if (rng(1, 100) <= smash.ignore_chance) {
#####: 116: return smash.failure_sound; // Make our "saving throw"
-: 117: }
#####: 118: if (damage(dam)) {
#####: 119: return smash.success_sound;
-: 120: }
#####: 121: return smash.failure_sound;
-: 122:}
-: 123:
-: 124:// Roll all damage types, but only apply whichever is the best.
#####: 125:bool Furniture::damage(Damage_set dam)
-: 126:{
#####: 127: if (!type || type->hp == 0) {
#####: 128: return false;
-: 129: }
-: 130:
#####: 131: int best_dmg = 0;
#####: 132: for (int i = 0; i < DAMAGE_MAX; i++) {
#####: 133: Damage_type damtype = Damage_type(i);
#####: 134: int dmg = dam.get_damage(damtype) - type->smash.armor[damtype].roll();
#####: 135: if (dmg > best_dmg) {
#####: 136: best_dmg = dmg;
-: 137: }
-: 138: }
-: 139:
#####: 140: hp -= best_dmg;
#####: 141: if (hp <= 0) {
#####: 142: return true;
-: 143: }
#####: 144: return false;
-: 145:}
-: 146:
#####: 147:bool Furniture::damage(Damage_type damtype, int dam)
-: 148:{
#####: 149: if (dam <= 0) {
#####: 150: return false;
-: 151: }
#####: 152: if (!type || type->hp == 0) {
#####: 153: return false;
-: 154: }
#####: 155: Dice armor = type->smash.armor[damtype];
#####: 156: dam -= armor.roll();
#####: 157: if (dam <= 0) {
#####: 158: return false;
-: 159: }
#####: 160: hp -= dam;
#####: 161: if (hp <= 0) {
#####: 162: return true;
-: 163: }
#####: 164: return false;
-: 165:}
-: 166:
#####: 167:void Furniture::destroy()
-: 168:{
#####: 169: type = NULL;
#####: 170: uid = -1;
#####: 171:}
-: 172:
#####: 173:std::string Furniture::save_data()
-: 174:{
#####: 175: if (!type) {
#####: 176: return "Done";
-: 177: }
-: 178:
#####: 179: std::stringstream ret;
-: 180:
#####: 181: ret << "Type: " << type->name << std::endl; // Name is a persistant unique ID
#####: 182: ret << "HP: " << hp << std::endl;
#####: 183: ret << "UID: " << uid << std::endl;
#####: 184: ret << "Done";
-: 185:
#####: 186: return ret.str();
-: 187:}
-: 188:
#####: 189:bool Furniture::load_data(std::istream& data)
-: 190:{
#####: 191: std::string ident, junk;
#####: 192: while (ident != "done" && !data.eof()) {
#####: 193: if ( ! (data >> ident) ) {
#####: 194: debugmsg("Couldn't read Furniture data.");
#####: 195: return false;
-: 196: }
#####: 197: ident = no_caps( ident );
-: 198:
#####: 199: if (ident == "type:") {
#####: 200: std::string tmpname;
#####: 201: std::getline(data, tmpname);
#####: 202: tmpname = trim( tmpname );
#####: 203: type = FURNITURE_TYPES.lookup_name(tmpname);
#####: 204: if (!type) {
#####: 205: debugmsg("Unknown furniture '%s'", tmpname.c_str());
#####: 206: return false;
#####: 207: }
-: 208:
#####: 209: } else if (ident == "hp:") {
#####: 210: data >> hp;
#####: 211: std::getline(data, junk);
-: 212:
#####: 213: } else if (ident == "uid:") {
#####: 214: data >> uid;
#####: 215: std::getline(data, junk);
-: 216:
#####: 217: } else if (ident != "done") {
#####: 218: debugmsg("Unknown furniture identifier '%s'", ident.c_str());
#####: 219: return false;
-: 220: }
-: 221: }
#####: 222: return true;
-: 223:}
-: 224:
1484767: 225:void Tile::set_terrain(Terrain* ter)
-: 226:{
1484767: 227: if (!ter) {
#####: 228: debugmsg("Tile::set_terrain(NULL)!");
1484767: 229: return;
-: 230: }
1484767: 231: terrain = ter;
1484767: 232: hp = ter->hp;
-: 233:}
-: 234:
306: 235:void Tile::add_furniture(Furniture_type* type, int uid)
-: 236:{
306: 237: if (!type) {
#####: 238: debugmsg("Tile::add_furniture(NULL)!");
306: 239: return;
-: 240: }
-: 241:
306: 242: furniture.set_type(type);
306: 243: furniture.set_uid(uid);
-: 244:}
-: 245:
#####: 246:void Tile::add_furniture(Furniture furn)
-: 247:{
#####: 248: furniture = furn;
#####: 249:}
-: 250:
#####: 251:void Tile::remove_furniture()
-: 252:{
#####: 253: furniture.set_type(NULL);
#####: 254:}
-: 255:
12075: 256:glyph Tile::top_glyph()
-: 257:{
12075: 258: if (field.is_valid()) {
#####: 259: return field.top_glyph();
-: 260: }
12075: 261: if (furniture.is_real()) {
#####: 262: return furniture.get_glyph();
-: 263: }
12075: 264: if (!items.empty() && (!has_flag(TF_SEALED) || !has_flag(TF_OPAQUE))) {
335: 265: if (terrain && !terrain->has_flag(TF_FLOOR)) {
15: 266: return terrain->sym.hilite(c_blue);
-: 267: }
320: 268: glyph ret = items.back().top_glyph();
320: 269: if (items.size() > 1) {
#####: 270: ret = ret.invert();
-: 271: }
320: 272: return ret;
-: 273: }
11740: 274: if (!terrain) {
#####: 275: return glyph();
-: 276: }
11740: 277: glyph ret = terrain->sym;
11740: 278: if (is_smashable() && terrain->hp > 0 && hp < terrain->hp) {
#####: 279: int percent = (100 * hp) / terrain->hp;
#####: 280: if (percent >= 80) {
#####: 281: ret = ret.hilite(c_green);
#####: 282: } else if (percent >= 40) {
#####: 283: ret = ret.hilite(c_brown);
-: 284: } else {
#####: 285: ret = ret.hilite(c_red);
-: 286: }
-: 287: }
11740: 288: return ret;
-: 289:}
-: 290:
5976: 291:int Tile::move_cost()
-: 292:{
5976: 293: if (furniture.is_real()) {
#####: 294: return furniture.move_cost();
-: 295: }
5976: 296: if (!terrain) {
#####: 297: return 0;
-: 298: }
5976: 299: return (terrain->movecost);
-: 300:}
-: 301:
#####: 302:int Tile::get_height()
-: 303:{
#####: 304: int ret = (terrain ? terrain->height : 0);
#####: 305: if (furniture.is_real()) {
#####: 306: ret += furniture.get_height();
-: 307: }
#####: 308: return ret;
-: 309:}
-: 310:
20: 311:std::string Tile::get_name()
-: 312:{
20: 313: std::stringstream ret;
20: 314: if (furniture.is_real()) {
#####: 315: ret << furniture.get_name() << " on ";
-: 316: }
20: 317: ret << (terrain ? terrain->get_name() : "<c=red>BUG - Unknown<c=/>");
-: 318:
20: 319: return ret.str();
-: 320:}
-: 321:
#####: 322:std::string Tile::get_name_indefinite()
-: 323:{
#####: 324: std::stringstream ret;
#####: 325: if (furniture.is_real()) {
#####: 326: ret << (furniture.has_flag(TF_PLURAL) ? "some" : "a") << " " <<
#####: 327: furniture.get_name() << " on ";
-: 328: }
#####: 329: if (terrain) {
#####: 330: ret << (terrain->has_flag(TF_PLURAL) ? "some" : "a") << " " <<
#####: 331: terrain->get_name();
-: 332: } else {
#####: 333: ret << "<c=red>BUG - Unknown<c=/>";
-: 334: }
#####: 335: return ret.str();
-: 336:}
-: 337:
779625: 338:bool Tile::blocks_sense(Sense_type sense, int z_value)
-: 339:{
779625: 340: if (!terrain) {
#####: 341: return false;
-: 342: }
-: 343:
779625: 344: switch (sense) {
-: 345:
-: 346: case SENSE_NULL:
#####: 347: return true;
-: 348:
-: 349: case SENSE_SIGHT:
779625: 350: if (field.is_valid() && field.has_flag(TF_OPAQUE)) {
#####: 351: return true;
779625: 352: } else if (has_flag(TF_OPAQUE) && z_value <= get_height()) {
#####: 353: return true;
-: 354: }
779625: 355: return false;
-: 356:
-: 357: case SENSE_SOUND:
#####: 358: return false;
-: 359:
-: 360: case SENSE_ECHOLOCATION:
#####: 361: return (move_cost() == 0);
-: 362:
-: 363: case SENSE_SMELL:
#####: 364: return (move_cost() == 0);
-: 365:
-: 366: case SENSE_OMNISCIENT:
#####: 367: return false;
-: 368:
-: 369: case SENSE_MAX:
#####: 370: return false;
-: 371:
-: 372: }
#####: 373: return false;
-: 374:}
-: 375:
793465: 376:bool Tile::has_flag(Terrain_flag flag)
-: 377:{
793465: 378: if (field.is_valid() && field.has_flag(flag)) {
#####: 379: return true;
-: 380: }
793465: 381: if (!terrain) {
#####: 382: return false;
-: 383: }
793465: 384: return terrain->has_flag(flag);
-: 385:}
-: 386:
#####: 387:bool Tile::has_field()
-: 388:{
#####: 389: return field.is_valid();
-: 390:}
-: 391:
#####: 392:bool Tile::has_furniture()
-: 393:{
#####: 394: return furniture.is_real();
-: 395:}
-: 396:
11740: 397:bool Tile::is_smashable()
-: 398:{
11740: 399: if (furniture.is_real() && furniture.is_smashable()) {
#####: 400: return true;
-: 401: }
11740: 402: return (terrain && terrain->can_smash());
-: 403:}
-: 404:
#####: 405:std::string Tile::smash(Damage_set dam)
-: 406:{
-: 407:// First check furniture
#####: 408: if (furniture.is_real()) {
#####: 409: std::string sound = furniture.smash(dam);
#####: 410: if (furniture.hp <= 0) { // We destroyed the furniture!
-: 411:// First, add all items in the furniture's type list
#####: 412: Item_group* furn_items = furniture.type->components;
#####: 413: if (furn_items) {
#####: 414: for (int i = 0; i < furn_items->item_types.size(); i++) {
#####: 415: Item it(furn_items->item_types[i].item);
#####: 416: for (int n = 0; n < furn_items->item_types[i].number; n++) {
#####: 417: items.push_back(it);
-: 418: }
#####: 419: }
-: 420: }
-: 421:// Next, destroy the furniture
#####: 422: furniture.destroy();
-: 423: }
#####: 424: return sound; // We smashed furniture, we don't get to smash terrain too!
-: 425: }
-: 426:
#####: 427: if (!is_smashable()) { // This also verifies that terrain != NULL
#####: 428: return "";
-: 429: }
-: 430:
#####: 431: Terrain_smash smash = terrain->smash;
-: 432:
#####: 433: if (rng(1, 100) <= smash.ignore_chance) {
#####: 434: return smash.failure_sound; // Make our "saving throw"
-: 435: }
-: 436:
#####: 437: if (damage(dam)) {
#####: 438: return smash.success_sound;
-: 439: }
-: 440:
#####: 441: return smash.failure_sound;
-: 442:}
-: 443:
-: 444:// Roll all damage types; but only actually use the very best one.
#####: 445:bool Tile::damage(Damage_set dam)
-: 446:{
#####: 447: if (!terrain || terrain->hp == 0) {
#####: 448: return false;
-: 449: }
-: 450:
#####: 451: int best_dmg = 0;
#####: 452: for (int i = 0; i < DAMAGE_MAX; i++) {
#####: 453: Damage_type damtype = Damage_type(i);
#####: 454: int dmg = dam.get_damage(damtype) - terrain->smash.armor[damtype].roll();
#####: 455: if (dmg > best_dmg) {
#####: 456: best_dmg = dmg;
-: 457: }
-: 458: }
-: 459:
#####: 460: hp -= best_dmg;
#####: 461: if (hp <= 0) {
#####: 462: destroy();
#####: 463: return true;
-: 464: }
#####: 465: return false;
-: 466:}
-: 467:
#####: 468:bool Tile::damage(Damage_type type, int dam)
-: 469:{
#####: 470: if (dam <= 0) {
#####: 471: return false;
-: 472: }
#####: 473: if (!terrain || terrain->hp == 0) {
#####: 474: return false;
-: 475: }
#####: 476: Dice armor = terrain->smash.armor[type];
#####: 477: dam -= armor.roll();
#####: 478: if (dam <= 0) {
#####: 479: return false;
-: 480: }
#####: 481: hp -= dam;
#####: 482: if (hp <= 0) {
#####: 483: destroy();
#####: 484: return true;
-: 485: }
#####: 486: return false;
-: 487:}
-: 488:
#####: 489:void Tile::destroy()
-: 490:{
-: 491:// If HP is negative, then we run damage *again* with the extra damage
#####: 492: int extra = 0 - hp;
#####: 493: Terrain* result = TERRAIN.lookup_name( terrain->destroy_result );
#####: 494: if (!result) {
-: 495: debugmsg("Tried to destroy '%s' but couldn't look up result '%s'.",
#####: 496: get_name().c_str(), terrain->destroy_result.c_str());
-: 497: } else {
#####: 498: set_terrain(result);
#####: 499: damage(DAMAGE_NULL, extra); // See above
-: 500: }
#####: 501:}
-: 502:
#####: 503:bool Tile::signal_applies(std::string signal)
-: 504:{
#####: 505: signal = no_caps(signal);
#####: 506: signal = trim(signal);
#####: 507: if (!terrain || terrain->signal_handlers.count(signal) == 0) {
#####: 508: return false;
-: 509: }
#####: 510: return true;
-: 511:}
-: 512:
#####: 513:bool Tile::apply_signal(std::string signal, Entity* user)
-: 514:{
#####: 515: signal = no_caps(signal);
#####: 516: signal = trim(signal);
#####: 517: std::string user_name = "";
-: 518:
#####: 519: if (user) {
#####: 520: user_name = user->get_name_to_player();
-: 521: }
-: 522:
#####: 523: if (!terrain || !signal_applies(signal)) {
#####: 524: if (user) {
#####: 525: GAME.add_msg("Nothing to %s there.", user_name.c_str(), signal.c_str());
-: 526: }
#####: 527: return false;
-: 528: }
-: 529:
#####: 530: Terrain_signal_handler handler = terrain->signal_handlers[signal];
-: 531:
#####: 532: int success = handler.success_rate;
-: 533:// Apply bonuses, if the user exists
#####: 534: if (user) {
-: 535:// Terrain bonuses - check the flags for the terrain the user is on
-: 536:// Kind of weird to check GAME.map from a tile, but... eh
#####: 537: Tile* user_tile = GAME.map->get_tile(user->pos);
#####: 538: if (user_tile) {
#####: 539: for (std::list<Terrain_flag_bonus>::iterator it =
#####: 540: handler.terrain_flag_bonuses.begin();
#####: 541: it != handler.terrain_flag_bonuses.end();
-: 542: it++) {
#####: 543: if (user_tile->has_flag( it->flag )) {
#####: 544: success += it->amount;
-: 545: }
-: 546: }
-: 547: }
-: 548:// Stat bonuses
#####: 549: for (std::list<Stat_bonus>::iterator it = handler.stat_bonuses.begin();
#####: 550: it != handler.stat_bonuses.end();
-: 551: it++) {
#####: 552: int stat = 0;
#####: 553: switch (it->stat) {
#####: 554: case STAT_STRENGTH: stat = user->stats.strength; break;
#####: 555: case STAT_DEXTERITY: stat = user->stats.dexterity; break;
#####: 556: case STAT_INTELLIGENCE: stat = user->stats.intelligence; break;
#####: 557: case STAT_PERCEPTION: stat = user->stats.perception; break;
-: 558: }
-: 559:// Apply stat in different ways, depending on the operator used...
#####: 560: switch (it->op) {
-: 561:
-: 562: case MATH_MULTIPLY:
#####: 563: success += stat * it->amount;
#####: 564: break;
-: 565:
-: 566: case MATH_GREATER_THAN:
#####: 567: if (stat > it->amount) {
#####: 568: success += it->amount_static;
-: 569: }
#####: 570: break;
-: 571:
-: 572: case MATH_GREATER_THAN_OR_EQUAL_TO:
#####: 573: if (stat >= it->amount) {
#####: 574: success += it->amount_static;
-: 575: }
#####: 576: break;
-: 577:
-: 578: case MATH_LESS_THAN:
#####: 579: if (stat < it->amount) {
#####: 580: success += it->amount_static;
-: 581: }
#####: 582: break;
-: 583:
-: 584: case MATH_LESS_THAN_OR_EQUAL_TO:
#####: 585: if (stat <= it->amount) {
#####: 586: success += it->amount_static;
-: 587: }
#####: 588: break;
-: 589:
-: 590: case MATH_EQUAL_TO:
#####: 591: if (stat == it->amount) {
#####: 592: success += it->amount_static;
-: 593: }
#####: 594: break;
-: 595:
-: 596: default:
#####: 597: debugmsg("Tile::apply_signal encountered unknown operator");
#####: 598: return false;
-: 599: } // switch (it->symbol)
-: 600: } // Iterator over handler.bonuses
-: 601: } // if (user)
-: 602:
-: 603:// We've finalized our success rate; now roll against it
-: 604:
#####: 605: if (success <= 0) {
#####: 606: if (user) {
-: 607: GAME.add_msg("<c=red>%s (0 percent success rate)<c=/>",
#####: 608: handler.failure_message.c_str());
-: 609: }
#####: 610: return true; // True since we *tried*
-: 611:
#####: 612: } else if (rng(1, 100) <= success) {
-: 613:// Success!
#####: 614: if (handler.success_message.empty()) {
#####: 615: if (user) {
-: 616: GAME.add_msg("<c=ltred>%s %s the %s.<c=/>",
#####: 617: user_name.c_str(), signal.c_str(), get_name().c_str());
-: 618: }
#####: 619: } else if (user) {
#####: 620: std::stringstream mes;
#####: 621: mes << "<c=ltred>" << handler.success_message << "<c=/>";
#####: 622: GAME.add_msg(mes.str());
-: 623: }
#####: 624: Terrain* result = TERRAIN.lookup_name(handler.result);
#####: 625: if (!result) {
-: 626: debugmsg("Tile::apply_signal couldn't find terrain '%s'! (%s)",
#####: 627: handler.result.c_str(), get_name().c_str());
#####: 628: return false;
-: 629: }
#####: 630: terrain = result;
#####: 631: return true;
-: 632: }
-: 633:// Failure.
#####: 634: if (user) {
#####: 635: GAME.add_msg( handler.failure_message );
-: 636: }
#####: 637: return true; // True cause we still *tried* to...
-: 638:}
-: 639:
#####: 640:std::string Tile::save_data()
-: 641:{
#####: 642: if (!terrain) {
#####: 643: return "Done";
-: 644: }
-: 645:
#####: 646: std::stringstream ret;
-: 647:
#####: 648: ret << "Type: " << terrain->name << std::endl; // Name is a persistant UID
#####: 649: ret << "HP: " << hp << std::endl;
#####: 650: if (field.is_valid()) {
#####: 651: ret << "Field: " << field.save_data() << std::endl;
-: 652: }
#####: 653: if (furniture.is_real()) {
#####: 654: ret << "Furniture: " << std::endl << furniture.save_data() << std::endl;
-: 655: }
#####: 656: for (int i = 0; i < items.size(); i++) {
#####: 657: ret << "Item: " << std::endl << items[i].save_data() << std::endl;
-: 658: }
-: 659:
#####: 660: ret << "Done";
-: 661:
#####: 662: return ret.str();
-: 663:}
-: 664:
#####: 665:bool Tile::load_data(std::istream& data)
-: 666:{
#####: 667: std::string ident, junk;
#####: 668: while (ident != "done" && !data.eof()) {
#####: 669: if ( ! (data >> ident) ) {
#####: 670: debugmsg("Couldn't read data (Tile).");
#####: 671: return false;
-: 672: }
#####: 673: ident = no_caps(ident);
-: 674:
#####: 675: if (ident == "type:") {
#####: 676: std::string tmpname;
#####: 677: std::getline(data, tmpname);
#####: 678: tmpname = trim(tmpname);
#####: 679: terrain = TERRAIN.lookup_name(tmpname);
#####: 680: if (!terrain) {
#####: 681: debugmsg("Unknown Terrain '%s'", tmpname.c_str());
#####: 682: return false;
#####: 683: }
-: 684:
#####: 685: } else if (ident == "hp:") {
#####: 686: data >> hp;
#####: 687: std::getline(data, junk);
-: 688:
#####: 689: } else if (ident == "field:") {
#####: 690: if (!field.load_data(data)) {
#####: 691: field = Field();
-: 692: }
-: 693:
#####: 694: } else if (ident == "furniture:") {
#####: 695: if (!furniture.load_data(data)) {
#####: 696: furniture = Furniture();
-: 697: }
-: 698:
#####: 699: } else if (ident == "item:") {
#####: 700: Item tmpit;
#####: 701: if (tmpit.load_data(data)) {
#####: 702: items.push_back(tmpit);
#####: 703: }
-: 704:
#####: 705: } else if (ident != "done") {
#####: 706: debugmsg("Unknown Tile property '%s'", ident.c_str());
#####: 707: return false;
-: 708: }
-: 709: }
#####: 710: return true;
-: 711:}
-: 712:
2327: 713:Submap::Submap()
-: 714:{
2327: 715: spec_used = NULL;
2327: 716: rotation = DIR_NULL;
2327: 717: level = 0;
2327: 718:}
-: 719:
1459029: 720:Submap::~Submap()
-: 721:{
1459029: 722:}
-: 723:
#####: 724:void Submap::generate_empty()
-: 725:{
#####: 726: Terrain* grass = TERRAIN.lookup_name("grass");
#####: 727: Terrain* dirt = TERRAIN.lookup_name("dirt");
#####: 728: if (!grass || !dirt) {
#####: 729: debugmsg("Couldn't find terrain for generate_empty()");
#####: 730: return;
-: 731: }
-: 732:
#####: 733: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 734: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 735: tiles[x][y].set_terrain(one_in(2) ? grass : dirt);
-: 736: }
-: 737: }
-: 738:}
-: 739:
302: 740:void Submap::generate_open()
-: 741:{
302: 742: Terrain* open = TERRAIN.lookup_name("empty");
302: 743: if (!open) {
#####: 744: debugmsg("Couldn't find terrain 'empty'; Submap::generate_open()");
302: 745: return;
-: 746: }
-: 747:
7852: 748: for (int x = 0; x < SUBMAP_SIZE; x++) {
196300: 749: for (int y = 0; y < SUBMAP_SIZE; y++) {
188750: 750: tiles[x][y].set_terrain(open);
-: 751: }
-: 752: }
-: 753:}
-: 754:
2025: 755:void Submap::generate(Worldmap* map, int posx, int posy, int posz)
-: 756:{
2025: 757: if (!map) {
#####: 758: debugmsg("Submap::generate(NULL, %d, %d)", posx, posy);
#####: 759: generate_empty();
#####: 760: return;
-: 761: }
2025: 762: Worldmap_tile *tile = map->get_tile(posx, posy);
2025: 763: if (!tile) {
#####: 764: generate_empty();
#####: 765: return;
-: 766: }
-: 767: World_terrain* ter[5];
2025: 768: ter[0] = tile->terrain;
-: 769:// North
2025: 770: tile = map->get_tile(posx, posy - 1);
2025: 771: ter[1] = (tile ? tile->terrain : NULL);
-: 772:// East
2025: 773: tile = map->get_tile(posx + 1, posy);
2025: 774: ter[2] = (tile ? tile->terrain : NULL);
-: 775:// South
2025: 776: tile = map->get_tile(posx, posy + 1);
2025: 777: ter[3] = (tile ? tile->terrain : NULL);
-: 778:// West
2025: 779: tile = map->get_tile(posx - 1, posy);
2025: 780: ter[4] = (tile ? tile->terrain : NULL);
-: 781:
2025: 782: generate(ter, posz);
-: 783:}
-: 784:
2025: 785:void Submap::generate(World_terrain* terrain[5], int posz)
-: 786:{
2025: 787: if (!terrain[0]) {
#####: 788: generate_empty();
-: 789: } else {
2025: 790: std::vector<bool> neighbor;
2025: 791: Mapgen_spec* spec = NULL;
-: 792:// We shouldn't ever hit this; Mapgen_pool handles above-ground. But safety!
2025: 793: if (posz > 0) {
#####: 794: generate_open();
2025: 795: } else if (terrain[0]->has_flag(WTF_RELATIONAL)) {
98: 796: neighbor.push_back(false);
490: 797: for (int i = 1; i < 5; i++) {
392: 798: bool nb = (terrain[i] == terrain[0]);
587: 799: for (int n = 0; !nb && n < terrain[0]->connectors.size(); n++) {
195: 800: std::string conn = no_caps( terrain[0]->connectors[n] );
195: 801: if ( no_caps( terrain[i]->get_data_name() ) == conn ) {
#####: 802: nb = true;
-: 803: }
195: 804: }
392: 805: neighbor.push_back(nb);
-: 806: }
98: 807: spec = MAPGEN_SPECS.random_for_terrain(terrain[0], neighbor);
-: 808: } else {
1927: 809: spec = MAPGEN_SPECS.random_for_terrain(terrain[0], "", 0);
-: 810: }
2025: 811: if (!spec) {
#####: 812: int num_conn = 0;
#####: 813: for (int i = 0; i < neighbor.size(); i++) {
#####: 814: if (neighbor[i]) {
#####: 815: num_conn++;
-: 816: }
-: 817: }
-: 818: debugmsg("Mapgen::generate() failed to find spec for %s [conn=%d, z=%d]",
#####: 819: terrain[0]->get_data_name().c_str(), num_conn, posz);
#####: 820: generate_empty();
-: 821: return;
-: 822: }
2025: 823: spec->prepare(terrain);
2025: 824: generate( spec );
-: 825: }
-: 826:
-: 827:// If we're above ground, DON'T do adjacency maps!
2025: 828: if (posz > 0) {
#####: 829: return;
-: 830: }
-: 831:
-: 832:// Now do adjacency maps
10125: 833: for (int i = 1; i < 5; i++) {
8100: 834: if (terrain[i] && terrain[i] != terrain[0]) {
1089: 835: Mapgen_spec* adj = MAPGEN_SPECS.random_adjacent_to(terrain[i],terrain[0]);
1089: 836: if (adj) {
721: 837: adj->prepare(terrain);
721: 838: adj->rotate( Direction(i) );
721: 839: generate_adjacent( adj );
-: 840: }
-: 841: }
-: 842: }
-: 843:}
-: 844:
2025: 845:void Submap::generate(Mapgen_spec* spec)
-: 846:{
2025: 847: if (!spec) {
#####: 848: debugmsg("Null spec in Submap::generate()!");
#####: 849: generate_empty();
2025: 850: return;
-: 851: }
-: 852:// Set our subname to the spec's subname (defaults to empty, only matters for
-: 853:// multi-story buildings
-: 854:// Ditto rotation.
2025: 855: spec_used = spec;
2025: 856: subname = spec->subname;
-: 857:// Rotation gets set in Mapgen_spec::prepare(), so it should still be valid here
2025: 858: rotation = spec->rotation;
-: 859:// First, set the terrain.
52650: 860: for (int x = 0; x < SUBMAP_SIZE; x++) {
1316250: 861: for (int y = 0; y < SUBMAP_SIZE; y++) {
1265625: 862: Terrain* ter = spec->pick_terrain(x, y);
1265625: 863: if (!ter) {
-: 864: debugmsg("Generating null terrain at [%d:%d] (%s)", x, y,
#####: 865: spec->get_name().c_str());
#####: 866: spec->debug_output();
-: 867: }
1265625: 868: tiles[x][y].set_terrain(ter);
-: 869: }
-: 870: }
-: 871:
-: 872:// Next, add any furniture that needs adding.
-: 873:// The Game keeps track of furniture UIDs, but so do Mapgen_specs.
-: 874:// So store a std::map of what each Mapgen UID should be translated to.
2025: 875: std::map<int,int> map_uid_to_game_uid;
52650: 876: for (int x = 0; x < SUBMAP_SIZE; x++) {
1316250: 877: for (int y = 0; y < SUBMAP_SIZE; y++) {
1265625: 878: Furniture_type* furniture = spec->pick_furniture(x, y);
1265625: 879: if (furniture) {
306: 880: int map_uid = spec->pick_furniture_uid(x, y);
306: 881: if (map_uid_to_game_uid.count(map_uid) == 0) {
234: 882: map_uid_to_game_uid[map_uid] = GAME.get_furniture_uid();
-: 883: }
306: 884: tiles[x][y].add_furniture(furniture, map_uid_to_game_uid[map_uid]);
-: 885: }
-: 886: }
-: 887: }
-: 888:
-: 889:// Next, add items.
5776: 890: for (std::map<char,Item_area>::iterator it = spec->item_defs.begin();
2888: 891: it != spec->item_defs.end();
-: 892: it++) {
863: 893: Item_area* area = &(it->second);
863: 894: area->reset();
2913: 895: while (area && area->place_item()) {
1187: 896: Point p = area->pick_location();
1187: 897: Item item( area->pick_type(spec->get_name()) );
1187: 898: if (item.type) {
1187: 899: item.prep_for_generation();
1187: 900: add_item(item, p.x, p.y);
-: 901: }
1187: 902: }
-: 903: }
-: 904:
-: 905:// Item_group_amount_areas work similarly!
4056: 906: for (std::map<char,Item_group_amount_area>::iterator
2025: 907: it = spec->item_group_defs.begin();
2028: 908: it != spec->item_group_defs.end();
-: 909: it++) {
3: 910: Item_group_amount_area* area = &(it->second);
3: 911: Item_group_amount group = area->pick_group();
3: 912: int amount = group.amount.roll();
8: 913: for (int i = 0; i < amount; i++) {
5: 914: Point p = area->pick_location();
5: 915: Item item( group.group->pick_type() );
5: 916: item.prep_for_generation();
5: 917: add_item(item, p.x, p.y);
5: 918: }
3: 919: }
-: 920:
-: 921:// Item_amount_areas work the same as Item_group_amount_areas, more or less
4054: 922: for (std::map<char,Item_amount_area>::iterator
2025: 923: it = spec->item_amount_defs.begin();
2027: 924: it != spec->item_amount_defs.end();
-: 925: it++) {
2: 926: Item_amount_area* area = &(it->second);
2: 927: Item_amount item_amt = area->pick_item();
2: 928: int amount = item_amt.amount.roll();
5: 929: for (int i = 0; i < amount; i++) {
3: 930: Point p = area->pick_location();
3: 931: Item item( item_amt.item );
3: 932: item.prep_for_generation();
3: 933: add_item(item, p.x, p.y);
3: 934: }
2027: 935: }
-: 936:}
-: 937:
721: 938:void Submap::generate_adjacent(Mapgen_spec* spec)
-: 939:{
721: 940: if (spec == NULL) {
721: 941: return;
-: 942: }
-: 943:// First, set the terrain.
18746: 944: for (int x = 0; x < SUBMAP_SIZE; x++) {
468650: 945: for (int y = 0; y < SUBMAP_SIZE; y++) {
450625: 946: Terrain* tmpter = spec->pick_terrain(x, y);
-: 947:// TODO: Only overwrite terrain with the "ground" tag
546475: 948: if (tmpter &&
95850: 949: (!tiles[x][y].terrain || tiles[x][y].terrain->has_flag(TF_MUTABLE))) {
28992: 950: tiles[x][y].set_terrain(tmpter);
-: 951: }
-: 952: }
-: 953: }
-: 954:// Next, add items.
1442: 955: for (std::map<char,Item_area>::iterator it = spec->item_defs.begin();
721: 956: it != spec->item_defs.end();
-: 957: it++) {
#####: 958: Item_area* area = &(it->second);
#####: 959: while (area && area->place_item()) {
#####: 960: Point p = area->pick_location();
#####: 961: Item item( area->pick_type() );
#####: 962: tiles[p.x][p.y].items.push_back(item);
#####: 963: }
-: 964: }
-: 965:}
-: 966:
302: 967:void Submap::generate_above(World_terrain* type, Submap* below)
-: 968:{
302: 969: if (!type) {
#####: 970: debugmsg("Submap::generate_above(NULL, ?) called!");
#####: 971: generate_empty();
#####: 972: return;
-: 973: }
302: 974: if (!below) {
#####: 975: debugmsg("Submap::generate_above(?, NULL) called!");
#####: 976: generate_empty();
#####: 977: return;
-: 978: }
-: 979:
302: 980: level = below->level + 1;
302: 981: subname = below->subname;
302: 982: rotation = below->rotation;
-: 983:
302: 984: Mapgen_spec* spec = MAPGEN_SPECS.random_with_subname(subname, level);
302: 985: if (!spec) {
302: 986: generate_open();
302: 987: return;
-: 988: }
-: 989: World_terrain* ter[5];
#####: 990: ter[0] = type;
#####: 991: for (int i = 0; i < 5; i++) {
#####: 992: ter[i] = NULL;
-: 993: }
#####: 994: spec->rotate(rotation);
#####: 995: spec->prepare(ter, false); // false means no rotation happens here.
#####: 996: generate(spec);
-: 997:// We might need to add stairs to match what's below.
#####: 998: if (spec->has_flag(MAPFLAG_AUTOSTAIRS)) {
#####: 999: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1000: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1001: Tile* t = &(below->tiles[x][y]);
#####: 1002: if (t->terrain && t->terrain->has_flag(TF_STAIRS_UP)) {
#####: 1003: std::string stair_name = t->terrain->inverse;
#####: 1004: Terrain* stair = TERRAIN.lookup_name(stair_name);
#####: 1005: if (stair) {
#####: 1006: tiles[x][y].set_terrain(stair);
#####: 1007: }
-: 1008: }
-: 1009: }
-: 1010: }
-: 1011: }
-: 1012:}
-: 1013:
#####: 1014:void Submap::clear_items()
-: 1015:{
#####: 1016: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1017: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1018: tiles[x][y].items.clear();
-: 1019: }
-: 1020: }
#####: 1021:}
-: 1022:
1195: 1023:bool Submap::add_item(Item item, int x, int y)
-: 1024:{
1195: 1025: if (x < 0 || y < 0 || x >= SUBMAP_SIZE || y >= SUBMAP_SIZE) {
29: 1026: return false;
-: 1027: }
1166: 1028: if (item.count > 1) {
#####: 1029: int count = item.count;
#####: 1030: item.count = 1;
#####: 1031: for (int i = 0; i < count; i++) {
#####: 1032: if (!add_item(item, x, y)) {
#####: 1033: return false;
-: 1034: }
-: 1035: }
#####: 1036: return true;
-: 1037: }
2234: 1038: if ((tiles[x][y].move_cost() > 0 || tiles[x][y].has_flag(TF_CONTAINER)) &&
1068: 1039: !tiles[x][y].has_flag(TF_NO_ITEMS)) {
1068: 1040: tiles[x][y].items.push_back(item);
-: 1041: } else {
-: 1042:// Pick a random adjacent space with move_cost != 0
98: 1043: std::vector<Point> valid_points;
392: 1044: for (int px = x - 1; px <= x + 1; px++) {
1176: 1045: for (int py = y - 1; py <= y + 1; py++) {
1752: 1046: if (px >= 0 && py >= 0 && px < SUBMAP_SIZE && py < SUBMAP_SIZE &&
870: 1047: tiles[px][py].move_cost() > 0) {
471: 1048: valid_points.push_back( Point(px, py) );
-: 1049: }
-: 1050: }
-: 1051: }
98: 1052: if (valid_points.empty()) {
#####: 1053: return false; // No valid points! Oh well. ITEM OBLITERATED
-: 1054:// TODO: Don't obliterate items.
-: 1055: }
98: 1056: int index = rng(0, valid_points.size() - 1);
98: 1057: Point p = valid_points[index];
98: 1058: tiles[p.x][p.y].items.push_back(item);
-: 1059: }
1166: 1060: return true;
-: 1061:}
-: 1062:
#####: 1063:int Submap::item_count(int x, int y)
-: 1064:{
#####: 1065: if (x < 0 || x >= SUBMAP_SIZE || x < 0 || y >= SUBMAP_SIZE) {
#####: 1066: return 0;
-: 1067: }
#####: 1068: return tiles[x][y].items.size();
-: 1069:}
-: 1070:
20: 1071:std::vector<Item>* Submap::items_at(int x, int y)
-: 1072:{
20: 1073: if (x < 0 || x >= SUBMAP_SIZE || x < 0 || y >= SUBMAP_SIZE) {
#####: 1074: return NULL;
-: 1075: }
20: 1076: return &(tiles[x][y].items);
-: 1077:}
-: 1078:
#####: 1079:Point Submap::random_empty_tile()
-: 1080:{
#####: 1081: std::vector<Point> options;
#####: 1082: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1083: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1084: if (tiles[x][y].move_cost() > 0) {
#####: 1085: options.push_back( Point(x, y) );
-: 1086: }
-: 1087: }
-: 1088: }
-: 1089:
#####: 1090: if (options.empty()) {
#####: 1091: return Point(-1, -1);
-: 1092: }
#####: 1093: return options[ rng(0, options.size() - 1) ];
-: 1094:}
-: 1095:
#####: 1096:std::string Submap::get_spec_name()
-: 1097:{
#####: 1098: if (!spec_used) {
#####: 1099: return "Unknown";
-: 1100: }
#####: 1101: return spec_used->get_name();
-: 1102:}
-: 1103:
21: 1104:std::string Submap::get_world_ter_name()
-: 1105:{
21: 1106: if (!spec_used) {
#####: 1107: return "";
-: 1108: }
21: 1109: return spec_used->terrain_name;
-: 1110:}
-: 1111:
#####: 1112:std::string Submap::save_data()
-: 1113:{
#####: 1114: std::stringstream ret;
-: 1115:
#####: 1116: if (spec_used) {
#####: 1117: ret << "Spec: " << spec_used->get_short_name() << std::endl;
-: 1118: }
-: 1119:
#####: 1120: if (!subname.empty()) {
#####: 1121: ret << "Subname: " << subname << std::endl;
-: 1122: }
#####: 1123: ret << "Rotation: " << int(rotation) << std::endl;
#####: 1124: ret << "Level: " << level << std::endl;
#####: 1125: ret << "Tiles: " << std::endl;
#####: 1126: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1127: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1128: ret << tiles[x][y].save_data() << std::endl;
-: 1129: }
-: 1130: }
-: 1131:
#####: 1132: ret << "Done";
-: 1133:
#####: 1134: return ret.str();
-: 1135:}
-: 1136:
#####: 1137:bool Submap::load_data(std::istream& data)
-: 1138:{
#####: 1139: std::string ident, junk;
#####: 1140: while (ident != "done" && !data.eof()) {
#####: 1141: if ( ! (data >> ident) ) {
#####: 1142: debugmsg("Couldn't read Submap data.");
#####: 1143: return false;
-: 1144: }
#####: 1145: ident = no_caps(ident);
-: 1146:
#####: 1147: if (ident == "tiles:") {
#####: 1148: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1149: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1150: if (!tiles[x][y].load_data(data)) {
#####: 1151: debugmsg("Failed to read Submap Tile [%d:%d]", x, y);
#####: 1152: return false;
-: 1153: }
-: 1154: }
-: 1155: }
-: 1156:
#####: 1157: } else if (ident == "spec:") {
#####: 1158: std::string specname;
#####: 1159: std::getline(data, specname);
#####: 1160: specname = trim(specname);
#####: 1161: spec_used = MAPGEN_SPECS.lookup_name(specname);
#####: 1162: if (!spec_used) {
#####: 1163: debugmsg("Unknown Mapgen_spec %s.", specname.c_str());
#####: 1164: return false;
#####: 1165: }
-: 1166:
#####: 1167: } else if (ident == "subname:") {
#####: 1168: std::string tmpname;
#####: 1169: std::getline(data, tmpname);
#####: 1170: subname = trim(tmpname);
-: 1171:
#####: 1172: } else if (ident == "rotation:") {
-: 1173: int tmprot;
#####: 1174: data >> tmprot;
#####: 1175: if (tmprot < 0 || tmprot > DIR_WEST) {
#####: 1176: debugmsg("Invalid rotation %d (range is 0 - 5).", tmprot);
#####: 1177: return false;
-: 1178: }
#####: 1179: rotation = Direction(tmprot);
#####: 1180: std::getline(data, junk);
-: 1181:
#####: 1182: } else if (ident == "level:") {
#####: 1183: data >> level;
#####: 1184: std::getline(data, junk);
-: 1185:
#####: 1186: } else if (ident != "done") {
#####: 1187: debugmsg("Unknown Submap property '%s'", ident.c_str());
-: 1188: }
-: 1189: }
#####: 1190: if (ident != "done") {
#####: 1191: debugmsg("Submap save data was incomplete.");
#####: 1192: return false;
-: 1193: }
#####: 1194: return true;
-: 1195:}
-: 1196:
1: 1197:Submap_pool::Submap_pool()
-: 1198:{
1: 1199: sector = Point(-1, -1);
1: 1200:}
-: 1201:
2: 1202:Submap_pool::~Submap_pool()
-: 1203:{
4656: 1204: for (std::list<Submap*>::iterator it = instances.begin();
2328: 1205: it != instances.end();
-: 1206: it++) {
2327: 1207: delete (*it);
-: 1208: }
1: 1209:}
-: 1210:
1316: 1211:Submap* Submap_pool::at_location(int x, int y, int z)
-: 1212:{
1316: 1213: return at_location( Tripoint(x, y, z) );
-: 1214:}
-: 1215:
#####: 1216:Submap* Submap_pool::at_location(Point p)
-: 1217:{
#####: 1218: Tripoint trip(p.x, p.y, 0);
#####: 1219: return at_location(trip);
-: 1220:}
-: 1221:
1316: 1222:Submap* Submap_pool::at_location(Tripoint p)
-: 1223:{
1316: 1224: if (point_map.count(p) > 0) {
1014: 1225: return point_map[p];
-: 1226: }
-: 1227:/*
-: 1228: if (TESTING_MODE) {
-: 1229: debugmsg("WARNING: Generating rogue submap %s! We have %s.",
-: 1230: p.str().c_str(), get_range_text().c_str());
-: 1231: }
-: 1232:*/
302: 1233: return generate_submap(p);
-: 1234:}
-: 1235:
42: 1236:void Submap_pool::load_area(int sector_x, int sector_y)
-: 1237:{
42: 1238: int max_sector = WORLDMAP_SIZE / SECTOR_SIZE;
42: 1239: if (sector_x < 0 || sector_x > max_sector ||
-: 1240: sector_y < 0 || sector_y > max_sector ) {
-: 1241: debugmsg("Submap_pool::load_area(%d, %d) - limit (%d, %d)",
#####: 1242: sector_x, sector_y, max_sector, max_sector);
#####: 1243: return;
-: 1244: }
-: 1245:
-: 1246:// Check if we're loading what we already have - if so, skip all this work
42: 1247: if (sector_x == sector.x && sector_y == sector.y) {
41: 1248: return;
-: 1249: }
-: 1250:
-: 1251:// Start by clearing out existing submaps which we don't need...
-: 1252:// (unless we're brand-new)
1: 1253: if (sector.x != -1 && sector.y != -1) {
#####: 1254: clear_submaps(sector_x, sector_y);
-: 1255: }
-: 1256:
-: 1257:/* At this point, we've saved and deleted all submaps which won't be in the
-: 1258: * updated pool. The next step is to load (or generate if need be) all the
-: 1259: * submaps which WILL be in the updated pool.
-: 1260: */
1: 1261: init_submaps(sector_x, sector_y);
-: 1262:
-: 1263:// Finally, set sector.
1: 1264: sector = Point(sector_x, sector_y);
-: 1265:
-: 1266:}
-: 1267:
42: 1268:void Submap_pool::load_area_centered_on(int center_x, int center_y)
-: 1269:{
42: 1270: if (center_x < 0 || center_x >= WORLDMAP_SIZE ||
-: 1271: center_y < 0 || center_y >= WORLDMAP_SIZE ) {
-: 1272: debugmsg("Submap_pool::load_area_centered_on(%d, %d) - limit (%d, %d)",
#####: 1273: center_x, center_y, WORLDMAP_SIZE, WORLDMAP_SIZE);
42: 1274: return;
-: 1275: }
-: 1276:// e.g. SECTOR_SIZE = 10; 47 => 40
42: 1277: int sector_x = center_x - (center_x % SECTOR_SIZE);
42: 1278: int sector_y = center_y - (center_y % SECTOR_SIZE);
-: 1279:
-: 1280:// 40 => 4
42: 1281: sector_x /= SECTOR_SIZE;
42: 1282: sector_y /= SECTOR_SIZE;
-: 1283:
-: 1284:// But these numbers are for the CENTER sector! So subtract one.
42: 1285: if (sector_x > 0) {
42: 1286: sector_x--;
-: 1287: }
42: 1288: if (sector_y > 0) {
42: 1289: sector_y--;
-: 1290: }
-: 1291:
42: 1292: load_area(sector_x, sector_y);
-: 1293:}
-: 1294:
#####: 1295:int Submap_pool::size()
-: 1296:{
#####: 1297: return instances.size();
-: 1298:}
-: 1299:
#####: 1300:std::string Submap_pool::all_size()
-: 1301:{
#####: 1302: std::stringstream ret;
#####: 1303: ret << "instances: " << instances.size() << " point_map: " <<
#####: 1304: point_map.size();
#####: 1305: return ret.str();
-: 1306:}
-: 1307:
#####: 1308:std::string Submap_pool::get_range_text()
-: 1309:{
#####: 1310: std::stringstream ret;
#####: 1311: Point lower = sector;
#####: 1312: Point upper = lower;
#####: 1313: lower.x *= SECTOR_SIZE;
#####: 1314: lower.y *= SECTOR_SIZE;
#####: 1315: upper.x += 3;
#####: 1316: upper.y += 3;
#####: 1317: upper.x *= SECTOR_SIZE;
#####: 1318: upper.y *= SECTOR_SIZE;
#####: 1319: upper.x += SECTOR_SIZE - 1;
#####: 1320: upper.y += SECTOR_SIZE - 1;
#####: 1321: ret << lower.str() << " to " << upper.str() << " (center ";
#####: 1322: lower.x += SECTOR_SIZE;
#####: 1323: lower.y += SECTOR_SIZE;
#####: 1324: upper.x -= SECTOR_SIZE;
#####: 1325: upper.y -= SECTOR_SIZE;
#####: 1326: ret << lower.str() << " to " << upper.str() << ")";
#####: 1327: return ret.str();
-: 1328:}
-: 1329:
-: 1330:
#####: 1331:void Submap_pool::remove_point(Tripoint p)
-: 1332:{
#####: 1333: if (point_map.count(p) == 0) {
#####: 1334: if (TESTING_MODE) {
#####: 1335: debugmsg("Submap_pool couldn't remove point %s.", p.str().c_str());
-: 1336: }
#####: 1337: return;
-: 1338: }
#####: 1339: point_map.erase(p);
-: 1340:}
-: 1341:
#####: 1342:void Submap_pool::remove_submap(Submap* sm)
-: 1343:{
#####: 1344: if (!sm) {
#####: 1345: if (TESTING_MODE) {
#####: 1346: debugmsg("Submap_pool couldn't remove submap %d.", sm);
-: 1347: }
#####: 1348: return;
-: 1349: }
#####: 1350: delete sm;
#####: 1351: instances.remove(sm);
-: 1352:}
-: 1353:
#####: 1354:void Submap_pool::clear_submaps(int sector_x, int sector_y)
-: 1355:{
#####: 1356: std::string map_dir = SAVE_DIR + "/" + GAME.worldmap->get_name();
#####: 1357: if (!directory_exists(map_dir)) {
#####: 1358: if (!create_directory(map_dir)) {
#####: 1359: debugmsg("Couldn't create directory '%s'.", map_dir.c_str());
-: 1360: return;
-: 1361: }
-: 1362: }
-: 1363:
-: 1364:/*
-: 1365: if (TESTING_MODE) {
-: 1366: debugmsg("Submap_pool::clear_submaps(%d, %d) (sector = %s)",
-: 1367: sector_x, sector_y, sector.str().c_str());
-: 1368: }
-: 1369:*/
#####: 1370: int num_removed = 0;
#####: 1371: for (int sx = sector.x; sx < sector.x + 3; sx++) {
#####: 1372: for (int sy = sector.y; sy < sector.y + 3; sy++) {
-: 1373:// Only save sectors that won't exist in the new Submap_pool.
#####: 1374: if (sx < sector_x || sx >= sector_x + 3 ||
-: 1375: sy < sector_y || sy >= sector_y + 3 ) {
#####: 1376: std::stringstream filename;
#####: 1377: filename << map_dir << "/map." << sx << "." << sy;
#####: 1378: std::ofstream fout;
#####: 1379: fout.open( filename.str().c_str() );
#####: 1380: if (!fout.is_open()) {
#####: 1381: debugmsg("Couldn't open '%s' for writing.", filename.str().c_str());
-: 1382: return;
-: 1383: }
-: 1384:
#####: 1385: int start_x = sx * SECTOR_SIZE, start_y = sy * SECTOR_SIZE;
-: 1386:/*
-: 1387: if (TESTING_MODE) {
-: 1388: debugmsg("Clearing from %d:%d to %d:%d", start_x, start_y,
-: 1389: start_x + SECTOR_SIZE - 1, start_y + SECTOR_SIZE - 1);
-: 1390: }
-: 1391:*/
#####: 1392: for (int mx = start_x; mx < start_x + SECTOR_SIZE; mx++) {
#####: 1393: for (int my = start_y; my < start_y + SECTOR_SIZE; my++) {
#####: 1394: Tripoint curpos = Tripoint(mx, my, 0);
-: 1395:// while loop moves upwards until we stop having maps
#####: 1396: while (point_map.count(curpos) > 0) {
#####: 1397: Submap* curmap = point_map[curpos];
#####: 1398: fout << curpos.x << " " << curpos.y << " " << curpos.z <<
#####: 1399: std::endl << curmap->save_data() << std::endl;
#####: 1400: remove_point(curpos);
#####: 1401: remove_submap(curmap);
#####: 1402: num_removed++;
#####: 1403: curpos.z++;
-: 1404: }
#####: 1405: } // for (start_y <= mx < start_x + SECTOR_SIZE
#####: 1406: } // for (start_x <= mx < start_x + SECTOR_SIZE
-: 1407: } // If <sector is moving out of bounds>
-: 1408: } // for (int sy = sector.y; sy < sector.y + 3; sy++)
#####: 1409: } // for (int sx = sector.x; sx < sector.x + 3; sx++)
-: 1410:
-: 1411:/*
-: 1412: if (TESTING_MODE) {
-: 1413: debugmsg("%d submaps erased; %d left (point_map %d, instances %d).",
-: 1414: num_removed, size(), point_map.size(), instances.size());
-: 1415: }
-: 1416:*/
-: 1417:
-: 1418:}
-: 1419:
1: 1420:void Submap_pool::init_submaps(int sector_x, int sector_y)
-: 1421:{
1: 1422: std::string map_dir = SAVE_DIR + "/" + GAME.worldmap->get_name();
-: 1423:/* The first time we use a new world, the directory won't even exist! This will
-: 1424: * be remedied the first time we have to SAVE Submaps, but for now, we'll take
-: 1425: * it as a sign that we need to generate ALL of them.
-: 1426: */
1: 1427: bool gen_all = false;
1: 1428: if (!directory_exists(map_dir)) {
#####: 1429: gen_all = true;
-: 1430: }
4: 1431: for (int sx = sector_x; sx < sector_x + 3; sx++) {
12: 1432: for (int sy = sector_y; sy < sector_y + 3; sy++) {
-: 1433:/* Again, we check for overlap with the *old* position - no need to re-load
-: 1434: * or re-generate those submaps.
-: 1435: */
9: 1436: if (sx < sector.x || sx >= sector.x + 3 ||
-: 1437: sy < sector.y || sy >= sector.y + 3 ) {
-: 1438:// Attempt to load from file
9: 1439: std::stringstream filename;
9: 1440: if (!gen_all) {
18: 1441: filename << SAVE_DIR << "/" << GAME.worldmap->get_name() << "/map." <<
9: 1442: sx << "." << sy;
-: 1443: }
9: 1444: if (gen_all || !load_submaps( filename.str() )) {
-: 1445:// No file! Generate the submaps.
9: 1446: int startx = sx * SECTOR_SIZE, starty = sy * SECTOR_SIZE;
144: 1447: for (int mx = startx; mx < startx + SECTOR_SIZE; mx++) {
2160: 1448: for (int my = starty; my < starty + SECTOR_SIZE; my++) {
2025: 1449: generate_submap(mx, my);
-: 1450: }
-: 1451: }
9: 1452: }
-: 1453: }
-: 1454: }
1: 1455: }
1: 1456:}
-: 1457:
9: 1458:bool Submap_pool::load_submaps(std::string filename)
-: 1459:{
9: 1460: std::ifstream fin;
9: 1461: fin.open( filename.c_str() );
9: 1462: if (!fin.is_open()) {
9: 1463: return false;
-: 1464: }
#####: 1465: while (!fin.eof()) {
#####: 1466: Tripoint smpos;
#####: 1467: fin >> smpos.x >> smpos.y >> smpos.z;
#####: 1468: if (!fin.eof()) {
-: 1469:/* Too spammy. Uncomment if really needed...
-: 1470: if (TESTING_MODE) {
-: 1471: debugmsg("Loading %s...", smpos.str().c_str());
-: 1472: }
-: 1473: */
#####: 1474: bool use_sm = true;
#####: 1475: if (point_map.count(smpos) > 0) {
#####: 1476: use_sm = false;
-: 1477:/* I commented this out because sometimes, there's supposed to be a submap
-: 1478: * collision - an example is when using Test mode to teleport to a very-close-by
-: 1479: * location. I don't think that a submap collision will ever happen
-: 1480: * unintentionally, and if it does, it doesn't need to be fatal.
-: 1481:
-: 1482: debugmsg("Submap_pool collision at %s!", smpos.str().c_str());
-: 1483: return false;
-: 1484:*/
-: 1485: }
#####: 1486: Submap* sm = new Submap;
#####: 1487: if (sm->load_data(fin)) {
-: 1488:/*
-: 1489: bool shipwreck = TESTING_MODE && sm->spec_used &&
-: 1490: sm->spec_used->get_short_name() ==
-: 1491: "shipwreck_beach_whales";
-: 1492: if (shipwreck) {
-: 1493: debugmsg("Loaded shipwreck");
-: 1494: }
-: 1495:*/
#####: 1496: if (use_sm) {
-: 1497:/*
-: 1498: if (shipwreck) {
-: 1499: debugmsg("Using it!");
-: 1500: }
-: 1501:*/
#####: 1502: instances.push_back(sm);
#####: 1503: point_map[smpos] = sm;
-: 1504: } else {
-: 1505:/*
-: 1506: if (shipwreck) {
-: 1507: debugmsg("Tossing it!");
-: 1508: }
-: 1509:*/
#####: 1510: delete sm;
-: 1511: }
-: 1512: } else {
#####: 1513: delete sm;
#####: 1514: debugmsg("Failed to load submap at %s.", smpos.str().c_str());
#####: 1515: return false;
-: 1516: }
-: 1517: }
#####: 1518: }
#####: 1519: return true;
-: 1520:}
-: 1521:
2025: 1522:Submap* Submap_pool::generate_submap(int x, int y, int z)
-: 1523:{
2025: 1524: return generate_submap( Tripoint(x, y, z) );
-: 1525:}
-: 1526:
2327: 1527:Submap* Submap_pool::generate_submap(Tripoint p)
-: 1528:{
2327: 1529: Submap* sub = new Submap;
2327: 1530: if (p.z > 0) {
302: 1531: Submap* below = at_location(p.x, p.y, p.z - 1);
302: 1532: Worldmap_tile *tile = GAME.worldmap->get_tile(p.x, p.y);
302: 1533: if (!tile) {
#####: 1534: sub->generate_empty();
-: 1535: } else {
302: 1536: sub->generate_above(tile->terrain, below);
-: 1537: }
302: 1538: point_map[p] = sub;
302: 1539: instances.push_back(sub);
302: 1540: return sub;
-: 1541: }
2025: 1542: sub->generate(GAME.worldmap, p.x, p.y, p.z);
2025: 1543: point_map[p] = sub;
2025: 1544: instances.push_back(sub);
2025: 1545: return sub;
-: 1546:}
-: 1547:
1: 1548:Map::Map()
-: 1549:{
1: 1550: posx = 0;
1: 1551: posy = 0;
1: 1552: posz = 0;
-: 1553:
14: 1554: for (int x = 0; x < MAP_SIZE; x++) {
182: 1555: for (int y = 0; y < MAP_SIZE; y++) {
1352: 1556: for (int z = 0; z < VERTICAL_MAP_SIZE * 2 + 1; z++) {
1183: 1557: submaps[x][y][z] = NULL;
-: 1558: }
-: 1559: }
-: 1560: }
1: 1561:}
-: 1562:
1: 1563:Map::~Map()
-: 1564:{
1: 1565:}
-: 1566:
#####: 1567:void Map::generate_empty()
-: 1568:{
#####: 1569: for (int x = 0; x < MAP_SIZE; x++) {
#####: 1570: for (int y = 0; y < MAP_SIZE; y++) {
#####: 1571: submaps[x][y][posz]->generate_empty();
-: 1572: }
-: 1573: }
#####: 1574:}
-: 1575:
-: 1576:/*
-: 1577:void Map::test_generate(std::string terrain_name)
-: 1578:{
-: 1579: for (int x = 0; x < MAP_SIZE; x++) {
-: 1580: for (int y = 0; y < MAP_SIZE; y++) {
-: 1581: submaps[x][y][posz]->generate(terrain_name);
-: 1582: }
-: 1583: }
-: 1584:}
-: 1585:*/
-: 1586:
3: 1587:void Map::generate(Worldmap *world, int wposx, int wposy, int wposz)
-: 1588:{
-: 1589:// All int arguments default to -999
3: 1590: if (wposx != -999) {
1: 1591: posx = wposx;
-: 1592: }
3: 1593: if (wposy != -999) {
1: 1594: posy = wposy;
-: 1595: }
3: 1596: if (wposz != -999) {
1: 1597: posz = wposz;
-: 1598: }
-: 1599:// TODO: Support posz < 0
9: 1600: for (int z = 0; z <= posz + 1; z++) {
6: 1601: int z_index = z + VERTICAL_MAP_SIZE - posz;
84: 1602: for (int x = 0; x < MAP_SIZE; x++) {
1092: 1603: for (int y = 0; y < MAP_SIZE; y++) {
-: 1604:/* at_location either returns the existing submap with that location keyed in,
-: 1605: * or creates a new submap, generates it with the world information at that
-: 1606: * location, and returns it.
-: 1607: */
1014: 1608: submaps[x][y][z_index] = SUBMAP_POOL.at_location(posx + x, posy + y, z);
1014: 1609: if (z == 0) {
507: 1610: spawn_monsters(world, posx + x, posy + y, x, y, z);
-: 1611: }
-: 1612: }
-: 1613: }
-: 1614: }
3: 1615:}
-: 1616:
41: 1617:void Map::shift(Worldmap *world, int shiftx, int shifty, int shiftz)
-: 1618:{
41: 1619: if (shiftx == 0 && shifty == 0 && shiftz == 0) {
80: 1620: return;
-: 1621: }
2: 1622: posx += shiftx;
2: 1623: posy += shifty;
2: 1624: posz += shiftz;
2: 1625: generate(world);
-: 1626:}
-: 1627:
507: 1628:void Map::spawn_monsters(Worldmap *world, int worldx, int worldy,
-: 1629: int subx, int suby, int zlevel)
-: 1630:{
-: 1631:// If we have bad inputs, return with an error message
507: 1632: if (!world) {
#####: 1633: debugmsg("Map::spawn_monsters() called with NULL world");
#####: 1634: return;
-: 1635: }
507: 1636: if (subx < 0 || suby < 0 || subx >= MAP_SIZE || suby >= MAP_SIZE) {
#####: 1637: debugmsg("Map::spawn_monsters() called on submap [%d:%d]", subx, suby);
#####: 1638: return;
-: 1639: }
-: 1640:// Fetch the monsters from the world
507: 1641: std::vector<Monster_spawn>* monsters = world->get_spawns(worldx, worldy);
-: 1642:
507: 1643: if (monsters->empty()) {
503: 1644: return; // No monsters here, skip the rest!
-: 1645: }
-: 1646:
-: 1647:/*
-: 1648: int zdex = zlevel + VERTICAL_MAP_SIZE - posz;
-: 1649:debugmsg("Spawning monsters at World[%d:%d](%s), Submap[%d:%d:%d](%s)",
-: 1650: worldx, worldy, world->get_name(worldx, worldy).c_str(),
-: 1651: subx, suby, posz, submaps[subx][suby][zdex]->get_spec_name().c_str());
-: 1652:*/
-: 1653:
-: 1654:// Pick some empty tiles
-: 1655:/* TODO: Support placing aquatic monsters in water tiles, etc.
-: 1656: * Perhaps by replacing random_empty_tile() with tile_for(Monster_type*)?
-: 1657: */
4: 1658: int minx = subx * SUBMAP_SIZE, miny = suby * SUBMAP_SIZE;
4: 1659: int maxx = minx + SUBMAP_SIZE - 1, maxy = miny + SUBMAP_SIZE - 1;
-: 1660:/*
-: 1661: debugmsg("Submap [%d:%d:%d], tiles [%d:%d] to [%d:%d]",
-: 1662: subx, suby, zlevel, minx, miny, maxx, maxy);
-: 1663:*/
4: 1664: std::vector<Point> available_tiles;
104: 1665: for (int x = minx; x <= maxx; x++) {
2600: 1666: for (int y = miny; y <= maxy; y++) {
2500: 1667: if (move_cost(x, y, zlevel) > 0) {
2395: 1668: available_tiles.push_back( Point(x, y) );
-: 1669: }
-: 1670: }
-: 1671: }
-: 1672:
-: 1673:/*
-: 1674: if (available_tiles.empty()) {
-: 1675: debugmsg("No available tiles!");
-: 1676: return;
-: 1677: }
-: 1678:*/
8: 1679: for (int i = 0; !available_tiles.empty() && i < monsters->size(); i++) {
18: 1680: while (!available_tiles.empty() && (*monsters)[i].population > 0) {
-: 1681:// Pick an available tile and remove it from the list
10: 1682: int index = rng(0, available_tiles.size() - 1);
10: 1683: Point pos = available_tiles[index];
10: 1684: available_tiles.erase( available_tiles.begin() + index );
-: 1685:// Create a monster and place it there
10: 1686: Monster* mon = (*monsters)[i].generate_monster();
-: 1687://debugmsg("Generating '%s'", mon->get_name().c_str());
10: 1688: mon->pos = Tripoint(pos.x, pos.y, zlevel);
-: 1689:/*
-: 1690:debugmsg("Placed at [%d:%d:%d] - '%s'", pos.x, pos.y, posz,
-: 1691: get_name(pos.x, pos.y, posz).c_str());
-: 1692:*/
10: 1693: GAME.entities.add_entity(mon);
10: 1694: (*monsters)[i].population--;
10: 1695: }
4: 1696: }
-: 1697:}
-: 1698:
#####: 1699:Generic_map Map::get_movement_map(Entity_AI AI,
-: 1700: Tripoint origin, Tripoint target)
-: 1701:{
-: 1702:// Set the bounds of the map
#####: 1703: int min_x = (origin.x < target.x ? origin.x : target.x);
#####: 1704: int min_y = (origin.y < target.y ? origin.y : target.y);
#####: 1705: int min_z = (origin.z < target.z ? origin.z : target.z);
#####: 1706: int max_x = (origin.x > target.x ? origin.x : target.x);
#####: 1707: int max_y = (origin.y > target.y ? origin.y : target.y);
#####: 1708: int max_z = (origin.z > target.z ? origin.z : target.z);
-: 1709:
-: 1710:// Expand the bounds of the map by our area awareness bonus.
#####: 1711: min_x -= AI.area_awareness;
#####: 1712: min_y -= AI.area_awareness;
#####: 1713: max_x += AI.area_awareness;
#####: 1714: max_y += AI.area_awareness;
-: 1715:
#####: 1716: int x_size = 1 + max_x - min_x;
#####: 1717: int y_size = 1 + max_y - min_y;
#####: 1718: int z_size = 1 + max_z - min_z;
-: 1719:
#####: 1720: Generic_map ret(x_size, y_size, z_size);
#####: 1721: ret.x_offset = min_x;
#####: 1722: ret.y_offset = min_y;
#####: 1723: ret.z_offset = min_z;
-: 1724:
#####: 1725: for (int x = min_x; x <= max_x; x++) {
#####: 1726: for (int y = min_y; y <= max_y; y++) {
#####: 1727: for (int z = min_z; z <= max_z; z++) {
#####: 1728: int map_x = x - min_x;
#####: 1729: int map_y = y - min_y;
#####: 1730: int map_z = z - min_z;
#####: 1731: int cost = move_cost(x, y, z);
-: 1732:// TODO: If there's a field here, increase cost accordingly
#####: 1733: if (cost == 0 && is_smashable(x, y, z)) {
#####: 1734: cost = 500; // TODO: Estimate costs more intelligently
-: 1735: }
#####: 1736: ret.set_cost(map_x, map_y, map_z, cost);
#####: 1737: if (has_flag(TF_STAIRS_UP, x, y, z)) {
#####: 1738: ret.set_goes_up( Tripoint(map_x, map_y, map_z) );
-: 1739: }
#####: 1740: if (has_flag(TF_STAIRS_DOWN, x, y, z)) {
#####: 1741: ret.set_goes_down( Tripoint(map_x, map_y, map_z) );
-: 1742: }
-: 1743: }
-: 1744: }
-: 1745: }
-: 1746:
#####: 1747: return ret;
-: 1748:}
-: 1749:
#####: 1750:Generic_map Map::get_dijkstra_map(Tripoint target, int weight,
-: 1751: bool include_smashable)
-: 1752:{
#####: 1753: Generic_map ret(SUBMAP_SIZE * MAP_SIZE, SUBMAP_SIZE * MAP_SIZE, posz + 1);
#####: 1754: ret.set_cost(target, weight);
#####: 1755: std::vector<Tripoint> active;
#####: 1756: active.push_back(target);
#####: 1757: while (!active.empty()) {
#####: 1758: Tripoint cur = active[0];
#####: 1759: active.erase(active.begin());
-: 1760:// Check all adjacent terrain
#####: 1761: for (int x = cur.x - 1; x <= cur.x + 1; x++) {
#####: 1762: for (int y = cur.y - 1; y <= cur.y + 1; y++) {
#####: 1763: if (x == cur.x && y == cur.y) { // Skip our own cell
#####: 1764: y++;
-: 1765: }
#####: 1766: if (((include_smashable && is_smashable(x, y, cur.z)) ||
#####: 1767: move_cost(x, y, cur.z) > 0) &&
#####: 1768: ret.get_cost(x, y, cur.z) < ret.get_cost(cur) - 1) {
#####: 1769: ret.set_cost(x, y, cur.z, ret.get_cost(cur) - 1);
#####: 1770: active.push_back( Tripoint(x, y, cur.z) );
-: 1771: }
-: 1772: }
-: 1773: }
#####: 1774: if (has_flag(TF_STAIRS_DOWN, cur)) {
#####: 1775: Tripoint down(cur.x, cur.y, cur.z - 1);
#####: 1776: if (ret.get_cost(down) < ret.get_cost(cur) - 1) {
#####: 1777: ret.set_cost(down, ret.get_cost(cur) - 1);
#####: 1778: active.push_back( down );
#####: 1779: }
-: 1780: }
#####: 1781: if (has_flag(TF_STAIRS_UP, cur)) {
#####: 1782: Tripoint down(cur.x, cur.y, cur.z + 1);
#####: 1783: if (ret.get_cost(down) < ret.get_cost(cur) - 1) {
#####: 1784: ret.set_cost(down, ret.get_cost(cur) - 1);
#####: 1785: active.push_back( down );
#####: 1786: }
-: 1787: }
#####: 1788: } // while (!active.empty())
#####: 1789: return ret;
-: 1790:}
-: 1791:
#####: 1792:int Map::move_cost(Tripoint pos)
-: 1793:{
#####: 1794: return move_cost(pos.x, pos.y, pos.z);
-: 1795:}
-: 1796:
3940: 1797:int Map::move_cost(int x, int y, int z)
-: 1798:{
3940: 1799: Tile *t = get_tile(x, y, z);
3940: 1800: if (!t) {
#####: 1801: return 100;
-: 1802: }
3940: 1803: return t->move_cost();
-: 1804:}
-: 1805:
#####: 1806:int Map::get_height(Tripoint pos)
-: 1807:{
#####: 1808: return get_height(pos.x, pos.y, pos.z);
-: 1809:}
-: 1810:
#####: 1811:int Map::get_height(int x, int y, int z)
-: 1812:{
#####: 1813: Tile *t = get_tile(x, y, z);
#####: 1814: if (!t) {
#####: 1815: return 0;
-: 1816: }
#####: 1817: return t->get_height();
-: 1818:}
-: 1819:
#####: 1820:bool Map::is_smashable(Tripoint pos)
-: 1821:{
#####: 1822: return is_smashable(pos.x, pos.y, pos.z);
-: 1823:}
-: 1824:
#####: 1825:bool Map::is_smashable(int x, int y, int z)
-: 1826:{
#####: 1827: Tile *t = get_tile(x, y, z);
#####: 1828: return (t && t->is_smashable());
-: 1829:}
-: 1830:
20: 1831:bool Map::has_flag(Terrain_flag flag, Tripoint pos)
-: 1832:{
20: 1833: return has_flag(flag, pos.x, pos.y, pos.z);
-: 1834:}
-: 1835:
40: 1836:bool Map::has_flag(Terrain_flag flag, int x, int y, int z)
-: 1837:{
40: 1838: Tile *t = get_tile(x, y, z);
40: 1839: return (t && t->has_flag(flag));
-: 1840:}
-: 1841:
779625: 1842:bool Map::blocks_sense(Sense_type sense, Tripoint pos, int z_value)
-: 1843:{
779625: 1844: Tile *t = get_tile(pos);
779625: 1845: return (t && t->blocks_sense(sense, z_value));
-: 1846:}
-: 1847:
#####: 1848:bool Map::blocks_sense(Sense_type sense, int x, int y, int z)
-: 1849:{
#####: 1850: Tile *t = get_tile(x, y, z);
#####: 1851: return (t && t->blocks_sense(sense));
-: 1852:}
-: 1853:
#####: 1854:bool Map::add_item(Item item, Tripoint pos)
-: 1855:{
#####: 1856: return add_item(item, pos.x, pos.y, pos.z);
-: 1857:}
-: 1858:
#####: 1859:bool Map::add_item(Item item, int x, int y, int z)
-: 1860:{
#####: 1861: if (z == 999) { // z defaults to 999
#####: 1862: z = posz;
-: 1863: }
#####: 1864: z = z - posz + VERTICAL_MAP_SIZE;
#####: 1865: if (x < 0 || x >= SUBMAP_SIZE * MAP_SIZE ||
-: 1866: y < 0 || y >= SUBMAP_SIZE * MAP_SIZE ||
-: 1867: z < 0 || z >= VERTICAL_MAP_SIZE * 2 + 1) {
#####: 1868: return false;
-: 1869: }
#####: 1870: int sx = x / SUBMAP_SIZE, sy = y / SUBMAP_SIZE;
#####: 1871: x %= SUBMAP_SIZE;
#####: 1872: y %= SUBMAP_SIZE;
#####: 1873: return submaps[sx][sy][z]->add_item(item, x, y);
-: 1874:}
-: 1875:
#####: 1876:void Map::clear_items()
-: 1877:{
#####: 1878: for (int x = 0; x < MAP_SIZE; x++) {
#####: 1879: for (int y = 0; y < MAP_SIZE; y++) {
#####: 1880: submaps[x][y][VERTICAL_MAP_SIZE]->clear_items();
-: 1881: }
-: 1882: }
#####: 1883:}
-: 1884:
#####: 1885:bool Map::remove_item(Item* it, int uid)
-: 1886:{
-: 1887:// Sanity check
#####: 1888: if (it == NULL && uid < 0) {
#####: 1889: return false;
-: 1890: }
-: 1891:// Code duplication from find_item(), but what can ya do
#####: 1892: for (int x = 0; x < MAP_SIZE; x++) {
#####: 1893: for (int y = 0; y < MAP_SIZE; y++) {
#####: 1894: for (int z = 0; z < VERTICAL_MAP_SIZE * 2 + 1; z++) {
#####: 1895: Submap* sm = submaps[x][y][z];
#####: 1896: if (sm) {
#####: 1897: for (int sx = 0; sx < SUBMAP_SIZE; sx++) {
#####: 1898: for (int sy = 0; sy < SUBMAP_SIZE; sy++) {
#####: 1899: std::vector<Item>* items = sm->items_at(sx, sy);
#####: 1900: if (!items) {
#####: 1901: debugmsg("NULL Items in Map::find_item_uid()");
-: 1902: }
#####: 1903: for (int i = 0; i < items->size(); i++) {
#####: 1904: if ( &( (*items)[i] ) == it || (*items)[i].get_uid() == uid ) {
#####: 1905: items->erase( items->begin() + i );
#####: 1906: return true;
-: 1907: }
-: 1908: }
-: 1909: }
-: 1910: }
-: 1911: }
-: 1912: }
-: 1913: }
-: 1914: }
-: 1915:// If we never found it, return false
#####: 1916: return false;
-: 1917:}
-: 1918:
#####: 1919:bool Map::remove_item_uid(int uid)
-: 1920:{
#####: 1921: return remove_item(NULL, uid);
-: 1922:}
-: 1923:
#####: 1924:bool Map::add_field(Field_type* type, Tripoint pos, std::string creator)
-: 1925:{
#####: 1926: return add_field(type, pos.x, pos.y, pos.z);
-: 1927:}
-: 1928:
#####: 1929:bool Map::add_field(Field_type* type, int x, int y, int z, std::string creator)
-: 1930:{
#####: 1931: if (!type) {
#####: 1932: debugmsg("Tried to add NULL field! (%s)", creator.c_str());
#####: 1933: return false;
-: 1934: }
#####: 1935: Field field(type, 0, creator);
#####: 1936: return add_field(field, x, y, z);
-: 1937:}
-: 1938:
#####: 1939:bool Map::add_field(Field field, Tripoint pos)
-: 1940:{
#####: 1941: return add_field(field, pos.x, pos.y, pos.z);
-: 1942:}
-: 1943:
#####: 1944:bool Map::add_field(Field field, int x, int y, int z)
-: 1945:{
#####: 1946: Tile* tile = get_tile(x, y, z);
#####: 1947: if (tile->has_field()) {
-: 1948:// We can combine fields of the same type
#####: 1949: tile->field += field;
#####: 1950: field_points.push_back( Tripoint(x, y, (z == 999 ? posz : z)) );
#####: 1951: return true;
-: 1952: }
#####: 1953: if (tile->move_cost() == 0 && !field.has_flag(FIELD_FLAG_SOLID)) {
#####: 1954: return false;
-: 1955: }
#####: 1956: tile->field = field;
#####: 1957: field_points.push_back( Tripoint(x, y, (z == 999 ? posz : z)) );
#####: 1958: return true;
-: 1959:}
-: 1960:
#####: 1961:int Map::item_count(Tripoint pos)
-: 1962:{
#####: 1963: return item_count(pos.x, pos.y, pos.z);
-: 1964:}
-: 1965:
#####: 1966:int Map::item_count(int x, int y, int z)
-: 1967:{
#####: 1968: std::vector<Item>* it = items_at(x, y, z);
#####: 1969: if (!it) {
#####: 1970: return 0;
-: 1971: }
#####: 1972: return it->size();
-: 1973:}
-: 1974:
20: 1975:std::vector<Item>* Map::items_at(Tripoint pos)
-: 1976:{
20: 1977: return items_at(pos.x, pos.y, pos.z);
-: 1978:}
-: 1979:
20: 1980:std::vector<Item>* Map::items_at(int x, int y, int z)
-: 1981:{
20: 1982: if (z == 999) { // z defaults to 999
#####: 1983: z = posz;
-: 1984: }
20: 1985: z = z - posz + VERTICAL_MAP_SIZE;
20: 1986: if (x < 0 || x >= SUBMAP_SIZE * MAP_SIZE ||
-: 1987: y < 0 || y >= SUBMAP_SIZE * MAP_SIZE ||
-: 1988: z < 0 || z >= VERTICAL_MAP_SIZE * 2 + 1) {
#####: 1989: return NULL;
-: 1990: }
20: 1991: int sx = x / SUBMAP_SIZE, sy = y / SUBMAP_SIZE;
20: 1992: x %= SUBMAP_SIZE;
20: 1993: y %= SUBMAP_SIZE;
20: 1994: return submaps[sx][sy][z]->items_at(x, y);
-: 1995:}
-: 1996:
#####: 1997:Furniture* Map::furniture_at(Tripoint pos)
-: 1998:{
#####: 1999: return furniture_at(pos.x, pos.y, pos.z);
-: 2000:}
-: 2001:
#####: 2002:Furniture* Map::furniture_at(int x, int y, int z)
-: 2003:{
#####: 2004: Tile* tile = get_tile(x, y, z);
#####: 2005: if (!tile) {
#####: 2006: return NULL;
-: 2007: }
#####: 2008: if (!tile->furniture.is_real()) {
#####: 2009: return NULL;
-: 2010: }
#####: 2011: return &(tile->furniture);
-: 2012:}
-: 2013:
#####: 2014:void Map::add_furniture(Furniture furn, Tripoint pos)
-: 2015:{
#####: 2016: add_furniture(furn, pos.x, pos.y, pos.z);
#####: 2017:}
-: 2018:
#####: 2019:void Map::add_furniture(Furniture furn, int x, int y, int z)
-: 2020:{
#####: 2021: Tile* tile = get_tile(x, y, z);
#####: 2022: if (!tile) {
#####: 2023: return;
-: 2024: }
#####: 2025: tile->add_furniture(furn);
-: 2026:}
-: 2027:
-: 2028:/* grab_furniture() returns a list of the furniture at (target), along with any
-: 2029: * furniture connected to it. Furniture is considered connected if it touches
-: 2030: * in an orthogonal direction, and has the same UID from the mapgen file.
-: 2031: * To achieve this, grab_furniture() recurses into orthogonal tiles, and stops
-: 2032: * if there's no furniture there, or if the furniture is of a different UID.
-: 2033: * (id) defaults to -1, but is set when we recurse.
-: 2034: * Checked is a vector of points already checked, so that we don't get stuck in
-: 2035: * an infinite loop, cycling between two tiles. If it's NULL, we'll set it and
-: 2036: * delete it before we exit.
-: 2037: */
#####: 2038:std::vector<Furniture_pos> Map::grab_furniture(Tripoint origin, Tripoint target,
-: 2039: int id,
-: 2040: std::vector<Tripoint>* checked)
-: 2041:{
-: 2042:/* We have to create (checked) if it doesn't exist. But we also have to
-: 2043: * *remember* that we created it, and delete it before returning, to avoid
-: 2044: * memory leaks.
-: 2045: */
#####: 2046: bool created_checked = false;
#####: 2047: if (checked == NULL) {
#####: 2048: created_checked = true;
#####: 2049: checked = new std::vector<Tripoint>;
-: 2050: }
#####: 2051: std::vector<Furniture_pos> ret;
#####: 2052: Furniture* grabbed = furniture_at(target);
-: 2053:// Return an empty vector if no furniture there
#####: 2054: if (!grabbed) {
#####: 2055: if (created_checked) {
#####: 2056: delete checked;
-: 2057: }
#####: 2058: return ret;
-: 2059: }
-: 2060:// Return an empty vector if furniture is a different UID
#####: 2061: if (id >= 0 && grabbed->uid != id) {
#####: 2062: if (created_checked) {
#####: 2063: delete checked;
-: 2064: }
#####: 2065: return ret;
-: 2066: }
-: 2067:// Success! Push back the furniture at the target tile.
#####: 2068: Furniture_pos at_grab;
#####: 2069: at_grab.furniture = *grabbed;
#####: 2070: at_grab.pos = Point(target.x - origin.x, target.y - origin.y);
#####: 2071: ret.push_back(at_grab);
-: 2072:
-: 2073:// Now recurse...
#####: 2074: checked->push_back(target); // Ensure we won't try this target again.
#####: 2075: int id_used = grabbed->uid;
#####: 2076: for (int i = 1; i <= 4; i++) {
#####: 2077: Tripoint next = target;
#####: 2078: switch (i) {
#####: 2079: case 1: next.x++; break;
#####: 2080: case 2: next.x--; break;
#####: 2081: case 3: next.y++; break;
#####: 2082: case 4: next.y--; break;
-: 2083: }
#####: 2084: bool next_okay = (checked != NULL); // If checked is somehow NULL, skip this
#####: 2085: for (int n = 0; next_okay && n < checked->size(); n++) {
#####: 2086: if ( (*checked)[n] == next ) {
#####: 2087: next_okay = false;
-: 2088: }
-: 2089: }
#####: 2090: if (next_okay) {
-: 2091: std::vector<Furniture_pos> adj = grab_furniture(origin, next, id_used,
#####: 2092: checked);
#####: 2093: for (int n = 0; n < adj.size(); n++) {
#####: 2094: ret.push_back(adj[n]);
#####: 2095: }
-: 2096: }
#####: 2097: }
#####: 2098: if (created_checked) {
#####: 2099: delete checked;
-: 2100: }
#####: 2101: return ret;
-: 2102:}
-: 2103:
#####: 2104:void Map::clear_furniture(Tripoint pos)
-: 2105:{
#####: 2106: clear_furniture(pos.x, pos.y, pos.z);
#####: 2107:}
-: 2108:
#####: 2109:void Map::clear_furniture(int x, int y, int z)
-: 2110:{
#####: 2111: Tile* tile = get_tile(x, y, z);
#####: 2112: if (tile) {
#####: 2113: tile->remove_furniture();
-: 2114: }
#####: 2115:}
-: 2116:
#####: 2117:bool Map::contains_field(Tripoint pos)
-: 2118:{
#####: 2119: return contains_field(pos.x, pos.y, pos.z);
-: 2120:}
-: 2121:
#####: 2122:bool Map::contains_field(int x, int y, int z)
-: 2123:{
#####: 2124: return (get_tile(x, y, z)->has_field());
-: 2125:}
-: 2126:
#####: 2127:Field* Map::field_at(Tripoint pos)
-: 2128:{
#####: 2129: return field_at(pos.x, pos.y, pos.z);
-: 2130:}
-: 2131:
#####: 2132:Field* Map::field_at(int x, int y, int z)
-: 2133:{
#####: 2134: Tile* tile = get_tile(x, y, z);
#####: 2135: return &(tile->field);
-: 2136:}
-: 2137:
#####: 2138:int Map::field_uid_at(Tripoint pos)
-: 2139:{
#####: 2140: return field_uid_at(pos.x, pos.y, pos.z);
-: 2141:}
-: 2142:
#####: 2143:int Map::field_uid_at(int x, int y, int z)
-: 2144:{
#####: 2145: Field* tmp = field_at(x, y, z);
#####: 2146: if (tmp->level <= 0) {
#####: 2147: return -1;
-: 2148: }
#####: 2149: return tmp->get_type_uid();
-: 2150:}
-: 2151:
779625: 2152:Tile* Map::get_tile(Tripoint pos)
-: 2153:{
779625: 2154: return get_tile(pos.x, pos.y, pos.z);
-: 2155:}
-: 2156:
795700: 2157:Tile* Map::get_tile(int x, int y, int z)
-: 2158:{
-: 2159:// TODO: Set all fields, traps, etc. on tile_oob to "nothing"
795700: 2160: if (z == 999) { // z defaults to 999
40: 2161: z = posz;
-: 2162: }
795700: 2163: z = z - posz + VERTICAL_MAP_SIZE;
795700: 2164: if (x < 0 || x >= SUBMAP_SIZE * MAP_SIZE ||
-: 2165: y < 0 || y >= SUBMAP_SIZE * MAP_SIZE ||
-: 2166: z < 0 || z >= VERTICAL_MAP_SIZE * 2 + 1 ) {
1400: 2167: tile_oob.set_terrain(TERRAIN.lookup_uid(0));
1400: 2168: tile_oob.field.dead = true;
1400: 2169: return &tile_oob;
-: 2170: }
-: 2171:
794300: 2172: int sx = x / SUBMAP_SIZE, sy = y / SUBMAP_SIZE;
794300: 2173: if (submaps[sx][sy][z] == NULL) {
#####: 2174: return NULL;
-: 2175: }
794300: 2176: return &(submaps[sx][sy][z]->tiles[x % SUBMAP_SIZE][y % SUBMAP_SIZE]);
-: 2177:}
-: 2178:
#####: 2179:std::string Map::get_name(Tripoint pos)
-: 2180:{
#####: 2181: return get_name(pos.x, pos.y, pos.z);
-: 2182:}
-: 2183:
20: 2184:std::string Map::get_name(int x, int y, int z)
-: 2185:{
20: 2186: Tile* t = get_tile(x, y, z);
20: 2187: if (!t) {
#####: 2188: return "Bug - NULL tile";
-: 2189: }
20: 2190: return t->get_name();
-: 2191:}
-: 2192:
#####: 2193:std::string Map::get_name_indefinite(Tripoint pos)
-: 2194:{
#####: 2195: return get_name_indefinite(pos.x, pos.y, pos.z);
-: 2196:}
-: 2197:
#####: 2198:std::string Map::get_name_indefinite(int x, int y, int z)
-: 2199:{
#####: 2200: Tile* t = get_tile(x, y, z);
#####: 2201: if (!t) {
#####: 2202: return "Bug - NULL tile";
-: 2203: }
#####: 2204: return t->get_name_indefinite();
-: 2205:}
-: 2206:
#####: 2207:void Map::smash(int x, int y, Damage_set dam, bool make_sound)
-: 2208:{
#####: 2209: return smash(x, y, 999, dam, make_sound);
-: 2210:}
-: 2211:
#####: 2212:void Map::smash(int x, int y, int z, Damage_set dam, bool make_sound)
-: 2213:{
#####: 2214: Tile* hit = get_tile(x, y, z);
#####: 2215: if (hit) {
#####: 2216: std::string sound = hit->smash(dam);
#####: 2217: if (make_sound) {
-: 2218:// TODO: Don't hardcode volume (12)?
#####: 2219: GAME.make_sound(sound, 12, x, y);
#####: 2220: }
-: 2221: }
#####: 2222:}
-: 2223:
#####: 2224:void Map::smash(Tripoint pos, Damage_set dam, bool make_sound)
-: 2225:{
#####: 2226: return smash(pos.x, pos.y, pos.z, dam);
-: 2227:}
-: 2228:
#####: 2229:void Map::damage(int x, int y, Damage_set dam)
-: 2230:{
#####: 2231: damage(x, y, 999, dam);
#####: 2232:}
-: 2233:
#####: 2234:void Map::damage(int x, int y, int z, Damage_set dam)
-: 2235:{
#####: 2236: Tile* hit = get_tile(x, y, z);
#####: 2237: if (hit) {
#####: 2238: bool may_explode = has_flag(TF_EXPLOSIVE, x, y, z);
#####: 2239: std::string old_name = get_name(x, y, z);
#####: 2240: if (hit->damage(dam) && may_explode) {
-: 2241:// If we were explosive, then destroying us sets off an explosion!
-: 2242:// TODO: Shoudl explosion particulars be drawn from data? Probably...
#####: 2243: Explosion expl;
#####: 2244: expl.radius = Dice(2, 2, 5); // Average 8
#####: 2245: expl.force = Dice(4, 6, 16); // Average 30
#####: 2246: expl.shrapnel_count = Dice(2, 6, -2); // Average 5
#####: 2247: expl.shrapnel_damage = Dice(3, 6, 4); // Average 14.5
#####: 2248: expl.field_name = "fire";
#####: 2249: expl.field_chance = 25;
#####: 2250: expl.field_duration = Dice(50, 10, 200); // Average 475
#####: 2251: std::stringstream expl_reason;
#####: 2252: expl_reason << "an exploding " << old_name;
#####: 2253: expl.reason = expl_reason.str();
#####: 2254: expl.explode( Tripoint(x, y, z) );
#####: 2255: }
-: 2256: }
#####: 2257:}
-: 2258:
#####: 2259:void Map::damage(Tripoint pos, Damage_set dam)
-: 2260:{
#####: 2261: damage(pos.x, pos.y, pos.z, dam);
#####: 2262:}
-: 2263:
#####: 2264:bool Map::apply_signal(std::string signal, Tripoint pos, Entity* user)
-: 2265:{
#####: 2266: return apply_signal(signal, pos.x, pos.y, pos.z, user);
-: 2267:}
-: 2268:
#####: 2269:bool Map::apply_signal(std::string signal, int x, int y, int z, Entity* user)
-: 2270:{
#####: 2271: Tile* target = get_tile(x, y, z);
#####: 2272: if (target->signal_applies(signal)) {
#####: 2273: target->apply_signal(signal, user);
#####: 2274: return true;
-: 2275: }
#####: 2276: return false;
-: 2277:}
-: 2278:
-: 2279:/* TODO: We should track currently-active fields in a list of points. At
-: 2280: * present, we check *all* tiles for an active field. This is probably
-: 2281: * inefficient.
-: 2282: */
20: 2283:void Map::process_fields()
-: 2284:{
-: 2285:/* TODO: Won't work below ground level.
-: 2286: * TODO: Since we start at the upper-left and work our way down & right, fields
-: 2287: * to the north-west will have a better chance of spreading than fields
-: 2288: * to the south-east. Best way to fix this is to create a output map of
-: 2289: * fields, the copy that output map back to this after processing is
-: 2290: * done.
-: 2291: */
20: 2292: for (int i = 0; i < field_points.size(); i++) {
#####: 2293: Tripoint pos = field_points[i];
#####: 2294: Field* field = field_at(pos);
#####: 2295: if (!field) {
#####: 2296: debugmsg("Somehow encountered NULL field at %s!", pos.str().c_str());
20: 2297: return;
-: 2298: }
#####: 2299: if (field->is_valid()) {
#####: 2300: Entity* ent = GAME.entities.entity_at(pos);
#####: 2301: if (ent) {
#####: 2302: field->hit_entity(ent);
-: 2303: }
#####: 2304: field->process(this, pos);
#####: 2305: if (!field->is_valid()) { // It was destroyed/extinguished!
#####: 2306: field_points.erase( field_points.begin() + i);
#####: 2307: i--;
-: 2308: }
-: 2309: }
#####: 2310: }
-: 2311:}
-: 2312:
-: 2313:/* Still using Cataclysm/DDA style LOS. It sucks and is slow and I hate it.
-: 2314: * Basically, iterate over all Bresenham lines between [x0,y0] and [x1,y1].
-: 2315: * If any of the lines doesn't have something that blocks the relevent sense,
-: 2316: * return true. If we iterate through all of them and they all block, return
-: 2317: * false.
-: 2318: */
#####: 2319:bool Map::senses(int x0, int y0, int x1, int y1, int range, Sense_type sense)
-: 2320:{
#####: 2321: return senses(x0, x0, posz, x1, y1, posz, range, sense);
-: 2322:}
-: 2323:
12656: 2324:bool Map::senses(int x0, int y0, int z0, int x1, int y1, int z1, int range,
-: 2325: Sense_type sense)
-: 2326:{
12656: 2327: if (x0 < 0 || y0 < 0 ||
-: 2328: x1 >= SUBMAP_SIZE * MAP_SIZE || y1 >= SUBMAP_SIZE * MAP_SIZE) {
#####: 2329: return false;
-: 2330: }
12656: 2331: if (range >= 0 && rl_dist(x0, y0, z0, x1, y1, z1) > range) {
560: 2332: return false;
-: 2333: }
12096: 2334: if (sense == SENSE_SIGHT) {
12096: 2335: std::vector<Tripoint> line = line_of_sight(x0, y0, z0, x1, y1, z1);
12096: 2336: return (!line.empty() && (range < 0 || line.size() <= range));
#####: 2337: } else if (sense == SENSE_SMELL) {
-: 2338:// TODO: More realistic smell
#####: 2339: return (rl_dist(x0, y0, z0, x1, y1, z1) <= range);
-: 2340: }
#####: 2341: return false;
-: 2342:}
-: 2343:
#####: 2344:bool Map::clear_path_exists(Tripoint origin, Tripoint target, int range)
-: 2345:{
-: 2346: return clear_path_exists(origin.x, origin.y, origin.z,
#####: 2347: target.x, target.y, target.z, range);
-: 2348:}
-: 2349:
#####: 2350:bool Map::clear_path_exists(int x0, int y0, int z0, int x1, int y1, int z1,
-: 2351: int range)
-: 2352:{
#####: 2353: if (x0 < 0 || y0 < 0 ||
-: 2354: x1 >= SUBMAP_SIZE * MAP_SIZE || y1 >= SUBMAP_SIZE * MAP_SIZE) {
#####: 2355: return false;
-: 2356: }
#####: 2357: if (range >= 0 && rl_dist(x0, y0, z0, x1, y1, z1) > range) {
#####: 2358: return false;
-: 2359: }
#####: 2360: std::vector<Tripoint> line = clear_path(x0, y0, z0, x1, y1, z1);
#####: 2361: return (!line.empty() && (range < 0 || line.size() <= range));
-: 2362:}
-: 2363:
#####: 2364:std::vector<Tripoint> Map::clear_path(Tripoint origin, Tripoint target)
-: 2365:{
#####: 2366: return clear_path(origin.x, origin.y, origin.z, target.x, target.y, target.z);
-: 2367:}
-: 2368:
#####: 2369:std::vector<Tripoint> Map::clear_path(int x0, int y0, int z0,
-: 2370: int x1, int y1, int z1)
-: 2371:{
#####: 2372: std::vector<Tripoint> lines; // Process many lines at once.
#####: 2373: std::vector< std::vector<Tripoint> > return_values;
#####: 2374: std::vector<int> t_values; // T-values for Bresenham lines
-: 2375:
#####: 2376: int dx = x1 - x0, dy = y1 - y0, dz = z1 - z0;
#####: 2377: int ax = abs(dx) << 1, ay = abs(dy) << 1;
#####: 2378: int sx = (dx < 0 ? -1 : 1), sy = (dy < 0 ? -1 : 1);
#####: 2379: int dist = rl_dist(x0, y0, x1, y1);
-: 2380: int z_step;
#####: 2381: if (dist == 0) {
#####: 2382: z_step = 0;
-: 2383: } else {
#####: 2384: z_step = (100 * dz) / dist;
-: 2385: }
#####: 2386: if (dx == 0) {
#####: 2387: sx = 0;
-: 2388: }
#####: 2389: if (dy == 0) {
#####: 2390: sy = 0;
-: 2391: }
-: 2392:
#####: 2393: int min_t = (ax > ay ? ay - ax : ax - ay),
#####: 2394: max_t = 0;
#####: 2395: if (dx == 0 || dy == 0) {
#####: 2396: min_t = 0;
-: 2397: }
-: 2398:// Init our "lines"
#####: 2399: std::vector<Tripoint> seed;
#####: 2400: for (int t = min_t; t <= max_t; t++) {
#####: 2401: lines.push_back( Tripoint(x0, y0, z0) );
#####: 2402: return_values.push_back(seed);
#####: 2403: t_values.push_back(t);
-: 2404: }
#####: 2405: int z_value = 50; // Each tile is 100 microunits tall, start halfway up
#####: 2406: int z_level = z0;
-: 2407:// Keep going as long as we've got at least one valid line
#####: 2408: while (!lines.empty()) {
-: 2409:// Since we track z_value universally, don't do it inside the for loop below
#####: 2410: z_value += z_step;
#####: 2411: if (z_value < 0) {
#####: 2412: z_level--;
#####: 2413: z_value += 100;
#####: 2414: } else if (z_value >= 100) {
#####: 2415: z_level++;
#####: 2416: z_value -= 100;
-: 2417: }
#####: 2418: for (int i = 0; i < lines.size(); i++) {
#####: 2419: lines[i].z = z_level;
#####: 2420: if (ax > ay) {
#####: 2421: lines[i].x += sx;
#####: 2422: if (t_values[i] >= 0) {
#####: 2423: lines[i].y += sy;
#####: 2424: t_values[i] -= ax;
-: 2425: }
#####: 2426: t_values[i] += ay;
-: 2427: } else {
#####: 2428: lines[i].y += sy;
#####: 2429: if (t_values[i] >= 0) {
#####: 2430: lines[i].x += sx;
#####: 2431: t_values[i] -= ay;
-: 2432: }
#####: 2433: t_values[i] += ax;
-: 2434: }
#####: 2435: return_values[i].push_back(lines[i]);
-: 2436:// Don't need to check z, right?
#####: 2437: if (lines[i].x == x1 && lines[i].y == y1) {
#####: 2438: return return_values[i];
-: 2439: }
-: 2440:// TODO: Make this work better over z-values.
#####: 2441: if (move_cost(lines[i]) == 0) {
#####: 2442: lines.erase(lines.begin() + i);
#####: 2443: t_values.erase(t_values.begin() + i);
#####: 2444: return_values.erase(return_values.begin() + i);
#####: 2445: i--;
-: 2446: }
-: 2447: }
-: 2448: }
#####: 2449: return std::vector<Tripoint>();
-: 2450:}
-: 2451:
#####: 2452:bool Map::senses(Point origin, Point target, int range, Sense_type sense)
-: 2453:{
-: 2454: return senses(origin.x, origin.y, posz, target.x, target.y, posz, range,
#####: 2455: sense);
-: 2456:}
-: 2457:
560: 2458:bool Map::senses(Tripoint origin, Tripoint target, int range, Sense_type sense)
-: 2459:{
-: 2460: return senses(origin.x, origin.y, origin.z, target.x, target.y, target.z,
560: 2461: range, sense);
-: 2462:}
-: 2463:
#####: 2464:std::vector<Tripoint> Map::line_of_sight(int x0, int y0, int x1, int y1)
-: 2465:{
#####: 2466: return line_of_sight(x0, y0, posz, x1, y1, posz);
-: 2467:}
-: 2468:
12096: 2469:std::vector<Tripoint> Map::line_of_sight(int x0, int y0, int z0,
-: 2470: int x1, int y1, int z1)
-: 2471:{
12096: 2472: std::vector<Tripoint> lines; // Process many lines at once.
12096: 2473: std::vector<std::vector<Tripoint> > return_values;
12096: 2474: std::vector<int> t_values; // T-values for Bresenham lines
-: 2475:
12096: 2476: int dx = x1 - x0, dy = y1 - y0, dz = z1 - z0;
12096: 2477: int ax = abs(dx) << 1, ay = abs(dy) << 1;
12096: 2478: int sx = (dx < 0 ? -1 : 1), sy = (dy < 0 ? -1 : 1);
12096: 2479: int dist = rl_dist(x0, y0, x1, y1);
-: 2480: int z_step;
12096: 2481: if (dist == 0) {
21: 2482: z_step = 0;
-: 2483: } else {
12075: 2484: z_step = (100 * dz) / dist;
-: 2485: }
12096: 2486: if (dx == 0) {
504: 2487: sx = 0;
-: 2488: }
12096: 2489: if (dy == 0) {
504: 2490: sy = 0;
-: 2491: }
-: 2492:
12096: 2493: int min_t = (ax > ay ? ay - ax : ax - ay),
12096: 2494: max_t = 0;
12096: 2495: if (dx == 0 || dy == 0) {
987: 2496: min_t = 0;
-: 2497: }
-: 2498:// Init our "lines"
12096: 2499: std::vector<Tripoint> seed;
109200: 2500: for (int t = min_t; t <= max_t; t++) {
97104: 2501: lines.push_back( Tripoint(x0, y0, z0) );
97104: 2502: return_values.push_back(seed);
97104: 2503: t_values.push_back(t);
-: 2504: }
12096: 2505: int z_value = 50; // Each tile is 100 microunits tall, start halfway up
12096: 2506: int z_level = z0;
-: 2507:// Keep going as long as we've got at least one valid line
108969: 2508: while (!lines.empty()) {
-: 2509:// Since we track z_value universally, don't do it inside the for loop below
96873: 2510: bool z_stepped = false;
96873: 2511: int old_z = z_level;
96873: 2512: z_value += z_step;
96873: 2513: if (z_value < 0) {
#####: 2514: z_level--;
#####: 2515: z_value += 100;
#####: 2516: z_stepped = true;
96873: 2517: } else if (z_value >= 100) {
#####: 2518: z_level++;
#####: 2519: z_value -= 100;
#####: 2520: z_stepped = true;
-: 2521: }
876498: 2522: for (int i = 0; i < lines.size(); i++) {
791721: 2523: lines[i].z = z_level;
791721: 2524: if (ax > ay) {
392952: 2525: lines[i].x += sx;
392952: 2526: if (t_values[i] >= 0) {
144627: 2527: lines[i].y += sy;
144627: 2528: t_values[i] -= ax;
-: 2529: }
392952: 2530: t_values[i] += ay;
-: 2531: } else {
398769: 2532: lines[i].y += sy;
398769: 2533: if (t_values[i] >= 0) {
150444: 2534: lines[i].x += sx;
150444: 2535: t_values[i] -= ay;
-: 2536: }
398769: 2537: t_values[i] += ax;
-: 2538: }
791721: 2539: return_values[i].push_back(lines[i]);
-: 2540:// Don't need to check z, right?
791721: 2541: if (lines[i].x == x1 && lines[i].y == y1) {
12096: 2542: return return_values[i];
-: 2543: }
779625: 2544: if (blocks_sense(SENSE_SIGHT, lines[i], z_value) ||
-: 2545: (z_stepped &&
#####: 2546: blocks_sense(SENSE_SIGHT, lines[i].x, lines[i].y, old_z))) {
#####: 2547: lines.erase(lines.begin() + i);
#####: 2548: t_values.erase(t_values.begin() + i);
#####: 2549: return_values.erase(return_values.begin() + i);
#####: 2550: i--;
-: 2551: }
-: 2552: }
-: 2553: }
#####: 2554: return std::vector<Tripoint>();
-: 2555:}
-: 2556:
#####: 2557:std::vector<Tripoint> Map::line_of_sight(Point origin, Point target)
-: 2558:{
#####: 2559: return line_of_sight(origin.x, origin.y, target.x, target.y);
-: 2560:}
-: 2561:
#####: 2562:std::vector<Tripoint> Map::line_of_sight(Tripoint origin, Tripoint target)
-: 2563:{
-: 2564: return line_of_sight(origin.x, origin.y, origin.z,
#####: 2565: target.x, target.y, target.z);
-: 2566:}
-: 2567:
21: 2568:void Map::draw(Window* w, Entity_pool *entities, Tripoint ref,
-: 2569: int range, Sense_type sense)
-: 2570:{
21: 2571: draw(w, entities, ref.x, ref.y, ref.z, range, sense);
21: 2572:}
-: 2573:
21: 2574:void Map::draw(Window* w, Entity_pool *entities, int refx, int refy, int refz,
-: 2575: int range, Sense_type sense)
-: 2576:{
21: 2577: if (!w) {
21: 2578: return;
-: 2579: }
21: 2580: int winx = w->sizex(), winy = w->sizey();
21: 2581: if (winy % 2 == 0) {
21: 2582: winy--; // Only odd numbers are allowed!
-: 2583: }
21: 2584: int minx = refx - (winx / 2), maxx = refx + ( (winx - 1) / 2 );
21: 2585: int miny = refy - (winy / 2) - 1, maxy = refy + ( (winy - 1) / 2 );
-: 2586: draw_area(w, entities, refx, refy, refz, minx, miny, maxx, maxy, range,
21: 2587: sense);
-: 2588:}
-: 2589:
#####: 2590:void Map::draw_area(Window *w, Entity_pool *entities, Tripoint ref,
-: 2591: int minx, int miny, int maxx, int maxy,
-: 2592: int range, Sense_type sense)
-: 2593:{
-: 2594: draw_area(w, entities, ref.x, ref.y, ref.z, minx, miny, maxx, maxy, range,
#####: 2595: sense);
#####: 2596:}
-: 2597:
21: 2598:void Map::draw_area(Window *w, Entity_pool *entities,
-: 2599: int refx, int refy, int refz,
-: 2600: int minx, int miny, int maxx, int maxy,
-: 2601: int range, Sense_type sense)
-: 2602:{
21: 2603: if (!w) {
21: 2604: return;
-: 2605: }
-: 2606:
-: 2607:// Range defaults to -1; which means use light level
21: 2608: if (range == -1) {
#####: 2609: range = GAME.get_light_level();
-: 2610: }
-: 2611:
21: 2612: int winx = w->sizex(), winy = w->sizey();
21: 2613: int dist = winx > winy ? winx / 2 : winy / 2;
525: 2614: for (int x = 0; x < winx; x++) {
12600: 2615: for (int y = 0; y < winy; y++) {
12096: 2616: int terx = refx + x - (winx / 2), tery = refy + y - (winy / 2);
12096: 2617: int z_used = posz;
24192: 2618: while (z_used > 0 && has_flag(TF_OPEN_SPACE, terx, tery, z_used)) {
#####: 2619: z_used--;
-: 2620: }
12096: 2621: int range_used = (dist < range ? dist : range);
12096: 2622: if (senses(refx, refy, refz, terx, tery, z_used, range_used, sense)) {
-: 2623:// If we're inbounds, draw normally...
12096: 2624: if (terx >= minx && terx <= maxx && tery >= miny && tery <= maxy) {
12096: 2625: draw_tile(w, entities, terx, tery, refx, refy, false);
-: 2626: } else { // Otherwise, that last "true" means "change colors to dkgray"
#####: 2627: draw_tile(w, entities, terx, tery, refx, refy, false, true);
-: 2628: }
-: 2629: } else {
-: 2630:// TODO: Don't use a literal glyph! TILES GEEZE
#####: 2631: w->putglyph(x, y, glyph(' ', c_black, c_black));
-: 2632: }
-: 2633: }
-: 2634: }
-: 2635:}
-: 2636:
12096: 2637:void Map::draw_tile(Window* w, Entity_pool *entities, int tilex, int tiley,
-: 2638: int refx, int refy, bool invert, bool gray)
-: 2639:{
12096: 2640: draw_tile(w, entities, tilex, tiley, posz, refx, refy, invert, gray);
12096: 2641:}
-: 2642:
12096: 2643:void Map::draw_tile(Window* w, Entity_pool *entities,
-: 2644: int tilex, int tiley, int tilez,
-: 2645: int refx, int refy, bool invert, bool gray)
-: 2646:{
12096: 2647: if (!w) {
#####: 2648: return;
-: 2649: }
12096: 2650: int winx = w->sizex(), winy = w->sizey();
12096: 2651: int centerx = winx / 2, centery = winy / 2;
12096: 2652: int dx = tilex - refx, dy = tiley - refy;
12096: 2653: int tile_winx = centerx + dx, tile_winy = centery + dy;
12096: 2654: if (tile_winx < 0 || tile_winx >= winx || tile_winy < 0 || tile_winy >= winy){
#####: 2655: return; // It won't fit in the window!
-: 2656: }
-: 2657:// Now pick a glyph...
12096: 2658: glyph output;
12096: 2659: bool picked_glyph = false;
12096: 2660: int curz = tilez;
-: 2661:/* Start from the z-level that we're looking at. As long as there's no entity,
-: 2662: * and the terrain is open space, drop down a level.
-: 2663: */
36288: 2664: while (!picked_glyph && curz >= 0) {
12096: 2665: if (entities) {
12096: 2666: Entity* ent = entities->entity_at(tilex, tiley, curz);
12096: 2667: if (ent) {
21: 2668: output = ent->get_glyph();
21: 2669: picked_glyph = true;
-: 2670: }
-: 2671: }
12096: 2672: if (!picked_glyph) {
12075: 2673: Tile* tile = get_tile(tilex, tiley, curz);
12075: 2674: if (!tile->has_flag(TF_OPEN_SPACE)) {
12075: 2675: output = tile->top_glyph();
12075: 2676: picked_glyph = true;
-: 2677: }
-: 2678: }
12096: 2679: if (picked_glyph) {
12096: 2680: if (curz < tilez) {
#####: 2681: output = output.hilite();
-: 2682: }
-: 2683: } else {
#####: 2684: curz--;
-: 2685: }
-: 2686: }
12096: 2687: if (!picked_glyph) {
#####: 2688: int smx = tilex / SUBMAP_SIZE, smy = tiley / SUBMAP_SIZE;
#####: 2689: if (smx < 0 || smx >= MAP_SIZE || smy < 0 || smy >= MAP_SIZE) {
#####: 2690: debugmsg("Could not find a glyph - out of bounds!");
-: 2691: } else {
-: 2692:// Find the submap the tile's in...
#####: 2693: int smz = tilez - posz + VERTICAL_MAP_SIZE;
#####: 2694: Submap* sm = submaps[smx][smy][smz];
#####: 2695: while (!sm && smz > 0) {
#####: 2696: smz--;
#####: 2697: sm = submaps[smx][smy][smz];
-: 2698: }
#####: 2699: if (sm) {
-: 2700: debugmsg("Really could not find a glyph! %s",
#####: 2701: sm->get_spec_name().c_str());
-: 2702: } else {
#####: 2703: debugmsg("Really could not find a glyph - invalid submap!");
-: 2704: }
-: 2705: }
#####: 2706: return;
-: 2707: }
12096: 2708: if (invert) {
#####: 2709: output = output.invert();
-: 2710: }
12096: 2711: if (gray) {
#####: 2712: output.fg = c_dkgray;
-: 2713: }
12096: 2714: w->putglyph(tile_winx, tile_winy, output);
-: 2715:}
-: 2716:
-: 2717:
21: 2718:Submap* Map::get_center_submap()
-: 2719:{
21: 2720: return submaps[MAP_SIZE / 2][MAP_SIZE / 2][VERTICAL_MAP_SIZE];
-: 2721:}
-: 2722:
#####: 2723:Submap* Map::get_testing_submap()
-: 2724:{
#####: 2725: return submaps[MAP_SIZE / 2][MAP_SIZE / 2 - 1][VERTICAL_MAP_SIZE];
-: 2726:}
-: 2727:
-: 2728:
#####: 2729:Point Map::get_center_point()
-: 2730:{
#####: 2731: return Point(posx + MAP_SIZE / 2, posy + MAP_SIZE / 2);
-: 2732:}
-: 2733:
-: 2734:// TODO: Clean this up?
#####: 2735:Tripoint Map::find_item(Item* it, int uid)
-: 2736:{
-: 2737:// Sanity check
#####: 2738: if (it == NULL && uid < 0) {
#####: 2739: return Tripoint(-1, -1, -1);
-: 2740: }
#####: 2741: for (int x = 0; x < MAP_SIZE; x++) {
#####: 2742: for (int y = 0; y < MAP_SIZE; y++) {
#####: 2743: for (int z = 0; z < VERTICAL_MAP_SIZE * 2 + 1; z++) {
#####: 2744: Submap* sm = submaps[x][y][z];
#####: 2745: int rz = z - VERTICAL_MAP_SIZE + posz;
#####: 2746: if (sm) {
#####: 2747: for (int sx = 0; sx < SUBMAP_SIZE; sx++) {
#####: 2748: for (int sy = 0; sy < SUBMAP_SIZE; sy++) {
#####: 2749: int rx = x * SUBMAP_SIZE + sx;
#####: 2750: int ry = y * SUBMAP_SIZE + sy;
#####: 2751: std::vector<Item>* items = sm->items_at(sx, sy);
#####: 2752: if (!items) {
#####: 2753: debugmsg("NULL Items in Map::find_item_uid()");
-: 2754: }
#####: 2755: for (int i = 0; i < items->size(); i++) {
#####: 2756: if ( &( (*items)[i] ) == it || (*items)[i].get_uid() == uid ) {
#####: 2757: return Tripoint(rx, ry, rz);
-: 2758: }
-: 2759: }
-: 2760: }
-: 2761: }
-: 2762: }
-: 2763: }
-: 2764: }
-: 2765: }
-: 2766:// If we never found it... return nothing point
#####: 2767: return Tripoint(-1, -1, -1);
-: 2768:}
-: 2769:
#####: 2770:Tripoint Map::find_item_uid(int uid)
-: 2771:{
#####: 2772: return find_item(NULL, uid);
-: 2773:}
-: 2774:
#####: 2775:std::string Map::get_range_text()
-: 2776:{
#####: 2777: std::stringstream ret;
#####: 2778: Tripoint min(posx, posy, posz), max(posx + MAP_SIZE - 1, posy + MAP_SIZE - 1);
#####: 2779: ret << min.str() << " to " << max.str();
#####: 2780: return ret.str();
-: 2781:}
-: 0:Source:map.cpp
-: 0:Graph:obj/map.gcno
-: 0:Data:obj/map.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include "field.h"
-: 2:#include "map.h"
-: 3:#include "rng.h"
-: 4:#include "globals.h"
-: 5:#include "monster.h"
-: 6:#include "game.h"
-: 7:#include "attack.h"
-: 8:#include "entity.h"
-: 9:#include "enum.h"
-: 10:#include "worldmap.h"
-: 11:#include "files.h" // For SAVE_DIR
-: 12:#include <fstream>
-: 13:#include <sstream>
-: 14:
1454376: 15:Furniture::Furniture()
-: 16:{
1454376: 17: type = NULL;
1454376: 18: uid = -1;
1454376: 19:}
-: 20:
1454376: 21:Furniture::~Furniture()
-: 22:{
1454376: 23:}
-: 24:
1079: 25:void Furniture::set_type(Furniture_type* t)
-: 26:{
1079: 27: type = t;
1079: 28: if (type) {
1079: 29: hp = type->hp;
-: 30: }
1079: 31:}
-: 32:
1079: 33:void Furniture::set_uid(int id)
-: 34:{
1079: 35: uid = id;
1079: 36:}
-: 37:
187950: 38:bool Furniture::is_real()
-: 39:{
187950: 40: return (type);
-: 41:}
-: 42:
#####: 43:int Furniture::get_uid()
-: 44:{
#####: 45: return uid;
-: 46:}
-: 47:
#####: 48:glyph Furniture::get_glyph()
-: 49:{
#####: 50: if (!type) {
#####: 51: return glyph();
-: 52: }
#####: 53: glyph ret = type->sym;
#####: 54: if (is_smashable() && hp > 0 && hp < type->hp) {
#####: 55: int percent = (100 * hp) / type->hp;
#####: 56: if (percent >= 80) {
#####: 57: ret = ret.hilite(c_green);
#####: 58: } else if (percent >= 40) {
#####: 59: ret = ret.hilite(c_brown);
-: 60: } else {
#####: 61: ret = ret.hilite(c_red);
-: 62: }
-: 63: }
#####: 64: return ret;
-: 65:}
-: 66:
143: 67:int Furniture::move_cost()
-: 68:{
143: 69: if (!type) {
#####: 70: return 100;
-: 71: }
143: 72: return type->move_cost;
-: 73:}
-: 74:
#####: 75:int Furniture::get_height()
-: 76:{
#####: 77: if (!type) {
#####: 78: return 0;
-: 79: }
#####: 80: return type->height;
-: 81:}
-: 82:
#####: 83:int Furniture::get_weight()
-: 84:{
#####: 85: if (!type) {
#####: 86: return 0;
-: 87: }
#####: 88: return type->weight;
-: 89:}
-: 90:
#####: 91:std::string Furniture::get_name()
-: 92:{
#####: 93: if (!type) {
#####: 94: return "";
-: 95: }
#####: 96: return type->get_name();
-: 97:}
-: 98:
#####: 99:bool Furniture::has_flag(Terrain_flag flag)
-: 100:{
#####: 101: return (type && type->has_flag(flag));
-: 102:}
-: 103:
#####: 104:bool Furniture::is_smashable()
-: 105:{
#####: 106: return (type && type->smashable);
-: 107:}
-: 108:
#####: 109:std::string Furniture::smash(Damage_set dam)
-: 110:{
#####: 111: if (!is_smashable()) { // This verifies that terrain != NULL
#####: 112: return "";
-: 113: }
#####: 114: Terrain_smash smash = type->smash;
#####: 115: if (rng(1, 100) <= smash.ignore_chance) {
#####: 116: return smash.failure_sound; // Make our "saving throw"
-: 117: }
#####: 118: if (damage(dam)) {
#####: 119: return smash.success_sound;
-: 120: }
#####: 121: return smash.failure_sound;
-: 122:}
-: 123:
-: 124:// Roll all damage types, but only apply whichever is the best.
#####: 125:bool Furniture::damage(Damage_set dam)
-: 126:{
#####: 127: if (!type || type->hp == 0) {
#####: 128: return false;
-: 129: }
-: 130:
#####: 131: int best_dmg = 0;
#####: 132: for (int i = 0; i < DAMAGE_MAX; i++) {
#####: 133: Damage_type damtype = Damage_type(i);
#####: 134: int dmg = dam.get_damage(damtype) - type->smash.armor[damtype].roll();
#####: 135: if (dmg > best_dmg) {
#####: 136: best_dmg = dmg;
-: 137: }
-: 138: }
-: 139:
#####: 140: hp -= best_dmg;
#####: 141: if (hp <= 0) {
#####: 142: return true;
-: 143: }
#####: 144: return false;
-: 145:}
-: 146:
#####: 147:bool Furniture::damage(Damage_type damtype, int dam)
-: 148:{
#####: 149: if (dam <= 0) {
#####: 150: return false;
-: 151: }
#####: 152: if (!type || type->hp == 0) {
#####: 153: return false;
-: 154: }
#####: 155: Dice armor = type->smash.armor[damtype];
#####: 156: dam -= armor.roll();
#####: 157: if (dam <= 0) {
#####: 158: return false;
-: 159: }
#####: 160: hp -= dam;
#####: 161: if (hp <= 0) {
#####: 162: return true;
-: 163: }
#####: 164: return false;
-: 165:}
-: 166:
#####: 167:void Furniture::destroy()
-: 168:{
#####: 169: type = NULL;
#####: 170: uid = -1;
#####: 171:}
-: 172:
#####: 173:std::string Furniture::save_data()
-: 174:{
#####: 175: if (!type) {
#####: 176: return "Done";
-: 177: }
-: 178:
#####: 179: std::stringstream ret;
-: 180:
#####: 181: ret << "Type: " << type->name << std::endl; // Name is a persistant unique ID
#####: 182: ret << "HP: " << hp << std::endl;
#####: 183: ret << "UID: " << uid << std::endl;
#####: 184: ret << "Done";
-: 185:
#####: 186: return ret.str();
-: 187:}
-: 188:
#####: 189:bool Furniture::load_data(std::istream& data)
-: 190:{
#####: 191: std::string ident, junk;
#####: 192: while (ident != "done" && !data.eof()) {
#####: 193: if ( ! (data >> ident) ) {
#####: 194: debugmsg("Couldn't read Furniture data.");
#####: 195: return false;
-: 196: }
#####: 197: ident = no_caps( ident );
-: 198:
#####: 199: if (ident == "type:") {
#####: 200: std::string tmpname;
#####: 201: std::getline(data, tmpname);
#####: 202: tmpname = trim( tmpname );
#####: 203: type = FURNITURE_TYPES.lookup_name(tmpname);
#####: 204: if (!type) {
#####: 205: debugmsg("Unknown furniture '%s'", tmpname.c_str());
#####: 206: return false;
#####: 207: }
-: 208:
#####: 209: } else if (ident == "hp:") {
#####: 210: data >> hp;
#####: 211: std::getline(data, junk);
-: 212:
#####: 213: } else if (ident == "uid:") {
#####: 214: data >> uid;
#####: 215: std::getline(data, junk);
-: 216:
#####: 217: } else if (ident != "done") {
#####: 218: debugmsg("Unknown furniture identifier '%s'", ident.c_str());
#####: 219: return false;
-: 220: }
-: 221: }
#####: 222: return true;
-: 223:}
-: 224:
1504359: 225:void Tile::set_terrain(Terrain* ter)
-: 226:{
1504359: 227: if (!ter) {
#####: 228: debugmsg("Tile::set_terrain(NULL)!");
1504359: 229: return;
-: 230: }
1504359: 231: terrain = ter;
1504359: 232: hp = ter->hp;
-: 233:}
-: 234:
1079: 235:void Tile::add_furniture(Furniture_type* type, int uid)
-: 236:{
1079: 237: if (!type) {
#####: 238: debugmsg("Tile::add_furniture(NULL)!");
1079: 239: return;
-: 240: }
-: 241:
1079: 242: furniture.set_type(type);
1079: 243: furniture.set_uid(uid);
-: 244:}
-: 245:
#####: 246:void Tile::add_furniture(Furniture furn)
-: 247:{
#####: 248: furniture = furn;
#####: 249:}
-: 250:
#####: 251:void Tile::remove_furniture()
-: 252:{
#####: 253: furniture.set_type(NULL);
#####: 254:}
-: 255:
63015: 256:glyph Tile::top_glyph()
-: 257:{
63015: 258: if (field.is_valid()) {
#####: 259: return field.top_glyph();
-: 260: }
63015: 261: if (furniture.is_real()) {
#####: 262: return furniture.get_glyph();
-: 263: }
63015: 264: if (!items.empty() && (!has_flag(TF_SEALED) || !has_flag(TF_OPAQUE))) {
419: 265: if (terrain && !terrain->has_flag(TF_FLOOR)) {
#####: 266: return terrain->sym.hilite(c_blue);
-: 267: }
419: 268: glyph ret = items.back().top_glyph();
419: 269: if (items.size() > 1) {
21: 270: ret = ret.invert();
-: 271: }
419: 272: return ret;
-: 273: }
62596: 274: if (!terrain) {
#####: 275: return glyph();
-: 276: }
62596: 277: glyph ret = terrain->sym;
62596: 278: if (is_smashable() && terrain->hp > 0 && hp < terrain->hp) {
#####: 279: int percent = (100 * hp) / terrain->hp;
#####: 280: if (percent >= 80) {
#####: 281: ret = ret.hilite(c_green);
#####: 282: } else if (percent >= 40) {
#####: 283: ret = ret.hilite(c_brown);
-: 284: } else {
#####: 285: ret = ret.hilite(c_red);
-: 286: }
-: 287: }
62596: 288: return ret;
-: 289:}
-: 290:
50299: 291:int Tile::move_cost()
-: 292:{
50299: 293: if (furniture.is_real()) {
143: 294: return furniture.move_cost();
-: 295: }
50156: 296: if (!terrain) {
#####: 297: return 0;
-: 298: }
50156: 299: return (terrain->movecost);
-: 300:}
-: 301:
12020: 302:int Tile::get_height()
-: 303:{
12020: 304: int ret = (terrain ? terrain->height : 0);
12020: 305: if (furniture.is_real()) {
#####: 306: ret += furniture.get_height();
-: 307: }
12020: 308: return ret;
-: 309:}
-: 310:
20: 311:std::string Tile::get_name()
-: 312:{
20: 313: std::stringstream ret;
20: 314: if (furniture.is_real()) {
#####: 315: ret << furniture.get_name() << " on ";
-: 316: }
20: 317: ret << (terrain ? terrain->get_name() : "<c=red>BUG - Unknown<c=/>");
-: 318:
20: 319: return ret.str();
-: 320:}
-: 321:
#####: 322:std::string Tile::get_name_indefinite()
-: 323:{
#####: 324: std::stringstream ret;
#####: 325: if (furniture.is_real()) {
#####: 326: ret << (furniture.has_flag(TF_PLURAL) ? "some" : "a") << " " <<
#####: 327: furniture.get_name() << " on ";
-: 328: }
#####: 329: if (terrain) {
#####: 330: ret << (terrain->has_flag(TF_PLURAL) ? "some" : "a") << " " <<
#####: 331: terrain->get_name();
-: 332: } else {
#####: 333: ret << "<c=red>BUG - Unknown<c=/>";
-: 334: }
#####: 335: return ret.str();
-: 336:}
-: 337:
22821343: 338:bool Tile::blocks_sense(Sense_type sense, int z_value)
-: 339:{
22821343: 340: if (!terrain) {
#####: 341: return false;
-: 342: }
-: 343:
22821343: 344: switch (sense) {
-: 345:
-: 346: case SENSE_NULL:
#####: 347: return true;
-: 348:
-: 349: case SENSE_SIGHT:
22821343: 350: if (field.is_valid() && field.has_flag(TF_OPAQUE)) {
#####: 351: return true;
22821343: 352: } else if (has_flag(TF_OPAQUE) && z_value <= get_height()) {
12020: 353: return true;
-: 354: }
22809323: 355: return false;
-: 356:
-: 357: case SENSE_SOUND:
#####: 358: return false;
-: 359:
-: 360: case SENSE_ECHOLOCATION:
#####: 361: return (move_cost() == 0);
-: 362:
-: 363: case SENSE_SMELL:
#####: 364: return (move_cost() == 0);
-: 365:
-: 366: case SENSE_OMNISCIENT:
#####: 367: return false;
-: 368:
-: 369: case SENSE_MAX:
#####: 370: return false;
-: 371:
-: 372: }
#####: 373: return false;
-: 374:}
-: 375:
22885801: 376:bool Tile::has_flag(Terrain_flag flag)
-: 377:{
22885801: 378: if (field.is_valid() && field.has_flag(flag)) {
#####: 379: return true;
-: 380: }
22885801: 381: if (!terrain) {
#####: 382: return false;
-: 383: }
22885801: 384: return terrain->has_flag(flag);
-: 385:}
-: 386:
#####: 387:bool Tile::has_field()
-: 388:{
#####: 389: return field.is_valid();
-: 390:}
-: 391:
#####: 392:bool Tile::has_furniture()
-: 393:{
#####: 394: return furniture.is_real();
-: 395:}
-: 396:
62596: 397:bool Tile::is_smashable()
-: 398:{
62596: 399: if (furniture.is_real() && furniture.is_smashable()) {
#####: 400: return true;
-: 401: }
62596: 402: return (terrain && terrain->can_smash());
-: 403:}
-: 404:
#####: 405:std::string Tile::smash(Damage_set dam)
-: 406:{
-: 407:// First check furniture
#####: 408: if (furniture.is_real()) {
#####: 409: std::string sound = furniture.smash(dam);
#####: 410: if (furniture.hp <= 0) { // We destroyed the furniture!
-: 411:// First, add all items in the furniture's type list
#####: 412: Item_group* furn_items = furniture.type->components;
#####: 413: if (furn_items) {
#####: 414: for (int i = 0; i < furn_items->item_types.size(); i++) {
#####: 415: Item it(furn_items->item_types[i].item);
#####: 416: for (int n = 0; n < furn_items->item_types[i].number; n++) {
#####: 417: items.push_back(it);
-: 418: }
#####: 419: }
-: 420: }
-: 421:// Next, destroy the furniture
#####: 422: furniture.destroy();
-: 423: }
#####: 424: return sound; // We smashed furniture, we don't get to smash terrain too!
-: 425: }
-: 426:
#####: 427: if (!is_smashable()) { // This also verifies that terrain != NULL
#####: 428: return "";
-: 429: }
-: 430:
#####: 431: Terrain_smash smash = terrain->smash;
-: 432:
#####: 433: if (rng(1, 100) <= smash.ignore_chance) {
#####: 434: return smash.failure_sound; // Make our "saving throw"
-: 435: }
-: 436:
#####: 437: if (damage(dam)) {
#####: 438: return smash.success_sound;
-: 439: }
-: 440:
#####: 441: return smash.failure_sound;
-: 442:}
-: 443:
-: 444:// Roll all damage types; but only actually use the very best one.
#####: 445:bool Tile::damage(Damage_set dam)
-: 446:{
#####: 447: if (!terrain || terrain->hp == 0) {
#####: 448: return false;
-: 449: }
-: 450:
#####: 451: int best_dmg = 0;
#####: 452: for (int i = 0; i < DAMAGE_MAX; i++) {
#####: 453: Damage_type damtype = Damage_type(i);
#####: 454: int dmg = dam.get_damage(damtype) - terrain->smash.armor[damtype].roll();
#####: 455: if (dmg > best_dmg) {
#####: 456: best_dmg = dmg;
-: 457: }
-: 458: }
-: 459:
#####: 460: hp -= best_dmg;
#####: 461: if (hp <= 0) {
#####: 462: destroy();
#####: 463: return true;
-: 464: }
#####: 465: return false;
-: 466:}
-: 467:
#####: 468:bool Tile::damage(Damage_type type, int dam)
-: 469:{
#####: 470: if (dam <= 0) {
#####: 471: return false;
-: 472: }
#####: 473: if (!terrain || terrain->hp == 0) {
#####: 474: return false;
-: 475: }
#####: 476: Dice armor = terrain->smash.armor[type];
#####: 477: dam -= armor.roll();
#####: 478: if (dam <= 0) {
#####: 479: return false;
-: 480: }
#####: 481: hp -= dam;
#####: 482: if (hp <= 0) {
#####: 483: destroy();
#####: 484: return true;
-: 485: }
#####: 486: return false;
-: 487:}
-: 488:
#####: 489:void Tile::destroy()
-: 490:{
-: 491:// If HP is negative, then we run damage *again* with the extra damage
#####: 492: int extra = 0 - hp;
#####: 493: Terrain* result = TERRAIN.lookup_name( terrain->destroy_result );
#####: 494: if (!result) {
-: 495: debugmsg("Tried to destroy '%s' but couldn't look up result '%s'.",
#####: 496: get_name().c_str(), terrain->destroy_result.c_str());
-: 497: } else {
#####: 498: set_terrain(result);
#####: 499: damage(DAMAGE_NULL, extra); // See above
-: 500: }
#####: 501:}
-: 502:
#####: 503:bool Tile::signal_applies(std::string signal)
-: 504:{
#####: 505: signal = no_caps(signal);
#####: 506: signal = trim(signal);
#####: 507: if (!terrain || terrain->signal_handlers.count(signal) == 0) {
#####: 508: return false;
-: 509: }
#####: 510: return true;
-: 511:}
-: 512:
#####: 513:bool Tile::apply_signal(std::string signal, Entity* user)
-: 514:{
#####: 515: signal = no_caps(signal);
#####: 516: signal = trim(signal);
#####: 517: std::string user_name = "";
-: 518:
#####: 519: if (user) {
#####: 520: user_name = user->get_name_to_player();
-: 521: }
-: 522:
#####: 523: if (!terrain || !signal_applies(signal)) {
#####: 524: if (user) {
#####: 525: GAME.add_msg("Nothing to %s there.", user_name.c_str(), signal.c_str());
-: 526: }
#####: 527: return false;
-: 528: }
-: 529:
#####: 530: Terrain_signal_handler handler = terrain->signal_handlers[signal];
-: 531:
#####: 532: int success = handler.success_rate;
-: 533:// Apply bonuses, if the user exists
#####: 534: if (user) {
-: 535:// Terrain bonuses - check the flags for the terrain the user is on
-: 536:// Kind of weird to check GAME.map from a tile, but... eh
#####: 537: Tile* user_tile = GAME.map->get_tile(user->pos);
#####: 538: if (user_tile) {
#####: 539: for (std::list<Terrain_flag_bonus>::iterator it =
#####: 540: handler.terrain_flag_bonuses.begin();
#####: 541: it != handler.terrain_flag_bonuses.end();
-: 542: it++) {
#####: 543: if (user_tile->has_flag( it->flag )) {
#####: 544: success += it->amount;
-: 545: }
-: 546: }
-: 547: }
-: 548:// Stat bonuses
#####: 549: for (std::list<Stat_bonus>::iterator it = handler.stat_bonuses.begin();
#####: 550: it != handler.stat_bonuses.end();
-: 551: it++) {
#####: 552: int stat = 0;
#####: 553: switch (it->stat) {
#####: 554: case STAT_STRENGTH: stat = user->stats.strength; break;
#####: 555: case STAT_DEXTERITY: stat = user->stats.dexterity; break;
#####: 556: case STAT_INTELLIGENCE: stat = user->stats.intelligence; break;
#####: 557: case STAT_PERCEPTION: stat = user->stats.perception; break;
-: 558: }
-: 559:// Apply stat in different ways, depending on the operator used...
#####: 560: switch (it->op) {
-: 561:
-: 562: case MATH_MULTIPLY:
#####: 563: success += stat * it->amount;
#####: 564: break;
-: 565:
-: 566: case MATH_GREATER_THAN:
#####: 567: if (stat > it->amount) {
#####: 568: success += it->amount_static;
-: 569: }
#####: 570: break;
-: 571:
-: 572: case MATH_GREATER_THAN_OR_EQUAL_TO:
#####: 573: if (stat >= it->amount) {
#####: 574: success += it->amount_static;
-: 575: }
#####: 576: break;
-: 577:
-: 578: case MATH_LESS_THAN:
#####: 579: if (stat < it->amount) {
#####: 580: success += it->amount_static;
-: 581: }
#####: 582: break;
-: 583:
-: 584: case MATH_LESS_THAN_OR_EQUAL_TO:
#####: 585: if (stat <= it->amount) {
#####: 586: success += it->amount_static;
-: 587: }
#####: 588: break;
-: 589:
-: 590: case MATH_EQUAL_TO:
#####: 591: if (stat == it->amount) {
#####: 592: success += it->amount_static;
-: 593: }
#####: 594: break;
-: 595:
-: 596: default:
#####: 597: debugmsg("Tile::apply_signal encountered unknown operator");
#####: 598: return false;
-: 599: } // switch (it->symbol)
-: 600: } // Iterator over handler.bonuses
-: 601: } // if (user)
-: 602:
-: 603:// We've finalized our success rate; now roll against it
-: 604:
#####: 605: if (success <= 0) {
#####: 606: if (user) {
-: 607: GAME.add_msg("<c=red>%s (0 percent success rate)<c=/>",
#####: 608: handler.failure_message.c_str());
-: 609: }
#####: 610: return true; // True since we *tried*
-: 611:
#####: 612: } else if (rng(1, 100) <= success) {
-: 613:// Success!
#####: 614: if (handler.success_message.empty()) {
#####: 615: if (user) {
-: 616: GAME.add_msg("<c=ltred>%s %s the %s.<c=/>",
#####: 617: user_name.c_str(), signal.c_str(), get_name().c_str());
-: 618: }
#####: 619: } else if (user) {
#####: 620: std::stringstream mes;
#####: 621: mes << "<c=ltred>" << handler.success_message << "<c=/>";
#####: 622: GAME.add_msg(mes.str());
-: 623: }
#####: 624: Terrain* result = TERRAIN.lookup_name(handler.result);
#####: 625: if (!result) {
-: 626: debugmsg("Tile::apply_signal couldn't find terrain '%s'! (%s)",
#####: 627: handler.result.c_str(), get_name().c_str());
#####: 628: return false;
-: 629: }
#####: 630: terrain = result;
#####: 631: return true;
-: 632: }
-: 633:// Failure.
#####: 634: if (user) {
#####: 635: GAME.add_msg( handler.failure_message );
-: 636: }
#####: 637: return true; // True cause we still *tried* to...
-: 638:}
-: 639:
#####: 640:std::string Tile::save_data()
-: 641:{
#####: 642: if (!terrain) {
#####: 643: return "Done";
-: 644: }
-: 645:
#####: 646: std::stringstream ret;
-: 647:
#####: 648: ret << "Type: " << terrain->name << std::endl; // Name is a persistant UID
#####: 649: ret << "HP: " << hp << std::endl;
#####: 650: if (field.is_valid()) {
#####: 651: ret << "Field: " << field.save_data() << std::endl;
-: 652: }
#####: 653: if (furniture.is_real()) {
#####: 654: ret << "Furniture: " << std::endl << furniture.save_data() << std::endl;
-: 655: }
#####: 656: for (int i = 0; i < items.size(); i++) {
#####: 657: ret << "Item: " << std::endl << items[i].save_data() << std::endl;
-: 658: }
-: 659:
#####: 660: ret << "Done";
-: 661:
#####: 662: return ret.str();
-: 663:}
-: 664:
#####: 665:bool Tile::load_data(std::istream& data)
-: 666:{
#####: 667: std::string ident, junk;
#####: 668: while (ident != "done" && !data.eof()) {
#####: 669: if ( ! (data >> ident) ) {
#####: 670: debugmsg("Couldn't read data (Tile).");
#####: 671: return false;
-: 672: }
#####: 673: ident = no_caps(ident);
-: 674:
#####: 675: if (ident == "type:") {
#####: 676: std::string tmpname;
#####: 677: std::getline(data, tmpname);
#####: 678: tmpname = trim(tmpname);
#####: 679: terrain = TERRAIN.lookup_name(tmpname);
#####: 680: if (!terrain) {
#####: 681: debugmsg("Unknown Terrain '%s'", tmpname.c_str());
#####: 682: return false;
#####: 683: }
-: 684:
#####: 685: } else if (ident == "hp:") {
#####: 686: data >> hp;
#####: 687: std::getline(data, junk);
-: 688:
#####: 689: } else if (ident == "field:") {
#####: 690: if (!field.load_data(data)) {
#####: 691: field = Field();
-: 692: }
-: 693:
#####: 694: } else if (ident == "furniture:") {
#####: 695: if (!furniture.load_data(data)) {
#####: 696: furniture = Furniture();
-: 697: }
-: 698:
#####: 699: } else if (ident == "item:") {
#####: 700: Item tmpit;
#####: 701: if (tmpit.load_data(data)) {
#####: 702: items.push_back(tmpit);
#####: 703: }
-: 704:
#####: 705: } else if (ident != "done") {
#####: 706: debugmsg("Unknown Tile property '%s'", ident.c_str());
#####: 707: return false;
-: 708: }
-: 709: }
#####: 710: return true;
-: 711:}
-: 712:
2327: 713:Submap::Submap()
-: 714:{
2327: 715: spec_used = NULL;
2327: 716: rotation = DIR_NULL;
2327: 717: level = 0;
2327: 718:}
-: 719:
1459029: 720:Submap::~Submap()
-: 721:{
1459029: 722:}
-: 723:
#####: 724:void Submap::generate_empty()
-: 725:{
#####: 726: Terrain* grass = TERRAIN.lookup_name("grass");
#####: 727: Terrain* dirt = TERRAIN.lookup_name("dirt");
#####: 728: if (!grass || !dirt) {
#####: 729: debugmsg("Couldn't find terrain for generate_empty()");
#####: 730: return;
-: 731: }
-: 732:
#####: 733: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 734: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 735: tiles[x][y].set_terrain(one_in(2) ? grass : dirt);
-: 736: }
-: 737: }
-: 738:}
-: 739:
277: 740:void Submap::generate_open()
-: 741:{
277: 742: Terrain* open = TERRAIN.lookup_name("empty");
277: 743: if (!open) {
#####: 744: debugmsg("Couldn't find terrain 'empty'; Submap::generate_open()");
277: 745: return;
-: 746: }
-: 747:
7202: 748: for (int x = 0; x < SUBMAP_SIZE; x++) {
180050: 749: for (int y = 0; y < SUBMAP_SIZE; y++) {
173125: 750: tiles[x][y].set_terrain(open);
-: 751: }
-: 752: }
-: 753:}
-: 754:
2025: 755:void Submap::generate(Worldmap* map, int posx, int posy, int posz)
-: 756:{
2025: 757: if (!map) {
#####: 758: debugmsg("Submap::generate(NULL, %d, %d)", posx, posy);
#####: 759: generate_empty();
#####: 760: return;
-: 761: }
2025: 762: Worldmap_tile *tile = map->get_tile(posx, posy);
2025: 763: if (!tile) {
#####: 764: generate_empty();
#####: 765: return;
-: 766: }
-: 767: World_terrain* ter[5];
2025: 768: ter[0] = tile->terrain;
-: 769:// North
2025: 770: tile = map->get_tile(posx, posy - 1);
2025: 771: ter[1] = (tile ? tile->terrain : NULL);
-: 772:// East
2025: 773: tile = map->get_tile(posx + 1, posy);
2025: 774: ter[2] = (tile ? tile->terrain : NULL);
-: 775:// South
2025: 776: tile = map->get_tile(posx, posy + 1);
2025: 777: ter[3] = (tile ? tile->terrain : NULL);
-: 778:// West
2025: 779: tile = map->get_tile(posx - 1, posy);
2025: 780: ter[4] = (tile ? tile->terrain : NULL);
-: 781:
2025: 782: generate(ter, posz);
-: 783:}
-: 784:
2025: 785:void Submap::generate(World_terrain* terrain[5], int posz)
-: 786:{
2025: 787: if (!terrain[0]) {
#####: 788: generate_empty();
-: 789: } else {
2025: 790: std::vector<bool> neighbor;
2025: 791: Mapgen_spec* spec = NULL;
-: 792:// We shouldn't ever hit this; Mapgen_pool handles above-ground. But safety!
2025: 793: if (posz > 0) {
#####: 794: generate_open();
2025: 795: } else if (terrain[0]->has_flag(WTF_RELATIONAL)) {
116: 796: neighbor.push_back(false);
580: 797: for (int i = 1; i < 5; i++) {
464: 798: bool nb = (terrain[i] == terrain[0]);
665: 799: for (int n = 0; !nb && n < terrain[0]->connectors.size(); n++) {
201: 800: std::string conn = no_caps( terrain[0]->connectors[n] );
201: 801: if ( no_caps( terrain[i]->get_data_name() ) == conn ) {
6: 802: nb = true;
-: 803: }
201: 804: }
464: 805: neighbor.push_back(nb);
-: 806: }
116: 807: spec = MAPGEN_SPECS.random_for_terrain(terrain[0], neighbor);
-: 808: } else {
1909: 809: spec = MAPGEN_SPECS.random_for_terrain(terrain[0], "", 0);
-: 810: }
2025: 811: if (!spec) {
#####: 812: int num_conn = 0;
#####: 813: for (int i = 0; i < neighbor.size(); i++) {
#####: 814: if (neighbor[i]) {
#####: 815: num_conn++;
-: 816: }
-: 817: }
-: 818: debugmsg("Mapgen::generate() failed to find spec for %s [conn=%d, z=%d]",
#####: 819: terrain[0]->get_data_name().c_str(), num_conn, posz);
#####: 820: generate_empty();
-: 821: return;
-: 822: }
2025: 823: spec->prepare(terrain);
2025: 824: generate( spec );
-: 825: }
-: 826:
-: 827:// If we're above ground, DON'T do adjacency maps!
2025: 828: if (posz > 0) {
#####: 829: return;
-: 830: }
-: 831:
-: 832:// Now do adjacency maps
10125: 833: for (int i = 1; i < 5; i++) {
8100: 834: if (terrain[i] && terrain[i] != terrain[0]) {
1073: 835: Mapgen_spec* adj = MAPGEN_SPECS.random_adjacent_to(terrain[i],terrain[0]);
1073: 836: if (adj) {
671: 837: adj->prepare(terrain);
671: 838: adj->rotate( Direction(i) );
671: 839: generate_adjacent( adj );
-: 840: }
-: 841: }
-: 842: }
-: 843:}
-: 844:
2050: 845:void Submap::generate(Mapgen_spec* spec)
-: 846:{
2050: 847: if (!spec) {
#####: 848: debugmsg("Null spec in Submap::generate()!");
#####: 849: generate_empty();
2050: 850: return;
-: 851: }
-: 852:// Set our subname to the spec's subname (defaults to empty, only matters for
-: 853:// multi-story buildings
-: 854:// Ditto rotation.
2050: 855: spec_used = spec;
2050: 856: subname = spec->subname;
-: 857:// Rotation gets set in Mapgen_spec::prepare(), so it should still be valid here
2050: 858: rotation = spec->rotation;
-: 859:// First, set the terrain.
53300: 860: for (int x = 0; x < SUBMAP_SIZE; x++) {
1332500: 861: for (int y = 0; y < SUBMAP_SIZE; y++) {
1281250: 862: Terrain* ter = spec->pick_terrain(x, y);
1281250: 863: if (!ter) {
-: 864: debugmsg("Generating null terrain at [%d:%d] (%s)", x, y,
#####: 865: spec->get_name().c_str());
#####: 866: spec->debug_output();
-: 867: }
1281250: 868: tiles[x][y].set_terrain(ter);
-: 869: }
-: 870: }
-: 871:
-: 872:// Next, add any furniture that needs adding.
-: 873:// The Game keeps track of furniture UIDs, but so do Mapgen_specs.
-: 874:// So store a std::map of what each Mapgen UID should be translated to.
2050: 875: std::map<int,int> map_uid_to_game_uid;
53300: 876: for (int x = 0; x < SUBMAP_SIZE; x++) {
1332500: 877: for (int y = 0; y < SUBMAP_SIZE; y++) {
1281250: 878: Furniture_type* furniture = spec->pick_furniture(x, y);
1281250: 879: if (furniture) {
1079: 880: int map_uid = spec->pick_furniture_uid(x, y);
1079: 881: if (map_uid_to_game_uid.count(map_uid) == 0) {
837: 882: map_uid_to_game_uid[map_uid] = GAME.get_furniture_uid();
-: 883: }
1079: 884: tiles[x][y].add_furniture(furniture, map_uid_to_game_uid[map_uid]);
-: 885: }
-: 886: }
-: 887: }
-: 888:
-: 889:// Next, add items.
5450: 890: for (std::map<char,Item_area>::iterator it = spec->item_defs.begin();
2725: 891: it != spec->item_defs.end();
-: 892: it++) {
675: 893: Item_area* area = &(it->second);
675: 894: area->reset();
2062: 895: while (area && area->place_item()) {
712: 896: Point p = area->pick_location();
712: 897: Item item( area->pick_type(spec->get_name()) );
712: 898: if (item.type) {
712: 899: item.prep_for_generation();
712: 900: add_item(item, p.x, p.y);
-: 901: }
712: 902: }
-: 903: }
-: 904:
-: 905:// Item_group_amount_areas work similarly!
4110: 906: for (std::map<char,Item_group_amount_area>::iterator
2050: 907: it = spec->item_group_defs.begin();
2055: 908: it != spec->item_group_defs.end();
-: 909: it++) {
5: 910: Item_group_amount_area* area = &(it->second);
5: 911: Item_group_amount group = area->pick_group();
5: 912: int amount = group.amount.roll();
14: 913: for (int i = 0; i < amount; i++) {
9: 914: Point p = area->pick_location();
9: 915: Item item( group.group->pick_type() );
9: 916: item.prep_for_generation();
9: 917: add_item(item, p.x, p.y);
9: 918: }
5: 919: }
-: 920:
-: 921:// Item_amount_areas work the same as Item_group_amount_areas, more or less
4130: 922: for (std::map<char,Item_amount_area>::iterator
2050: 923: it = spec->item_amount_defs.begin();
2065: 924: it != spec->item_amount_defs.end();
-: 925: it++) {
15: 926: Item_amount_area* area = &(it->second);
15: 927: Item_amount item_amt = area->pick_item();
15: 928: int amount = item_amt.amount.roll();
29: 929: for (int i = 0; i < amount; i++) {
14: 930: Point p = area->pick_location();
14: 931: Item item( item_amt.item );
14: 932: item.prep_for_generation();
14: 933: add_item(item, p.x, p.y);
14: 934: }
2065: 935: }
-: 936:}
-: 937:
671: 938:void Submap::generate_adjacent(Mapgen_spec* spec)
-: 939:{
671: 940: if (spec == NULL) {
671: 941: return;
-: 942: }
-: 943:// First, set the terrain.
17446: 944: for (int x = 0; x < SUBMAP_SIZE; x++) {
436150: 945: for (int y = 0; y < SUBMAP_SIZE; y++) {
419375: 946: Terrain* tmpter = spec->pick_terrain(x, y);
-: 947:// TODO: Only overwrite terrain with the "ground" tag
538007: 948: if (tmpter &&
118632: 949: (!tiles[x][y].terrain || tiles[x][y].terrain->has_flag(TF_MUTABLE))) {
32654: 950: tiles[x][y].set_terrain(tmpter);
-: 951: }
-: 952: }
-: 953: }
-: 954:// Next, add items.
1342: 955: for (std::map<char,Item_area>::iterator it = spec->item_defs.begin();
671: 956: it != spec->item_defs.end();
-: 957: it++) {
#####: 958: Item_area* area = &(it->second);
#####: 959: while (area && area->place_item()) {
#####: 960: Point p = area->pick_location();
#####: 961: Item item( area->pick_type() );
#####: 962: tiles[p.x][p.y].items.push_back(item);
#####: 963: }
-: 964: }
-: 965:}
-: 966:
302: 967:void Submap::generate_above(World_terrain* type, Submap* below)
-: 968:{
302: 969: if (!type) {
#####: 970: debugmsg("Submap::generate_above(NULL, ?) called!");
#####: 971: generate_empty();
#####: 972: return;
-: 973: }
302: 974: if (!below) {
#####: 975: debugmsg("Submap::generate_above(?, NULL) called!");
#####: 976: generate_empty();
#####: 977: return;
-: 978: }
-: 979:
302: 980: level = below->level + 1;
302: 981: subname = below->subname;
302: 982: rotation = below->rotation;
-: 983:
302: 984: Mapgen_spec* spec = MAPGEN_SPECS.random_with_subname(subname, level);
302: 985: if (!spec) {
277: 986: generate_open();
277: 987: return;
-: 988: }
-: 989: World_terrain* ter[5];
25: 990: ter[0] = type;
150: 991: for (int i = 0; i < 5; i++) {
125: 992: ter[i] = NULL;
-: 993: }
25: 994: spec->rotate(rotation);
25: 995: spec->prepare(ter, false); // false means no rotation happens here.
25: 996: generate(spec);
-: 997:// We might need to add stairs to match what's below.
25: 998: if (spec->has_flag(MAPFLAG_AUTOSTAIRS)) {
130: 999: for (int x = 0; x < SUBMAP_SIZE; x++) {
3250: 1000: for (int y = 0; y < SUBMAP_SIZE; y++) {
3125: 1001: Tile* t = &(below->tiles[x][y]);
3125: 1002: if (t->terrain && t->terrain->has_flag(TF_STAIRS_UP)) {
#####: 1003: std::string stair_name = t->terrain->inverse;
#####: 1004: Terrain* stair = TERRAIN.lookup_name(stair_name);
#####: 1005: if (stair) {
#####: 1006: tiles[x][y].set_terrain(stair);
#####: 1007: }
-: 1008: }
-: 1009: }
-: 1010: }
-: 1011: }
-: 1012:}
-: 1013:
#####: 1014:void Submap::clear_items()
-: 1015:{
#####: 1016: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1017: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1018: tiles[x][y].items.clear();
-: 1019: }
-: 1020: }
#####: 1021:}
-: 1022:
735: 1023:bool Submap::add_item(Item item, int x, int y)
-: 1024:{
735: 1025: if (x < 0 || y < 0 || x >= SUBMAP_SIZE || y >= SUBMAP_SIZE) {
7: 1026: return false;
-: 1027: }
728: 1028: if (item.count > 1) {
#####: 1029: int count = item.count;
#####: 1030: item.count = 1;
#####: 1031: for (int i = 0; i < count; i++) {
#####: 1032: if (!add_item(item, x, y)) {
#####: 1033: return false;
-: 1034: }
-: 1035: }
#####: 1036: return true;
-: 1037: }
1429: 1038: if ((tiles[x][y].move_cost() > 0 || tiles[x][y].has_flag(TF_CONTAINER)) &&
701: 1039: !tiles[x][y].has_flag(TF_NO_ITEMS)) {
701: 1040: tiles[x][y].items.push_back(item);
-: 1041: } else {
-: 1042:// Pick a random adjacent space with move_cost != 0
27: 1043: std::vector<Point> valid_points;
108: 1044: for (int px = x - 1; px <= x + 1; px++) {
324: 1045: for (int py = y - 1; py <= y + 1; py++) {
474: 1046: if (px >= 0 && py >= 0 && px < SUBMAP_SIZE && py < SUBMAP_SIZE &&
231: 1047: tiles[px][py].move_cost() > 0) {
142: 1048: valid_points.push_back( Point(px, py) );
-: 1049: }
-: 1050: }
-: 1051: }
27: 1052: if (valid_points.empty()) {
#####: 1053: return false; // No valid points! Oh well. ITEM OBLITERATED
-: 1054:// TODO: Don't obliterate items.
-: 1055: }
27: 1056: int index = rng(0, valid_points.size() - 1);
27: 1057: Point p = valid_points[index];
27: 1058: tiles[p.x][p.y].items.push_back(item);
-: 1059: }
728: 1060: return true;
-: 1061:}
-: 1062:
#####: 1063:int Submap::item_count(int x, int y)
-: 1064:{
#####: 1065: if (x < 0 || x >= SUBMAP_SIZE || x < 0 || y >= SUBMAP_SIZE) {
#####: 1066: return 0;
-: 1067: }
#####: 1068: return tiles[x][y].items.size();
-: 1069:}
-: 1070:
20: 1071:std::vector<Item>* Submap::items_at(int x, int y)
-: 1072:{
20: 1073: if (x < 0 || x >= SUBMAP_SIZE || x < 0 || y >= SUBMAP_SIZE) {
#####: 1074: return NULL;
-: 1075: }
20: 1076: return &(tiles[x][y].items);
-: 1077:}
-: 1078:
#####: 1079:Point Submap::random_empty_tile()
-: 1080:{
#####: 1081: std::vector<Point> options;
#####: 1082: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1083: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1084: if (tiles[x][y].move_cost() > 0) {
#####: 1085: options.push_back( Point(x, y) );
-: 1086: }
-: 1087: }
-: 1088: }
-: 1089:
#####: 1090: if (options.empty()) {
#####: 1091: return Point(-1, -1);
-: 1092: }
#####: 1093: return options[ rng(0, options.size() - 1) ];
-: 1094:}
-: 1095:
#####: 1096:std::string Submap::get_spec_name()
-: 1097:{
#####: 1098: if (!spec_used) {
#####: 1099: return "Unknown";
-: 1100: }
#####: 1101: return spec_used->get_name();
-: 1102:}
-: 1103:
21: 1104:std::string Submap::get_world_ter_name()
-: 1105:{
21: 1106: if (!spec_used) {
#####: 1107: return "";
-: 1108: }
21: 1109: return spec_used->terrain_name;
-: 1110:}
-: 1111:
#####: 1112:std::string Submap::save_data()
-: 1113:{
#####: 1114: std::stringstream ret;
-: 1115:
#####: 1116: if (spec_used) {
#####: 1117: ret << "Spec: " << spec_used->get_short_name() << std::endl;
-: 1118: }
-: 1119:
#####: 1120: if (!subname.empty()) {
#####: 1121: ret << "Subname: " << subname << std::endl;
-: 1122: }
#####: 1123: ret << "Rotation: " << int(rotation) << std::endl;
#####: 1124: ret << "Level: " << level << std::endl;
#####: 1125: ret << "Tiles: " << std::endl;
#####: 1126: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1127: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1128: ret << tiles[x][y].save_data() << std::endl;
-: 1129: }
-: 1130: }
-: 1131:
#####: 1132: ret << "Done";
-: 1133:
#####: 1134: return ret.str();
-: 1135:}
-: 1136:
#####: 1137:bool Submap::load_data(std::istream& data)
-: 1138:{
#####: 1139: std::string ident, junk;
#####: 1140: while (ident != "done" && !data.eof()) {
#####: 1141: if ( ! (data >> ident) ) {
#####: 1142: debugmsg("Couldn't read Submap data.");
#####: 1143: return false;
-: 1144: }
#####: 1145: ident = no_caps(ident);
-: 1146:
#####: 1147: if (ident == "tiles:") {
#####: 1148: for (int x = 0; x < SUBMAP_SIZE; x++) {
#####: 1149: for (int y = 0; y < SUBMAP_SIZE; y++) {
#####: 1150: if (!tiles[x][y].load_data(data)) {
#####: 1151: debugmsg("Failed to read Submap Tile [%d:%d]", x, y);
#####: 1152: return false;
-: 1153: }
-: 1154: }
-: 1155: }
-: 1156:
#####: 1157: } else if (ident == "spec:") {
#####: 1158: std::string specname;
#####: 1159: std::getline(data, specname);
#####: 1160: specname = trim(specname);
#####: 1161: spec_used = MAPGEN_SPECS.lookup_name(specname);
#####: 1162: if (!spec_used) {
#####: 1163: debugmsg("Unknown Mapgen_spec %s.", specname.c_str());
#####: 1164: return false;
#####: 1165: }
-: 1166:
#####: 1167: } else if (ident == "subname:") {
#####: 1168: std::string tmpname;
#####: 1169: std::getline(data, tmpname);
#####: 1170: subname = trim(tmpname);
-: 1171:
#####: 1172: } else if (ident == "rotation:") {
-: 1173: int tmprot;
#####: 1174: data >> tmprot;
#####: 1175: if (tmprot < 0 || tmprot > DIR_WEST) {
#####: 1176: debugmsg("Invalid rotation %d (range is 0 - 5).", tmprot);
#####: 1177: return false;
-: 1178: }
#####: 1179: rotation = Direction(tmprot);
#####: 1180: std::getline(data, junk);
-: 1181:
#####: 1182: } else if (ident == "level:") {
#####: 1183: data >> level;
#####: 1184: std::getline(data, junk);
-: 1185:
#####: 1186: } else if (ident != "done") {
#####: 1187: debugmsg("Unknown Submap property '%s'", ident.c_str());
-: 1188: }
-: 1189: }
#####: 1190: if (ident != "done") {
#####: 1191: debugmsg("Submap save data was incomplete.");
#####: 1192: return false;
-: 1193: }
#####: 1194: return true;
-: 1195:}
-: 1196:
1: 1197:Submap_pool::Submap_pool()
-: 1198:{
1: 1199: sector = Point(-1, -1);
1: 1200:}
-: 1201:
2: 1202:Submap_pool::~Submap_pool()
-: 1203:{
4656: 1204: for (std::list<Submap*>::iterator it = instances.begin();
2328: 1205: it != instances.end();
-: 1206: it++) {
2327: 1207: delete (*it);
-: 1208: }
1: 1209:}
-: 1210:
1316: 1211:Submap* Submap_pool::at_location(int x, int y, int z)
-: 1212:{
1316: 1213: return at_location( Tripoint(x, y, z) );
-: 1214:}
-: 1215:
#####: 1216:Submap* Submap_pool::at_location(Point p)
-: 1217:{
#####: 1218: Tripoint trip(p.x, p.y, 0);
#####: 1219: return at_location(trip);
-: 1220:}
-: 1221:
1316: 1222:Submap* Submap_pool::at_location(Tripoint p)
-: 1223:{
1316: 1224: if (point_map.count(p) > 0) {
1014: 1225: return point_map[p];
-: 1226: }
-: 1227:/*
-: 1228: if (TESTING_MODE) {
-: 1229: debugmsg("WARNING: Generating rogue submap %s! We have %s.",
-: 1230: p.str().c_str(), get_range_text().c_str());
-: 1231: }
-: 1232:*/
302: 1233: return generate_submap(p);
-: 1234:}
-: 1235:
42: 1236:void Submap_pool::load_area(int sector_x, int sector_y)
-: 1237:{
42: 1238: int max_sector = WORLDMAP_SIZE / SECTOR_SIZE;
42: 1239: if (sector_x < 0 || sector_x > max_sector ||
-: 1240: sector_y < 0 || sector_y > max_sector ) {
-: 1241: debugmsg("Submap_pool::load_area(%d, %d) - limit (%d, %d)",
#####: 1242: sector_x, sector_y, max_sector, max_sector);
#####: 1243: return;
-: 1244: }
-: 1245:
-: 1246:// Check if we're loading what we already have - if so, skip all this work
42: 1247: if (sector_x == sector.x && sector_y == sector.y) {
41: 1248: return;
-: 1249: }
-: 1250:
-: 1251:// Start by clearing out existing submaps which we don't need...
-: 1252:// (unless we're brand-new)
1: 1253: if (sector.x != -1 && sector.y != -1) {
#####: 1254: clear_submaps(sector_x, sector_y);
-: 1255: }
-: 1256:
-: 1257:/* At this point, we've saved and deleted all submaps which won't be in the
-: 1258: * updated pool. The next step is to load (or generate if need be) all the
-: 1259: * submaps which WILL be in the updated pool.
-: 1260: */
1: 1261: init_submaps(sector_x, sector_y);
-: 1262:
-: 1263:// Finally, set sector.
1: 1264: sector = Point(sector_x, sector_y);
-: 1265:
-: 1266:}
-: 1267:
42: 1268:void Submap_pool::load_area_centered_on(int center_x, int center_y)
-: 1269:{
42: 1270: if (center_x < 0 || center_x >= WORLDMAP_SIZE ||
-: 1271: center_y < 0 || center_y >= WORLDMAP_SIZE ) {
-: 1272: debugmsg("Submap_pool::load_area_centered_on(%d, %d) - limit (%d, %d)",
#####: 1273: center_x, center_y, WORLDMAP_SIZE, WORLDMAP_SIZE);
42: 1274: return;
-: 1275: }
-: 1276:// e.g. SECTOR_SIZE = 10; 47 => 40
42: 1277: int sector_x = center_x - (center_x % SECTOR_SIZE);
42: 1278: int sector_y = center_y - (center_y % SECTOR_SIZE);
-: 1279:
-: 1280:// 40 => 4
42: 1281: sector_x /= SECTOR_SIZE;
42: 1282: sector_y /= SECTOR_SIZE;
-: 1283:
-: 1284:// But these numbers are for the CENTER sector! So subtract one.
42: 1285: if (sector_x > 0) {
42: 1286: sector_x--;
-: 1287: }
42: 1288: if (sector_y > 0) {
42: 1289: sector_y--;
-: 1290: }
-: 1291:
42: 1292: load_area(sector_x, sector_y);
-: 1293:}
-: 1294:
#####: 1295:int Submap_pool::size()
-: 1296:{
#####: 1297: return instances.size();
-: 1298:}
-: 1299:
#####: 1300:std::string Submap_pool::all_size()
-: 1301:{
#####: 1302: std::stringstream ret;
#####: 1303: ret << "instances: " << instances.size() << " point_map: " <<
#####: 1304: point_map.size();
#####: 1305: return ret.str();
-: 1306:}
-: 1307:
#####: 1308:std::string Submap_pool::get_range_text()
-: 1309:{
#####: 1310: std::stringstream ret;
#####: 1311: Point lower = sector;
#####: 1312: Point upper = lower;
#####: 1313: lower.x *= SECTOR_SIZE;
#####: 1314: lower.y *= SECTOR_SIZE;
#####: 1315: upper.x += 3;
#####: 1316: upper.y += 3;
#####: 1317: upper.x *= SECTOR_SIZE;
#####: 1318: upper.y *= SECTOR_SIZE;
#####: 1319: upper.x += SECTOR_SIZE - 1;
#####: 1320: upper.y += SECTOR_SIZE - 1;
#####: 1321: ret << lower.str() << " to " << upper.str() << " (center ";
#####: 1322: lower.x += SECTOR_SIZE;
#####: 1323: lower.y += SECTOR_SIZE;
#####: 1324: upper.x -= SECTOR_SIZE;
#####: 1325: upper.y -= SECTOR_SIZE;
#####: 1326: ret << lower.str() << " to " << upper.str() << ")";
#####: 1327: return ret.str();
-: 1328:}
-: 1329:
-: 1330:
#####: 1331:void Submap_pool::remove_point(Tripoint p)
-: 1332:{
#####: 1333: if (point_map.count(p) == 0) {
#####: 1334: if (TESTING_MODE) {
#####: 1335: debugmsg("Submap_pool couldn't remove point %s.", p.str().c_str());
-: 1336: }
#####: 1337: return;
-: 1338: }
#####: 1339: point_map.erase(p);
-: 1340:}
-: 1341:
#####: 1342:void Submap_pool::remove_submap(Submap* sm)
-: 1343:{
#####: 1344: if (!sm) {
#####: 1345: if (TESTING_MODE) {
#####: 1346: debugmsg("Submap_pool couldn't remove submap %d.", sm);
-: 1347: }
#####: 1348: return;
-: 1349: }
#####: 1350: delete sm;
#####: 1351: instances.remove(sm);
-: 1352:}
-: 1353:
#####: 1354:void Submap_pool::clear_submaps(int sector_x, int sector_y)
-: 1355:{
#####: 1356: std::string map_dir = SAVE_DIR + "/" + GAME.worldmap->get_name();
#####: 1357: if (!directory_exists(map_dir)) {
#####: 1358: if (!create_directory(map_dir)) {
#####: 1359: debugmsg("Couldn't create directory '%s'.", map_dir.c_str());
-: 1360: return;
-: 1361: }
-: 1362: }
-: 1363:
-: 1364:/*
-: 1365: if (TESTING_MODE) {
-: 1366: debugmsg("Submap_pool::clear_submaps(%d, %d) (sector = %s)",
-: 1367: sector_x, sector_y, sector.str().c_str());
-: 1368: }
-: 1369:*/
#####: 1370: int num_removed = 0;
#####: 1371: for (int sx = sector.x; sx < sector.x + 3; sx++) {
#####: 1372: for (int sy = sector.y; sy < sector.y + 3; sy++) {
-: 1373:// Only save sectors that won't exist in the new Submap_pool.
#####: 1374: if (sx < sector_x || sx >= sector_x + 3 ||
-: 1375: sy < sector_y || sy >= sector_y + 3 ) {
#####: 1376: std::stringstream filename;
#####: 1377: filename << map_dir << "/map." << sx << "." << sy;
#####: 1378: std::ofstream fout;
#####: 1379: fout.open( filename.str().c_str() );
#####: 1380: if (!fout.is_open()) {
#####: 1381: debugmsg("Couldn't open '%s' for writing.", filename.str().c_str());
-: 1382: return;
-: 1383: }
-: 1384:
#####: 1385: int start_x = sx * SECTOR_SIZE, start_y = sy * SECTOR_SIZE;
-: 1386:/*
-: 1387: if (TESTING_MODE) {
-: 1388: debugmsg("Clearing from %d:%d to %d:%d", start_x, start_y,
-: 1389: start_x + SECTOR_SIZE - 1, start_y + SECTOR_SIZE - 1);
-: 1390: }
-: 1391:*/
#####: 1392: for (int mx = start_x; mx < start_x + SECTOR_SIZE; mx++) {
#####: 1393: for (int my = start_y; my < start_y + SECTOR_SIZE; my++) {
#####: 1394: Tripoint curpos = Tripoint(mx, my, 0);
-: 1395:// while loop moves upwards until we stop having maps
#####: 1396: while (point_map.count(curpos) > 0) {
#####: 1397: Submap* curmap = point_map[curpos];
#####: 1398: fout << curpos.x << " " << curpos.y << " " << curpos.z <<
#####: 1399: std::endl << curmap->save_data() << std::endl;
#####: 1400: remove_point(curpos);
#####: 1401: remove_submap(curmap);
#####: 1402: num_removed++;
#####: 1403: curpos.z++;
-: 1404: }
#####: 1405: } // for (start_y <= mx < start_x + SECTOR_SIZE
#####: 1406: } // for (start_x <= mx < start_x + SECTOR_SIZE
-: 1407: } // If <sector is moving out of bounds>
-: 1408: } // for (int sy = sector.y; sy < sector.y + 3; sy++)
#####: 1409: } // for (int sx = sector.x; sx < sector.x + 3; sx++)
-: 1410:
-: 1411:/*
-: 1412: if (TESTING_MODE) {
-: 1413: debugmsg("%d submaps erased; %d left (point_map %d, instances %d).",
-: 1414: num_removed, size(), point_map.size(), instances.size());
-: 1415: }
-: 1416:*/
-: 1417:
-: 1418:}
-: 1419:
1: 1420:void Submap_pool::init_submaps(int sector_x, int sector_y)
-: 1421:{
1: 1422: std::string map_dir = SAVE_DIR + "/" + GAME.worldmap->get_name();
-: 1423:/* The first time we use a new world, the directory won't even exist! This will
-: 1424: * be remedied the first time we have to SAVE Submaps, but for now, we'll take
-: 1425: * it as a sign that we need to generate ALL of them.
-: 1426: */
1: 1427: bool gen_all = false;
1: 1428: if (!directory_exists(map_dir)) {
#####: 1429: gen_all = true;
-: 1430: }
4: 1431: for (int sx = sector_x; sx < sector_x + 3; sx++) {
12: 1432: for (int sy = sector_y; sy < sector_y + 3; sy++) {
-: 1433:/* Again, we check for overlap with the *old* position - no need to re-load
-: 1434: * or re-generate those submaps.
-: 1435: */
9: 1436: if (sx < sector.x || sx >= sector.x + 3 ||
-: 1437: sy < sector.y || sy >= sector.y + 3 ) {
-: 1438:// Attempt to load from file
9: 1439: std::stringstream filename;
9: 1440: if (!gen_all) {
18: 1441: filename << SAVE_DIR << "/" << GAME.worldmap->get_name() << "/map." <<
9: 1442: sx << "." << sy;
-: 1443: }
9: 1444: if (gen_all || !load_submaps( filename.str() )) {
-: 1445:// No file! Generate the submaps.
9: 1446: int startx = sx * SECTOR_SIZE, starty = sy * SECTOR_SIZE;
144: 1447: for (int mx = startx; mx < startx + SECTOR_SIZE; mx++) {
2160: 1448: for (int my = starty; my < starty + SECTOR_SIZE; my++) {
2025: 1449: generate_submap(mx, my);
-: 1450: }
-: 1451: }
9: 1452: }
-: 1453: }
-: 1454: }
1: 1455: }
1: 1456:}
-: 1457:
9: 1458:bool Submap_pool::load_submaps(std::string filename)
-: 1459:{
9: 1460: std::ifstream fin;
9: 1461: fin.open( filename.c_str() );
9: 1462: if (!fin.is_open()) {
9: 1463: return false;
-: 1464: }
#####: 1465: while (!fin.eof()) {
#####: 1466: Tripoint smpos;
#####: 1467: fin >> smpos.x >> smpos.y >> smpos.z;
#####: 1468: if (!fin.eof()) {
-: 1469:/* Too spammy. Uncomment if really needed...
-: 1470: if (TESTING_MODE) {
-: 1471: debugmsg("Loading %s...", smpos.str().c_str());
-: 1472: }
-: 1473: */
#####: 1474: bool use_sm = true;
#####: 1475: if (point_map.count(smpos) > 0) {
#####: 1476: use_sm = false;
-: 1477:/* I commented this out because sometimes, there's supposed to be a submap
-: 1478: * collision - an example is when using Test mode to teleport to a very-close-by
-: 1479: * location. I don't think that a submap collision will ever happen
-: 1480: * unintentionally, and if it does, it doesn't need to be fatal.
-: 1481:
-: 1482: debugmsg("Submap_pool collision at %s!", smpos.str().c_str());
-: 1483: return false;
-: 1484:*/
-: 1485: }
#####: 1486: Submap* sm = new Submap;
#####: 1487: if (sm->load_data(fin)) {
-: 1488:/*
-: 1489: bool shipwreck = TESTING_MODE && sm->spec_used &&
-: 1490: sm->spec_used->get_short_name() ==
-: 1491: "shipwreck_beach_whales";
-: 1492: if (shipwreck) {
-: 1493: debugmsg("Loaded shipwreck");
-: 1494: }
-: 1495:*/
#####: 1496: if (use_sm) {
-: 1497:/*
-: 1498: if (shipwreck) {
-: 1499: debugmsg("Using it!");
-: 1500: }
-: 1501:*/
#####: 1502: instances.push_back(sm);
#####: 1503: point_map[smpos] = sm;
-: 1504: } else {
-: 1505:/*
-: 1506: if (shipwreck) {
-: 1507: debugmsg("Tossing it!");
-: 1508: }
-: 1509:*/
#####: 1510: delete sm;
-: 1511: }
-: 1512: } else {
#####: 1513: delete sm;
#####: 1514: debugmsg("Failed to load submap at %s.", smpos.str().c_str());
#####: 1515: return false;
-: 1516: }
-: 1517: }
#####: 1518: }
#####: 1519: return true;
-: 1520:}
-: 1521:
2025: 1522:Submap* Submap_pool::generate_submap(int x, int y, int z)
-: 1523:{
2025: 1524: return generate_submap( Tripoint(x, y, z) );
-: 1525:}
-: 1526:
2327: 1527:Submap* Submap_pool::generate_submap(Tripoint p)
-: 1528:{
2327: 1529: Submap* sub = new Submap;
2327: 1530: if (p.z > 0) {
302: 1531: Submap* below = at_location(p.x, p.y, p.z - 1);
302: 1532: Worldmap_tile *tile = GAME.worldmap->get_tile(p.x, p.y);
302: 1533: if (!tile) {
#####: 1534: sub->generate_empty();
-: 1535: } else {
302: 1536: sub->generate_above(tile->terrain, below);
-: 1537: }
302: 1538: point_map[p] = sub;
302: 1539: instances.push_back(sub);
302: 1540: return sub;
-: 1541: }
2025: 1542: sub->generate(GAME.worldmap, p.x, p.y, p.z);
2025: 1543: point_map[p] = sub;
2025: 1544: instances.push_back(sub);
2025: 1545: return sub;
-: 1546:}
-: 1547:
1: 1548:Map::Map()
-: 1549:{
1: 1550: posx = 0;
1: 1551: posy = 0;
1: 1552: posz = 0;
-: 1553:
14: 1554: for (int x = 0; x < MAP_SIZE; x++) {
182: 1555: for (int y = 0; y < MAP_SIZE; y++) {
1352: 1556: for (int z = 0; z < VERTICAL_MAP_SIZE * 2 + 1; z++) {
1183: 1557: submaps[x][y][z] = NULL;
-: 1558: }
-: 1559: }
-: 1560: }
1: 1561:}
-: 1562:
1: 1563:Map::~Map()
-: 1564:{
1: 1565:}
-: 1566:
#####: 1567:void Map::generate_empty()
-: 1568:{
#####: 1569: for (int x = 0; x < MAP_SIZE; x++) {
#####: 1570: for (int y = 0; y < MAP_SIZE; y++) {
#####: 1571: submaps[x][y][posz]->generate_empty();
-: 1572: }
-: 1573: }
#####: 1574:}
-: 1575:
-: 1576:/*
-: 1577:void Map::test_generate(std::string terrain_name)
-: 1578:{
-: 1579: for (int x = 0; x < MAP_SIZE; x++) {
-: 1580: for (int y = 0; y < MAP_SIZE; y++) {
-: 1581: submaps[x][y][posz]->generate(terrain_name);
-: 1582: }
-: 1583: }
-: 1584:}
-: 1585:*/
-: 1586:
3: 1587:void Map::generate(Worldmap *world, int wposx, int wposy, int wposz)
-: 1588:{
-: 1589:// All int arguments default to -999
3: 1590: if (wposx != -999) {
1: 1591: posx = wposx;
-: 1592: }
3: 1593: if (wposy != -999) {
1: 1594: posy = wposy;
-: 1595: }
3: 1596: if (wposz != -999) {
1: 1597: posz = wposz;
-: 1598: }
-: 1599:// TODO: Support posz < 0
9: 1600: for (int z = 0; z <= posz + 1; z++) {
6: 1601: int z_index = z + VERTICAL_MAP_SIZE - posz;
84: 1602: for (int x = 0; x < MAP_SIZE; x++) {
1092: 1603: for (int y = 0; y < MAP_SIZE; y++) {
-: 1604:/* at_location either returns the existing submap with that location keyed in,
-: 1605: * or creates a new submap, generates it with the world information at that
-: 1606: * location, and returns it.
-: 1607: */
1014: 1608: submaps[x][y][z_index] = SUBMAP_POOL.at_location(posx + x, posy + y, z);
1014: 1609: if (z == 0) {
507: 1610: spawn_monsters(world, posx + x, posy + y, x, y, z);
-: 1611: }
-: 1612: }
-: 1613: }
-: 1614: }
3: 1615:}
-: 1616:
41: 1617:void Map::shift(Worldmap *world, int shiftx, int shifty, int shiftz)
-: 1618:{
41: 1619: if (shiftx == 0 && shifty == 0 && shiftz == 0) {
80: 1620: return;
-: 1621: }
2: 1622: posx += shiftx;
2: 1623: posy += shifty;
2: 1624: posz += shiftz;
2: 1625: generate(world);
-: 1626:}
-: 1627:
507: 1628:void Map::spawn_monsters(Worldmap *world, int worldx, int worldy,
-: 1629: int subx, int suby, int zlevel)
-: 1630:{
-: 1631:// If we have bad inputs, return with an error message
507: 1632: if (!world) {
#####: 1633: debugmsg("Map::spawn_monsters() called with NULL world");
#####: 1634: return;
-: 1635: }
507: 1636: if (subx < 0 || suby < 0 || subx >= MAP_SIZE || suby >= MAP_SIZE) {
#####: 1637: debugmsg("Map::spawn_monsters() called on submap [%d:%d]", subx, suby);
#####: 1638: return;
-: 1639: }
-: 1640:// Fetch the monsters from the world
507: 1641: std::vector<Monster_spawn>* monsters = world->get_spawns(worldx, worldy);
-: 1642:
507: 1643: if (monsters->empty()) {
463: 1644: return; // No monsters here, skip the rest!
-: 1645: }
-: 1646:
-: 1647:/*
-: 1648: int zdex = zlevel + VERTICAL_MAP_SIZE - posz;
-: 1649:debugmsg("Spawning monsters at World[%d:%d](%s), Submap[%d:%d:%d](%s)",
-: 1650: worldx, worldy, world->get_name(worldx, worldy).c_str(),
-: 1651: subx, suby, posz, submaps[subx][suby][zdex]->get_spec_name().c_str());
-: 1652:*/
-: 1653:
-: 1654:// Pick some empty tiles
-: 1655:/* TODO: Support placing aquatic monsters in water tiles, etc.
-: 1656: * Perhaps by replacing random_empty_tile() with tile_for(Monster_type*)?
-: 1657: */
44: 1658: int minx = subx * SUBMAP_SIZE, miny = suby * SUBMAP_SIZE;
44: 1659: int maxx = minx + SUBMAP_SIZE - 1, maxy = miny + SUBMAP_SIZE - 1;
-: 1660:/*
-: 1661: debugmsg("Submap [%d:%d:%d], tiles [%d:%d] to [%d:%d]",
-: 1662: subx, suby, zlevel, minx, miny, maxx, maxy);
-: 1663:*/
44: 1664: std::vector<Point> available_tiles;
1144: 1665: for (int x = minx; x <= maxx; x++) {
28600: 1666: for (int y = miny; y <= maxy; y++) {
27500: 1667: if (move_cost(x, y, zlevel) > 0) {
25468: 1668: available_tiles.push_back( Point(x, y) );
-: 1669: }
-: 1670: }
-: 1671: }
-: 1672:
-: 1673:/*
-: 1674: if (available_tiles.empty()) {
-: 1675: debugmsg("No available tiles!");
-: 1676: return;
-: 1677: }
-: 1678:*/
88: 1679: for (int i = 0; !available_tiles.empty() && i < monsters->size(); i++) {
238: 1680: while (!available_tiles.empty() && (*monsters)[i].population > 0) {
-: 1681:// Pick an available tile and remove it from the list
150: 1682: int index = rng(0, available_tiles.size() - 1);
150: 1683: Point pos = available_tiles[index];
150: 1684: available_tiles.erase( available_tiles.begin() + index );
-: 1685:// Create a monster and place it there
150: 1686: Monster* mon = (*monsters)[i].generate_monster();
-: 1687://debugmsg("Generating '%s'", mon->get_name().c_str());
150: 1688: mon->pos = Tripoint(pos.x, pos.y, zlevel);
-: 1689:/*
-: 1690:debugmsg("Placed at [%d:%d:%d] - '%s'", pos.x, pos.y, posz,
-: 1691: get_name(pos.x, pos.y, posz).c_str());
-: 1692:*/
150: 1693: GAME.entities.add_entity(mon);
150: 1694: (*monsters)[i].population--;
150: 1695: }
44: 1696: }
-: 1697:}
-: 1698:
#####: 1699:Generic_map Map::get_movement_map(Entity_AI AI,
-: 1700: Tripoint origin, Tripoint target)
-: 1701:{
-: 1702:// Set the bounds of the map
#####: 1703: int min_x = (origin.x < target.x ? origin.x : target.x);
#####: 1704: int min_y = (origin.y < target.y ? origin.y : target.y);
#####: 1705: int min_z = (origin.z < target.z ? origin.z : target.z);
#####: 1706: int max_x = (origin.x > target.x ? origin.x : target.x);
#####: 1707: int max_y = (origin.y > target.y ? origin.y : target.y);
#####: 1708: int max_z = (origin.z > target.z ? origin.z : target.z);
-: 1709:
-: 1710:// Expand the bounds of the map by our area awareness bonus.
#####: 1711: min_x -= AI.area_awareness;
#####: 1712: min_y -= AI.area_awareness;
#####: 1713: max_x += AI.area_awareness;
#####: 1714: max_y += AI.area_awareness;
-: 1715:
#####: 1716: int x_size = 1 + max_x - min_x;
#####: 1717: int y_size = 1 + max_y - min_y;
#####: 1718: int z_size = 1 + max_z - min_z;
-: 1719:
#####: 1720: Generic_map ret(x_size, y_size, z_size);
#####: 1721: ret.x_offset = min_x;
#####: 1722: ret.y_offset = min_y;
#####: 1723: ret.z_offset = min_z;
-: 1724:
#####: 1725: for (int x = min_x; x <= max_x; x++) {
#####: 1726: for (int y = min_y; y <= max_y; y++) {
#####: 1727: for (int z = min_z; z <= max_z; z++) {
#####: 1728: int map_x = x - min_x;
#####: 1729: int map_y = y - min_y;
#####: 1730: int map_z = z - min_z;
#####: 1731: int cost = move_cost(x, y, z);
-: 1732:// TODO: If there's a field here, increase cost accordingly
#####: 1733: if (cost == 0 && is_smashable(x, y, z)) {
#####: 1734: cost = 500; // TODO: Estimate costs more intelligently
-: 1735: }
#####: 1736: ret.set_cost(map_x, map_y, map_z, cost);
#####: 1737: if (has_flag(TF_STAIRS_UP, x, y, z)) {
#####: 1738: ret.set_goes_up( Tripoint(map_x, map_y, map_z) );
-: 1739: }
#####: 1740: if (has_flag(TF_STAIRS_DOWN, x, y, z)) {
#####: 1741: ret.set_goes_down( Tripoint(map_x, map_y, map_z) );
-: 1742: }
-: 1743: }
-: 1744: }
-: 1745: }
-: 1746:
#####: 1747: return ret;
-: 1748:}
-: 1749:
#####: 1750:Generic_map Map::get_dijkstra_map(Tripoint target, int weight,
-: 1751: bool include_smashable)
-: 1752:{
#####: 1753: Generic_map ret(SUBMAP_SIZE * MAP_SIZE, SUBMAP_SIZE * MAP_SIZE, posz + 1);
#####: 1754: ret.set_cost(target, weight);
#####: 1755: std::vector<Tripoint> active;
#####: 1756: active.push_back(target);
#####: 1757: while (!active.empty()) {
#####: 1758: Tripoint cur = active[0];
#####: 1759: active.erase(active.begin());
-: 1760:// Check all adjacent terrain
#####: 1761: for (int x = cur.x - 1; x <= cur.x + 1; x++) {
#####: 1762: for (int y = cur.y - 1; y <= cur.y + 1; y++) {
#####: 1763: if (x == cur.x && y == cur.y) { // Skip our own cell
#####: 1764: y++;
-: 1765: }
#####: 1766: if (((include_smashable && is_smashable(x, y, cur.z)) ||
#####: 1767: move_cost(x, y, cur.z) > 0) &&
#####: 1768: ret.get_cost(x, y, cur.z) < ret.get_cost(cur) - 1) {
#####: 1769: ret.set_cost(x, y, cur.z, ret.get_cost(cur) - 1);
#####: 1770: active.push_back( Tripoint(x, y, cur.z) );
-: 1771: }
-: 1772: }
-: 1773: }
#####: 1774: if (has_flag(TF_STAIRS_DOWN, cur)) {
#####: 1775: Tripoint down(cur.x, cur.y, cur.z - 1);
#####: 1776: if (ret.get_cost(down) < ret.get_cost(cur) - 1) {
#####: 1777: ret.set_cost(down, ret.get_cost(cur) - 1);
#####: 1778: active.push_back( down );
#####: 1779: }
-: 1780: }
#####: 1781: if (has_flag(TF_STAIRS_UP, cur)) {
#####: 1782: Tripoint down(cur.x, cur.y, cur.z + 1);
#####: 1783: if (ret.get_cost(down) < ret.get_cost(cur) - 1) {
#####: 1784: ret.set_cost(down, ret.get_cost(cur) - 1);
#####: 1785: active.push_back( down );
#####: 1786: }
-: 1787: }
#####: 1788: } // while (!active.empty())
#####: 1789: return ret;
-: 1790:}
-: 1791:
#####: 1792:int Map::move_cost(Tripoint pos)
-: 1793:{
#####: 1794: return move_cost(pos.x, pos.y, pos.z);
-: 1795:}
-: 1796:
49340: 1797:int Map::move_cost(int x, int y, int z)
-: 1798:{
49340: 1799: Tile *t = get_tile(x, y, z);
49340: 1800: if (!t) {
#####: 1801: return 100;
-: 1802: }
49340: 1803: return t->move_cost();
-: 1804:}
-: 1805:
#####: 1806:int Map::get_height(Tripoint pos)
-: 1807:{
#####: 1808: return get_height(pos.x, pos.y, pos.z);
-: 1809:}
-: 1810:
#####: 1811:int Map::get_height(int x, int y, int z)
-: 1812:{
#####: 1813: Tile *t = get_tile(x, y, z);
#####: 1814: if (!t) {
#####: 1815: return 0;
-: 1816: }
#####: 1817: return t->get_height();
-: 1818:}
-: 1819:
#####: 1820:bool Map::is_smashable(Tripoint pos)
-: 1821:{
#####: 1822: return is_smashable(pos.x, pos.y, pos.z);
-: 1823:}
-: 1824:
#####: 1825:bool Map::is_smashable(int x, int y, int z)
-: 1826:{
#####: 1827: Tile *t = get_tile(x, y, z);
#####: 1828: return (t && t->is_smashable());
-: 1829:}
-: 1830:
20: 1831:bool Map::has_flag(Terrain_flag flag, Tripoint pos)
-: 1832:{
20: 1833: return has_flag(flag, pos.x, pos.y, pos.z);
-: 1834:}
-: 1835:
40: 1836:bool Map::has_flag(Terrain_flag flag, int x, int y, int z)
-: 1837:{
40: 1838: Tile *t = get_tile(x, y, z);
40: 1839: return (t && t->has_flag(flag));
-: 1840:}
-: 1841:
22821343: 1842:bool Map::blocks_sense(Sense_type sense, Tripoint pos, int z_value)
-: 1843:{
22821343: 1844: Tile *t = get_tile(pos);
22821343: 1845: return (t && t->blocks_sense(sense, z_value));
-: 1846:}
-: 1847:
#####: 1848:bool Map::blocks_sense(Sense_type sense, int x, int y, int z)
-: 1849:{
#####: 1850: Tile *t = get_tile(x, y, z);
#####: 1851: return (t && t->blocks_sense(sense));
-: 1852:}
-: 1853:
#####: 1854:bool Map::add_item(Item item, Tripoint pos)
-: 1855:{
#####: 1856: return add_item(item, pos.x, pos.y, pos.z);
-: 1857:}
-: 1858:
#####: 1859:bool Map::add_item(Item item, int x, int y, int z)
-: 1860:{
#####: 1861: if (z == 999) { // z defaults to 999
#####: 1862: z = posz;
-: 1863: }
#####: 1864: z = z - posz + VERTICAL_MAP_SIZE;
#####: 1865: if (x < 0 || x >= SUBMAP_SIZE * MAP_SIZE ||
-: 1866: y < 0 || y >= SUBMAP_SIZE * MAP_SIZE ||
-: 1867: z < 0 || z >= VERTICAL_MAP_SIZE * 2 + 1) {
#####: 1868: return false;
-: 1869: }
#####: 1870: int sx = x / SUBMAP_SIZE, sy = y / SUBMAP_SIZE;
#####: 1871: x %= SUBMAP_SIZE;
#####: 1872: y %= SUBMAP_SIZE;
#####: 1873: return submaps[sx][sy][z]->add_item(item, x, y);
-: 1874:}
-: 1875:
#####: 1876:void Map::clear_items()
-: 1877:{
#####: 1878: for (int x = 0; x < MAP_SIZE; x++) {
#####: 1879: for (int y = 0; y < MAP_SIZE; y++) {
#####: 1880: submaps[x][y][VERTICAL_MAP_SIZE]->clear_items();
-: 1881: }
-: 1882: }
#####: 1883:}
-: 1884:
#####: 1885:bool Map::remove_item(Item* it, int uid)
-: 1886:{
-: 1887:// Sanity check
#####: 1888: if (it == NULL && uid < 0) {
#####: 1889: return false;
-: 1890: }
-: 1891:// Code duplication from find_item(), but what can ya do
#####: 1892: for (int x = 0; x < MAP_SIZE; x++) {
#####: 1893: for (int y = 0; y < MAP_SIZE; y++) {
#####: 1894: for (int z = 0; z < VERTICAL_MAP_SIZE * 2 + 1; z++) {
#####: 1895: Submap* sm = submaps[x][y][z];
#####: 1896: if (sm) {
#####: 1897: for (int sx = 0; sx < SUBMAP_SIZE; sx++) {
#####: 1898: for (int sy = 0; sy < SUBMAP_SIZE; sy++) {
#####: 1899: std::vector<Item>* items = sm->items_at(sx, sy);
#####: 1900: if (!items) {
#####: 1901: debugmsg("NULL Items in Map::find_item_uid()");
-: 1902: }
#####: 1903: for (int i = 0; i < items->size(); i++) {
#####: 1904: if ( &( (*items)[i] ) == it || (*items)[i].get_uid() == uid ) {
#####: 1905: items->erase( items->begin() + i );
#####: 1906: return true;
-: 1907: }
-: 1908: }
-: 1909: }
-: 1910: }
-: 1911: }
-: 1912: }
-: 1913: }
-: 1914: }
-: 1915:// If we never found it, return false
#####: 1916: return false;
-: 1917:}
-: 1918:
#####: 1919:bool Map::remove_item_uid(int uid)
-: 1920:{
#####: 1921: return remove_item(NULL, uid);
-: 1922:}
-: 1923:
#####: 1924:bool Map::add_field(Field_type* type, Tripoint pos, std::string creator)
-: 1925:{
#####: 1926: return add_field(type, pos.x, pos.y, pos.z);
-: 1927:}
-: 1928:
#####: 1929:bool Map::add_field(Field_type* type, int x, int y, int z, std::string creator)
-: 1930:{
#####: 1931: if (!type) {
#####: 1932: debugmsg("Tried to add NULL field! (%s)", creator.c_str());
#####: 1933: return false;
-: 1934: }
#####: 1935: Field field(type, 0, creator);
#####: 1936: return add_field(field, x, y, z);
-: 1937:}
-: 1938:
#####: 1939:bool Map::add_field(Field field, Tripoint pos)
-: 1940:{
#####: 1941: return add_field(field, pos.x, pos.y, pos.z);
-: 1942:}
-: 1943:
#####: 1944:bool Map::add_field(Field field, int x, int y, int z)
-: 1945:{
#####: 1946: Tile* tile = get_tile(x, y, z);
#####: 1947: if (tile->has_field()) {
-: 1948:// We can combine fields of the same type
#####: 1949: tile->field += field;
#####: 1950: field_points.push_back( Tripoint(x, y, (z == 999 ? posz : z)) );
#####: 1951: return true;
-: 1952: }
#####: 1953: if (tile->move_cost() == 0 && !field.has_flag(FIELD_FLAG_SOLID)) {
#####: 1954: return false;
-: 1955: }
#####: 1956: tile->field = field;
#####: 1957: field_points.push_back( Tripoint(x, y, (z == 999 ? posz : z)) );
#####: 1958: return true;
-: 1959:}
-: 1960:
#####: 1961:int Map::item_count(Tripoint pos)
-: 1962:{
#####: 1963: return item_count(pos.x, pos.y, pos.z);
-: 1964:}
-: 1965:
#####: 1966:int Map::item_count(int x, int y, int z)
-: 1967:{
#####: 1968: std::vector<Item>* it = items_at(x, y, z);
#####: 1969: if (!it) {
#####: 1970: return 0;
-: 1971: }
#####: 1972: return it->size();
-: 1973:}
-: 1974:
20: 1975:std::vector<Item>* Map::items_at(Tripoint pos)
-: 1976:{
20: 1977: return items_at(pos.x, pos.y, pos.z);
-: 1978:}
-: 1979:
20: 1980:std::vector<Item>* Map::items_at(int x, int y, int z)
-: 1981:{
20: 1982: if (z == 999) { // z defaults to 999
#####: 1983: z = posz;
-: 1984: }
20: 1985: z = z - posz + VERTICAL_MAP_SIZE;
20: 1986: if (x < 0 || x >= SUBMAP_SIZE * MAP_SIZE ||
-: 1987: y < 0 || y >= SUBMAP_SIZE * MAP_SIZE ||
-: 1988: z < 0 || z >= VERTICAL_MAP_SIZE * 2 + 1) {
#####: 1989: return NULL;
-: 1990: }
20: 1991: int sx = x / SUBMAP_SIZE, sy = y / SUBMAP_SIZE;
20: 1992: x %= SUBMAP_SIZE;
20: 1993: y %= SUBMAP_SIZE;
20: 1994: return submaps[sx][sy][z]->items_at(x, y);
-: 1995:}
-: 1996:
#####: 1997:Furniture* Map::furniture_at(Tripoint pos)
-: 1998:{
#####: 1999: return furniture_at(pos.x, pos.y, pos.z);
-: 2000:}
-: 2001:
#####: 2002:Furniture* Map::furniture_at(int x, int y, int z)
-: 2003:{
#####: 2004: Tile* tile = get_tile(x, y, z);
#####: 2005: if (!tile) {
#####: 2006: return NULL;
-: 2007: }
#####: 2008: if (!tile->furniture.is_real()) {
#####: 2009: return NULL;
-: 2010: }
#####: 2011: return &(tile->furniture);
-: 2012:}
-: 2013:
#####: 2014:void Map::add_furniture(Furniture furn, Tripoint pos)
-: 2015:{
#####: 2016: add_furniture(furn, pos.x, pos.y, pos.z);
#####: 2017:}
-: 2018:
#####: 2019:void Map::add_furniture(Furniture furn, int x, int y, int z)
-: 2020:{
#####: 2021: Tile* tile = get_tile(x, y, z);
#####: 2022: if (!tile) {
#####: 2023: return;
-: 2024: }
#####: 2025: tile->add_furniture(furn);
-: 2026:}
-: 2027:
-: 2028:/* grab_furniture() returns a list of the furniture at (target), along with any
-: 2029: * furniture connected to it. Furniture is considered connected if it touches
-: 2030: * in an orthogonal direction, and has the same UID from the mapgen file.
-: 2031: * To achieve this, grab_furniture() recurses into orthogonal tiles, and stops
-: 2032: * if there's no furniture there, or if the furniture is of a different UID.
-: 2033: * (id) defaults to -1, but is set when we recurse.
-: 2034: * Checked is a vector of points already checked, so that we don't get stuck in
-: 2035: * an infinite loop, cycling between two tiles. If it's NULL, we'll set it and
-: 2036: * delete it before we exit.
-: 2037: */
#####: 2038:std::vector<Furniture_pos> Map::grab_furniture(Tripoint origin, Tripoint target,
-: 2039: int id,
-: 2040: std::vector<Tripoint>* checked)
-: 2041:{
-: 2042:/* We have to create (checked) if it doesn't exist. But we also have to
-: 2043: * *remember* that we created it, and delete it before returning, to avoid
-: 2044: * memory leaks.
-: 2045: */
#####: 2046: bool created_checked = false;
#####: 2047: if (checked == NULL) {
#####: 2048: created_checked = true;
#####: 2049: checked = new std::vector<Tripoint>;
-: 2050: }
#####: 2051: std::vector<Furniture_pos> ret;
#####: 2052: Furniture* grabbed = furniture_at(target);
-: 2053:// Return an empty vector if no furniture there
#####: 2054: if (!grabbed) {
#####: 2055: if (created_checked) {
#####: 2056: delete checked;
-: 2057: }
#####: 2058: return ret;
-: 2059: }
-: 2060:// Return an empty vector if furniture is a different UID
#####: 2061: if (id >= 0 && grabbed->uid != id) {
#####: 2062: if (created_checked) {
#####: 2063: delete checked;
-: 2064: }
#####: 2065: return ret;
-: 2066: }
-: 2067:// Success! Push back the furniture at the target tile.
#####: 2068: Furniture_pos at_grab;
#####: 2069: at_grab.furniture = *grabbed;
#####: 2070: at_grab.pos = Point(target.x - origin.x, target.y - origin.y);
#####: 2071: ret.push_back(at_grab);
-: 2072:
-: 2073:// Now recurse...
#####: 2074: checked->push_back(target); // Ensure we won't try this target again.
#####: 2075: int id_used = grabbed->uid;
#####: 2076: for (int i = 1; i <= 4; i++) {
#####: 2077: Tripoint next = target;
#####: 2078: switch (i) {
#####: 2079: case 1: next.x++; break;
#####: 2080: case 2: next.x--; break;
#####: 2081: case 3: next.y++; break;
#####: 2082: case 4: next.y--; break;
-: 2083: }
#####: 2084: bool next_okay = (checked != NULL); // If checked is somehow NULL, skip this
#####: 2085: for (int n = 0; next_okay && n < checked->size(); n++) {
#####: 2086: if ( (*checked)[n] == next ) {
#####: 2087: next_okay = false;
-: 2088: }
-: 2089: }
#####: 2090: if (next_okay) {
-: 2091: std::vector<Furniture_pos> adj = grab_furniture(origin, next, id_used,
#####: 2092: checked);
#####: 2093: for (int n = 0; n < adj.size(); n++) {
#####: 2094: ret.push_back(adj[n]);
#####: 2095: }
-: 2096: }
#####: 2097: }
#####: 2098: if (created_checked) {
#####: 2099: delete checked;
-: 2100: }
#####: 2101: return ret;
-: 2102:}
-: 2103:
#####: 2104:void Map::clear_furniture(Tripoint pos)
-: 2105:{
#####: 2106: clear_furniture(pos.x, pos.y, pos.z);
#####: 2107:}
-: 2108:
#####: 2109:void Map::clear_furniture(int x, int y, int z)
-: 2110:{
#####: 2111: Tile* tile = get_tile(x, y, z);
#####: 2112: if (tile) {
#####: 2113: tile->remove_furniture();
-: 2114: }
#####: 2115:}
-: 2116:
#####: 2117:bool Map::contains_field(Tripoint pos)
-: 2118:{
#####: 2119: return contains_field(pos.x, pos.y, pos.z);
-: 2120:}
-: 2121:
#####: 2122:bool Map::contains_field(int x, int y, int z)
-: 2123:{
#####: 2124: return (get_tile(x, y, z)->has_field());
-: 2125:}
-: 2126:
#####: 2127:Field* Map::field_at(Tripoint pos)
-: 2128:{
#####: 2129: return field_at(pos.x, pos.y, pos.z);
-: 2130:}
-: 2131:
#####: 2132:Field* Map::field_at(int x, int y, int z)
-: 2133:{
#####: 2134: Tile* tile = get_tile(x, y, z);
#####: 2135: return &(tile->field);
-: 2136:}
-: 2137:
#####: 2138:int Map::field_uid_at(Tripoint pos)
-: 2139:{
#####: 2140: return field_uid_at(pos.x, pos.y, pos.z);
-: 2141:}
-: 2142:
#####: 2143:int Map::field_uid_at(int x, int y, int z)
-: 2144:{
#####: 2145: Field* tmp = field_at(x, y, z);
#####: 2146: if (tmp->level <= 0) {
#####: 2147: return -1;
-: 2148: }
#####: 2149: return tmp->get_type_uid();
-: 2150:}
-: 2151:
22821343: 2152:Tile* Map::get_tile(Tripoint pos)
-: 2153:{
22821343: 2154: return get_tile(pos.x, pos.y, pos.z);
-: 2155:}
-: 2156:
22933758: 2157:Tile* Map::get_tile(int x, int y, int z)
-: 2158:{
-: 2159:// TODO: Set all fields, traps, etc. on tile_oob to "nothing"
22933758: 2160: if (z == 999) { // z defaults to 999
40: 2161: z = posz;
-: 2162: }
22933758: 2163: z = z - posz + VERTICAL_MAP_SIZE;
22933758: 2164: if (x < 0 || x >= SUBMAP_SIZE * MAP_SIZE ||
-: 2165: y < 0 || y >= SUBMAP_SIZE * MAP_SIZE ||
-: 2166: z < 0 || z >= VERTICAL_MAP_SIZE * 2 + 1 ) {
17330: 2167: tile_oob.set_terrain(TERRAIN.lookup_uid(0));
17330: 2168: tile_oob.field.dead = true;
17330: 2169: return &tile_oob;
-: 2170: }
-: 2171:
22916428: 2172: int sx = x / SUBMAP_SIZE, sy = y / SUBMAP_SIZE;
22916428: 2173: if (submaps[sx][sy][z] == NULL) {
#####: 2174: return NULL;
-: 2175: }
22916428: 2176: return &(submaps[sx][sy][z]->tiles[x % SUBMAP_SIZE][y % SUBMAP_SIZE]);
-: 2177:}
-: 2178:
#####: 2179:std::string Map::get_name(Tripoint pos)
-: 2180:{
#####: 2181: return get_name(pos.x, pos.y, pos.z);
-: 2182:}
-: 2183:
20: 2184:std::string Map::get_name(int x, int y, int z)
-: 2185:{
20: 2186: Tile* t = get_tile(x, y, z);
20: 2187: if (!t) {
#####: 2188: return "Bug - NULL tile";
-: 2189: }
20: 2190: return t->get_name();
-: 2191:}
-: 2192:
#####: 2193:std::string Map::get_name_indefinite(Tripoint pos)
-: 2194:{
#####: 2195: return get_name_indefinite(pos.x, pos.y, pos.z);
-: 2196:}
-: 2197:
#####: 2198:std::string Map::get_name_indefinite(int x, int y, int z)
-: 2199:{
#####: 2200: Tile* t = get_tile(x, y, z);
#####: 2201: if (!t) {
#####: 2202: return "Bug - NULL tile";
-: 2203: }
#####: 2204: return t->get_name_indefinite();
-: 2205:}
-: 2206:
#####: 2207:void Map::smash(int x, int y, Damage_set dam, bool make_sound)
-: 2208:{
#####: 2209: return smash(x, y, 999, dam, make_sound);
-: 2210:}
-: 2211:
#####: 2212:void Map::smash(int x, int y, int z, Damage_set dam, bool make_sound)
-: 2213:{
#####: 2214: Tile* hit = get_tile(x, y, z);
#####: 2215: if (hit) {
#####: 2216: std::string sound = hit->smash(dam);
#####: 2217: if (make_sound) {
-: 2218:// TODO: Don't hardcode volume (12)?
#####: 2219: GAME.make_sound(sound, 12, x, y);
#####: 2220: }
-: 2221: }
#####: 2222:}
-: 2223:
#####: 2224:void Map::smash(Tripoint pos, Damage_set dam, bool make_sound)
-: 2225:{
#####: 2226: return smash(pos.x, pos.y, pos.z, dam);
-: 2227:}
-: 2228:
#####: 2229:void Map::damage(int x, int y, Damage_set dam)
-: 2230:{
#####: 2231: damage(x, y, 999, dam);
#####: 2232:}
-: 2233:
#####: 2234:void Map::damage(int x, int y, int z, Damage_set dam)
-: 2235:{
#####: 2236: Tile* hit = get_tile(x, y, z);
#####: 2237: if (hit) {
#####: 2238: bool may_explode = has_flag(TF_EXPLOSIVE, x, y, z);
#####: 2239: std::string old_name = get_name(x, y, z);
#####: 2240: if (hit->damage(dam) && may_explode) {
-: 2241:// If we were explosive, then destroying us sets off an explosion!
-: 2242:// TODO: Shoudl explosion particulars be drawn from data? Probably...
#####: 2243: Explosion expl;
#####: 2244: expl.radius = Dice(2, 2, 5); // Average 8
#####: 2245: expl.force = Dice(4, 6, 16); // Average 30
#####: 2246: expl.shrapnel_count = Dice(2, 6, -2); // Average 5
#####: 2247: expl.shrapnel_damage = Dice(3, 6, 4); // Average 14.5
#####: 2248: expl.field_name = "fire";
#####: 2249: expl.field_chance = 25;
#####: 2250: expl.field_duration = Dice(50, 10, 200); // Average 475
#####: 2251: std::stringstream expl_reason;
#####: 2252: expl_reason << "an exploding " << old_name;
#####: 2253: expl.reason = expl_reason.str();
#####: 2254: expl.explode( Tripoint(x, y, z) );
#####: 2255: }
-: 2256: }
#####: 2257:}
-: 2258:
#####: 2259:void Map::damage(Tripoint pos, Damage_set dam)
-: 2260:{
#####: 2261: damage(pos.x, pos.y, pos.z, dam);
#####: 2262:}
-: 2263:
#####: 2264:bool Map::apply_signal(std::string signal, Tripoint pos, Entity* user)
-: 2265:{
#####: 2266: return apply_signal(signal, pos.x, pos.y, pos.z, user);
-: 2267:}
-: 2268:
#####: 2269:bool Map::apply_signal(std::string signal, int x, int y, int z, Entity* user)
-: 2270:{
#####: 2271: Tile* target = get_tile(x, y, z);
#####: 2272: if (target->signal_applies(signal)) {
#####: 2273: target->apply_signal(signal, user);
#####: 2274: return true;
-: 2275: }
#####: 2276: return false;
-: 2277:}
-: 2278:
-: 2279:/* TODO: We should track currently-active fields in a list of points. At
-: 2280: * present, we check *all* tiles for an active field. This is probably
-: 2281: * inefficient.
-: 2282: */
20: 2283:void Map::process_fields()
-: 2284:{
-: 2285:/* TODO: Won't work below ground level.
-: 2286: * TODO: Since we start at the upper-left and work our way down & right, fields
-: 2287: * to the north-west will have a better chance of spreading than fields
-: 2288: * to the south-east. Best way to fix this is to create a output map of
-: 2289: * fields, the copy that output map back to this after processing is
-: 2290: * done.
-: 2291: */
20: 2292: for (int i = 0; i < field_points.size(); i++) {
#####: 2293: Tripoint pos = field_points[i];
#####: 2294: Field* field = field_at(pos);
#####: 2295: if (!field) {
#####: 2296: debugmsg("Somehow encountered NULL field at %s!", pos.str().c_str());
20: 2297: return;
-: 2298: }
#####: 2299: if (field->is_valid()) {
#####: 2300: Entity* ent = GAME.entities.entity_at(pos);
#####: 2301: if (ent) {
#####: 2302: field->hit_entity(ent);
-: 2303: }
#####: 2304: field->process(this, pos);
#####: 2305: if (!field->is_valid()) { // It was destroyed/extinguished!
#####: 2306: field_points.erase( field_points.begin() + i);
#####: 2307: i--;
-: 2308: }
-: 2309: }
#####: 2310: }
-: 2311:}
-: 2312:
-: 2313:/* Still using Cataclysm/DDA style LOS. It sucks and is slow and I hate it.
-: 2314: * Basically, iterate over all Bresenham lines between [x0,y0] and [x1,y1].
-: 2315: * If any of the lines doesn't have something that blocks the relevent sense,
-: 2316: * return true. If we iterate through all of them and they all block, return
-: 2317: * false.
-: 2318: */
#####: 2319:bool Map::senses(int x0, int y0, int x1, int y1, int range, Sense_type sense)
-: 2320:{
#####: 2321: return senses(x0, x0, posz, x1, y1, posz, range, sense);
-: 2322:}
-: 2323:
74009: 2324:bool Map::senses(int x0, int y0, int z0, int x1, int y1, int z1, int range,
-: 2325: Sense_type sense)
-: 2326:{
74009: 2327: if (x0 < 0 || y0 < 0 ||
-: 2328: x1 >= SUBMAP_SIZE * MAP_SIZE || y1 >= SUBMAP_SIZE * MAP_SIZE) {
#####: 2329: return false;
-: 2330: }
74009: 2331: if (range >= 0 && rl_dist(x0, y0, z0, x1, y1, z1) > range) {
10484: 2332: return false;
-: 2333: }
63525: 2334: if (sense == SENSE_SIGHT) {
63525: 2335: std::vector<Tripoint> line = line_of_sight(x0, y0, z0, x1, y1, z1);
63525: 2336: return (!line.empty() && (range < 0 || line.size() <= range));
#####: 2337: } else if (sense == SENSE_SMELL) {
-: 2338:// TODO: More realistic smell
#####: 2339: return (rl_dist(x0, y0, z0, x1, y1, z1) <= range);
-: 2340: }
#####: 2341: return false;
-: 2342:}
-: 2343:
#####: 2344:bool Map::clear_path_exists(Tripoint origin, Tripoint target, int range)
-: 2345:{
-: 2346: return clear_path_exists(origin.x, origin.y, origin.z,
#####: 2347: target.x, target.y, target.z, range);
-: 2348:}
-: 2349:
#####: 2350:bool Map::clear_path_exists(int x0, int y0, int z0, int x1, int y1, int z1,
-: 2351: int range)
-: 2352:{
#####: 2353: if (x0 < 0 || y0 < 0 ||
-: 2354: x1 >= SUBMAP_SIZE * MAP_SIZE || y1 >= SUBMAP_SIZE * MAP_SIZE) {
#####: 2355: return false;
-: 2356: }
#####: 2357: if (range >= 0 && rl_dist(x0, y0, z0, x1, y1, z1) > range) {
#####: 2358: return false;
-: 2359: }
#####: 2360: std::vector<Tripoint> line = clear_path(x0, y0, z0, x1, y1, z1);
#####: 2361: return (!line.empty() && (range < 0 || line.size() <= range));
-: 2362:}
-: 2363:
#####: 2364:std::vector<Tripoint> Map::clear_path(Tripoint origin, Tripoint target)
-: 2365:{
#####: 2366: return clear_path(origin.x, origin.y, origin.z, target.x, target.y, target.z);
-: 2367:}
-: 2368:
#####: 2369:std::vector<Tripoint> Map::clear_path(int x0, int y0, int z0,
-: 2370: int x1, int y1, int z1)
-: 2371:{
#####: 2372: std::vector<Tripoint> lines; // Process many lines at once.
#####: 2373: std::vector< std::vector<Tripoint> > return_values;
#####: 2374: std::vector<int> t_values; // T-values for Bresenham lines
-: 2375:
#####: 2376: int dx = x1 - x0, dy = y1 - y0, dz = z1 - z0;
#####: 2377: int ax = abs(dx) << 1, ay = abs(dy) << 1;
#####: 2378: int sx = (dx < 0 ? -1 : 1), sy = (dy < 0 ? -1 : 1);
#####: 2379: int dist = rl_dist(x0, y0, x1, y1);
-: 2380: int z_step;
#####: 2381: if (dist == 0) {
#####: 2382: z_step = 0;
-: 2383: } else {
#####: 2384: z_step = (100 * dz) / dist;
-: 2385: }
#####: 2386: if (dx == 0) {
#####: 2387: sx = 0;
-: 2388: }
#####: 2389: if (dy == 0) {
#####: 2390: sy = 0;
-: 2391: }
-: 2392:
#####: 2393: int min_t = (ax > ay ? ay - ax : ax - ay),
#####: 2394: max_t = 0;
#####: 2395: if (dx == 0 || dy == 0) {
#####: 2396: min_t = 0;
-: 2397: }
-: 2398:// Init our "lines"
#####: 2399: std::vector<Tripoint> seed;
#####: 2400: for (int t = min_t; t <= max_t; t++) {
#####: 2401: lines.push_back( Tripoint(x0, y0, z0) );
#####: 2402: return_values.push_back(seed);
#####: 2403: t_values.push_back(t);
-: 2404: }
#####: 2405: int z_value = 50; // Each tile is 100 microunits tall, start halfway up
#####: 2406: int z_level = z0;
-: 2407:// Keep going as long as we've got at least one valid line
#####: 2408: while (!lines.empty()) {
-: 2409:// Since we track z_value universally, don't do it inside the for loop below
#####: 2410: z_value += z_step;
#####: 2411: if (z_value < 0) {
#####: 2412: z_level--;
#####: 2413: z_value += 100;
#####: 2414: } else if (z_value >= 100) {
#####: 2415: z_level++;
#####: 2416: z_value -= 100;
-: 2417: }
#####: 2418: for (int i = 0; i < lines.size(); i++) {
#####: 2419: lines[i].z = z_level;
#####: 2420: if (ax > ay) {
#####: 2421: lines[i].x += sx;
#####: 2422: if (t_values[i] >= 0) {
#####: 2423: lines[i].y += sy;
#####: 2424: t_values[i] -= ax;
-: 2425: }
#####: 2426: t_values[i] += ay;
-: 2427: } else {
#####: 2428: lines[i].y += sy;
#####: 2429: if (t_values[i] >= 0) {
#####: 2430: lines[i].x += sx;
#####: 2431: t_values[i] -= ay;
-: 2432: }
#####: 2433: t_values[i] += ax;
-: 2434: }
#####: 2435: return_values[i].push_back(lines[i]);
-: 2436:// Don't need to check z, right?
#####: 2437: if (lines[i].x == x1 && lines[i].y == y1) {
#####: 2438: return return_values[i];
-: 2439: }
-: 2440:// TODO: Make this work better over z-values.
#####: 2441: if (move_cost(lines[i]) == 0) {
#####: 2442: lines.erase(lines.begin() + i);
#####: 2443: t_values.erase(t_values.begin() + i);
#####: 2444: return_values.erase(return_values.begin() + i);
#####: 2445: i--;
-: 2446: }
-: 2447: }
-: 2448: }
#####: 2449: return std::vector<Tripoint>();
-: 2450:}
-: 2451:
#####: 2452:bool Map::senses(Point origin, Point target, int range, Sense_type sense)
-: 2453:{
-: 2454: return senses(origin.x, origin.y, posz, target.x, target.y, posz, range,
#####: 2455: sense);
-: 2456:}
-: 2457:
10484: 2458:bool Map::senses(Tripoint origin, Tripoint target, int range, Sense_type sense)
-: 2459:{
-: 2460: return senses(origin.x, origin.y, origin.z, target.x, target.y, target.z,
10484: 2461: range, sense);
-: 2462:}
-: 2463:
#####: 2464:std::vector<Tripoint> Map::line_of_sight(int x0, int y0, int x1, int y1)
-: 2465:{
#####: 2466: return line_of_sight(x0, y0, posz, x1, y1, posz);
-: 2467:}
-: 2468:
63525: 2469:std::vector<Tripoint> Map::line_of_sight(int x0, int y0, int z0,
-: 2470: int x1, int y1, int z1)
-: 2471:{
63525: 2472: std::vector<Tripoint> lines; // Process many lines at once.
63525: 2473: std::vector<std::vector<Tripoint> > return_values;
63525: 2474: std::vector<int> t_values; // T-values for Bresenham lines
-: 2475:
63525: 2476: int dx = x1 - x0, dy = y1 - y0, dz = z1 - z0;
63525: 2477: int ax = abs(dx) << 1, ay = abs(dy) << 1;
63525: 2478: int sx = (dx < 0 ? -1 : 1), sy = (dy < 0 ? -1 : 1);
63525: 2479: int dist = rl_dist(x0, y0, x1, y1);
-: 2480: int z_step;
63525: 2481: if (dist == 0) {
21: 2482: z_step = 0;
-: 2483: } else {
63504: 2484: z_step = (100 * dz) / dist;
-: 2485: }
63525: 2486: if (dx == 0) {
1155: 2487: sx = 0;
-: 2488: }
63525: 2489: if (dy == 0) {
1155: 2490: sy = 0;
-: 2491: }
-: 2492:
63525: 2493: int min_t = (ax > ay ? ay - ax : ax - ay),
63525: 2494: max_t = 0;
63525: 2495: if (dx == 0 || dy == 0) {
2289: 2496: min_t = 0;
-: 2497: }
-: 2498:// Init our "lines"
63525: 2499: std::vector<Tripoint> seed;
1227786: 2500: for (int t = min_t; t <= max_t; t++) {
1164261: 2501: lines.push_back( Tripoint(x0, y0, z0) );
1164261: 2502: return_values.push_back(seed);
1164261: 2503: t_values.push_back(t);
-: 2504: }
63525: 2505: int z_value = 50; // Each tile is 100 microunits tall, start halfway up
63525: 2506: int z_level = z0;
-: 2507:// Keep going as long as we've got at least one valid line
1226862: 2508: while (!lines.empty()) {
-: 2509:// Since we track z_value universally, don't do it inside the for loop below
1162848: 2510: bool z_stepped = false;
1162848: 2511: int old_z = z_level;
1162848: 2512: z_value += z_step;
1162848: 2513: if (z_value < 0) {
#####: 2514: z_level--;
#####: 2515: z_value += 100;
#####: 2516: z_stepped = true;
1162848: 2517: } else if (z_value >= 100) {
#####: 2518: z_level++;
#####: 2519: z_value -= 100;
#####: 2520: z_stepped = true;
-: 2521: }
23984191: 2522: for (int i = 0; i < lines.size(); i++) {
22884379: 2523: lines[i].z = z_level;
22884379: 2524: if (ax > ay) {
11433543: 2525: lines[i].x += sx;
11433543: 2526: if (t_values[i] >= 0) {
3989092: 2527: lines[i].y += sy;
3989092: 2528: t_values[i] -= ax;
-: 2529: }
11433543: 2530: t_values[i] += ay;
-: 2531: } else {
11450836: 2532: lines[i].y += sy;
11450836: 2533: if (t_values[i] >= 0) {
4014695: 2534: lines[i].x += sx;
4014695: 2535: t_values[i] -= ay;
-: 2536: }
11450836: 2537: t_values[i] += ax;
-: 2538: }
22884379: 2539: return_values[i].push_back(lines[i]);
-: 2540:// Don't need to check z, right?
22884379: 2541: if (lines[i].x == x1 && lines[i].y == y1) {
63036: 2542: return return_values[i];
-: 2543: }
22821343: 2544: if (blocks_sense(SENSE_SIGHT, lines[i], z_value) ||
-: 2545: (z_stepped &&
#####: 2546: blocks_sense(SENSE_SIGHT, lines[i].x, lines[i].y, old_z))) {
12020: 2547: lines.erase(lines.begin() + i);
12020: 2548: t_values.erase(t_values.begin() + i);
12020: 2549: return_values.erase(return_values.begin() + i);
12020: 2550: i--;
-: 2551: }
-: 2552: }
-: 2553: }
489: 2554: return std::vector<Tripoint>();
-: 2555:}
-: 2556:
#####: 2557:std::vector<Tripoint> Map::line_of_sight(Point origin, Point target)
-: 2558:{
#####: 2559: return line_of_sight(origin.x, origin.y, target.x, target.y);
-: 2560:}
-: 2561:
#####: 2562:std::vector<Tripoint> Map::line_of_sight(Tripoint origin, Tripoint target)
-: 2563:{
-: 2564: return line_of_sight(origin.x, origin.y, origin.z,
#####: 2565: target.x, target.y, target.z);
-: 2566:}
-: 2567:
21: 2568:void Map::draw(Window* w, Entity_pool *entities, Tripoint ref,
-: 2569: int range, Sense_type sense)
-: 2570:{
21: 2571: draw(w, entities, ref.x, ref.y, ref.z, range, sense);
21: 2572:}
-: 2573:
21: 2574:void Map::draw(Window* w, Entity_pool *entities, int refx, int refy, int refz,
-: 2575: int range, Sense_type sense)
-: 2576:{
21: 2577: if (!w) {
21: 2578: return;
-: 2579: }
21: 2580: int winx = w->sizex(), winy = w->sizey();
21: 2581: if (winy % 2 == 0) {
#####: 2582: winy--; // Only odd numbers are allowed!
-: 2583: }
21: 2584: int minx = refx - (winx / 2), maxx = refx + ( (winx - 1) / 2 );
21: 2585: int miny = refy - (winy / 2) - 1, maxy = refy + ( (winy - 1) / 2 );
-: 2586: draw_area(w, entities, refx, refy, refz, minx, miny, maxx, maxy, range,
21: 2587: sense);
-: 2588:}
-: 2589:
#####: 2590:void Map::draw_area(Window *w, Entity_pool *entities, Tripoint ref,
-: 2591: int minx, int miny, int maxx, int maxy,
-: 2592: int range, Sense_type sense)
-: 2593:{
-: 2594: draw_area(w, entities, ref.x, ref.y, ref.z, minx, miny, maxx, maxy, range,
#####: 2595: sense);
#####: 2596:}
-: 2597:
21: 2598:void Map::draw_area(Window *w, Entity_pool *entities,
-: 2599: int refx, int refy, int refz,
-: 2600: int minx, int miny, int maxx, int maxy,
-: 2601: int range, Sense_type sense)
-: 2602:{
21: 2603: if (!w) {
21: 2604: return;
-: 2605: }
-: 2606:
-: 2607:// Range defaults to -1; which means use light level
21: 2608: if (range == -1) {
#####: 2609: range = GAME.get_light_level();
-: 2610: }
-: 2611:
21: 2612: int winx = w->sizex(), winy = w->sizey();
21: 2613: int dist = winx > winy ? winx / 2 : winy / 2;
1176: 2614: for (int x = 0; x < winx; x++) {
64680: 2615: for (int y = 0; y < winy; y++) {
63525: 2616: int terx = refx + x - (winx / 2), tery = refy + y - (winy / 2);
63525: 2617: int z_used = posz;
127050: 2618: while (z_used > 0 && has_flag(TF_OPEN_SPACE, terx, tery, z_used)) {
#####: 2619: z_used--;
-: 2620: }
63525: 2621: int range_used = (dist < range ? dist : range);
63525: 2622: if (senses(refx, refy, refz, terx, tery, z_used, range_used, sense)) {
-: 2623:// If we're inbounds, draw normally...
63036: 2624: if (terx >= minx && terx <= maxx && tery >= miny && tery <= maxy) {
63036: 2625: draw_tile(w, entities, terx, tery, refx, refy, false);
-: 2626: } else { // Otherwise, that last "true" means "change colors to dkgray"
#####: 2627: draw_tile(w, entities, terx, tery, refx, refy, false, true);
-: 2628: }
-: 2629: } else {
-: 2630:// TODO: Don't use a literal glyph! TILES GEEZE
489: 2631: w->putglyph(x, y, glyph(' ', c_black, c_black));
-: 2632: }
-: 2633: }
-: 2634: }
-: 2635:}
-: 2636:
63036: 2637:void Map::draw_tile(Window* w, Entity_pool *entities, int tilex, int tiley,
-: 2638: int refx, int refy, bool invert, bool gray)
-: 2639:{
63036: 2640: draw_tile(w, entities, tilex, tiley, posz, refx, refy, invert, gray);
63036: 2641:}
-: 2642:
63036: 2643:void Map::draw_tile(Window* w, Entity_pool *entities,
-: 2644: int tilex, int tiley, int tilez,
-: 2645: int refx, int refy, bool invert, bool gray)
-: 2646:{
63036: 2647: if (!w) {
#####: 2648: return;
-: 2649: }
63036: 2650: int winx = w->sizex(), winy = w->sizey();
63036: 2651: int centerx = winx / 2, centery = winy / 2;
63036: 2652: int dx = tilex - refx, dy = tiley - refy;
63036: 2653: int tile_winx = centerx + dx, tile_winy = centery + dy;
63036: 2654: if (tile_winx < 0 || tile_winx >= winx || tile_winy < 0 || tile_winy >= winy){
#####: 2655: return; // It won't fit in the window!
-: 2656: }
-: 2657:// Now pick a glyph...
63036: 2658: glyph output;
63036: 2659: bool picked_glyph = false;
63036: 2660: int curz = tilez;
-: 2661:/* Start from the z-level that we're looking at. As long as there's no entity,
-: 2662: * and the terrain is open space, drop down a level.
-: 2663: */
189108: 2664: while (!picked_glyph && curz >= 0) {
63036: 2665: if (entities) {
63036: 2666: Entity* ent = entities->entity_at(tilex, tiley, curz);
63036: 2667: if (ent) {
21: 2668: output = ent->get_glyph();
21: 2669: picked_glyph = true;
-: 2670: }
-: 2671: }
63036: 2672: if (!picked_glyph) {
63015: 2673: Tile* tile = get_tile(tilex, tiley, curz);
63015: 2674: if (!tile->has_flag(TF_OPEN_SPACE)) {
63015: 2675: output = tile->top_glyph();
63015: 2676: picked_glyph = true;
-: 2677: }
-: 2678: }
63036: 2679: if (picked_glyph) {
63036: 2680: if (curz < tilez) {
#####: 2681: output = output.hilite();
-: 2682: }
-: 2683: } else {
#####: 2684: curz--;
-: 2685: }
-: 2686: }
63036: 2687: if (!picked_glyph) {
#####: 2688: int smx = tilex / SUBMAP_SIZE, smy = tiley / SUBMAP_SIZE;
#####: 2689: if (smx < 0 || smx >= MAP_SIZE || smy < 0 || smy >= MAP_SIZE) {
#####: 2690: debugmsg("Could not find a glyph - out of bounds!");
-: 2691: } else {
-: 2692:// Find the submap the tile's in...
#####: 2693: int smz = tilez - posz + VERTICAL_MAP_SIZE;
#####: 2694: Submap* sm = submaps[smx][smy][smz];
#####: 2695: while (!sm && smz > 0) {
#####: 2696: smz--;
#####: 2697: sm = submaps[smx][smy][smz];
-: 2698: }
#####: 2699: if (sm) {
-: 2700: debugmsg("Really could not find a glyph! %s",
#####: 2701: sm->get_spec_name().c_str());
-: 2702: } else {
#####: 2703: debugmsg("Really could not find a glyph - invalid submap!");
-: 2704: }
-: 2705: }
#####: 2706: return;
-: 2707: }
63036: 2708: if (invert) {
#####: 2709: output = output.invert();
-: 2710: }
63036: 2711: if (gray) {
#####: 2712: output.fg = c_dkgray;
-: 2713: }
63036: 2714: w->putglyph(tile_winx, tile_winy, output);
-: 2715:}
-: 2716:
-: 2717:
21: 2718:Submap* Map::get_center_submap()
-: 2719:{
21: 2720: return submaps[MAP_SIZE / 2][MAP_SIZE / 2][VERTICAL_MAP_SIZE];
-: 2721:}
-: 2722:
#####: 2723:Submap* Map::get_testing_submap()
-: 2724:{
#####: 2725: return submaps[MAP_SIZE / 2][MAP_SIZE / 2 - 1][VERTICAL_MAP_SIZE];
-: 2726:}
-: 2727:
-: 2728:
#####: 2729:Point Map::get_center_point()
-: 2730:{
#####: 2731: return Point(posx + MAP_SIZE / 2, posy + MAP_SIZE / 2);
-: 2732:}
-: 2733:
-: 2734:// TODO: Clean this up?
#####: 2735:Tripoint Map::find_item(Item* it, int uid)
-: 2736:{
-: 2737:// Sanity check
#####: 2738: if (it == NULL && uid < 0) {
#####: 2739: return Tripoint(-1, -1, -1);
-: 2740: }
#####: 2741: for (int x = 0; x < MAP_SIZE; x++) {
#####: 2742: for (int y = 0; y < MAP_SIZE; y++) {
#####: 2743: for (int z = 0; z < VERTICAL_MAP_SIZE * 2 + 1; z++) {
#####: 2744: Submap* sm = submaps[x][y][z];
#####: 2745: int rz = z - VERTICAL_MAP_SIZE + posz;
#####: 2746: if (sm) {
#####: 2747: for (int sx = 0; sx < SUBMAP_SIZE; sx++) {
#####: 2748: for (int sy = 0; sy < SUBMAP_SIZE; sy++) {
#####: 2749: int rx = x * SUBMAP_SIZE + sx;
#####: 2750: int ry = y * SUBMAP_SIZE + sy;
#####: 2751: std::vector<Item>* items = sm->items_at(sx, sy);
#####: 2752: if (!items) {
#####: 2753: debugmsg("NULL Items in Map::find_item_uid()");
-: 2754: }
#####: 2755: for (int i = 0; i < items->size(); i++) {
#####: 2756: if ( &( (*items)[i] ) == it || (*items)[i].get_uid() == uid ) {
#####: 2757: return Tripoint(rx, ry, rz);
-: 2758: }
-: 2759: }
-: 2760: }
-: 2761: }
-: 2762: }
-: 2763: }
-: 2764: }
-: 2765: }
-: 2766:// If we never found it... return nothing point
#####: 2767: return Tripoint(-1, -1, -1);
-: 2768:}
-: 2769:
#####: 2770:Tripoint Map::find_item_uid(int uid)
-: 2771:{
#####: 2772: return find_item(NULL, uid);
-: 2773:}
-: 2774:
#####: 2775:std::string Map::get_range_text()
-: 2776:{
#####: 2777: std::stringstream ret;
#####: 2778: Tripoint min(posx, posy, posz), max(posx + MAP_SIZE - 1, posy + MAP_SIZE - 1);
#####: 2779: ret << min.str() << " to " << max.str();
#####: 2780: return ret.str();
-: 2781:}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment