Created
July 31, 2014 12:23
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-: 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:} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-: 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