int Shop::nearShop(const Coordinate& where) { int y0 = where.row() - 2; int x0 = where.col() - 2; int rank = 3; if (where.level() == _tentative_shop_door.level()) rank = 1 + Point::gridDistance(where, _tentative_shop_door); for (int y = y0; y <= y0 + 4; ++y) { for (int x = x0; x <= x0 + 4; ++x) { if (World::level().tile(Point(y,x)).symbol() == SHOP_TILE) rank = min(rank, Point::gridDistance(Point(y,x), where)); } } return rank; }
void Level::updateMonsters() { /* remove monsters that seems to be gone * and make monsters we can't see !visible */ if (World::internalTurn() != _farlooked_turn) _turn_farlooks.clear(); for (set<Point>::iterator pi = _monster_points.begin(); pi != _monster_points.end(); ++pi) { Point point = *pi; unsigned char symbol = World::view(point); int color = World::color(point); /* add a monster, or update position of an existing monster */ unsigned char msymbol; if ((color >= INVERSE_BLACK && color <= INVERSE_WHITE) || (color >= INVERSE_BOLD_BLACK && color <= INVERSE_BOLD_WHITE)) msymbol = PET; else msymbol = symbol; bool shopkeeper = false, priest = false; const data::Monster* data = 0; int attitude = ATTITUDE_UNKNOWN; std::string name; parseFarlook(point, shopkeeper, priest, attitude, name, data); bool fixed_name = data && (shopkeeper || (data->genoFlags() & G_UNIQ) != 0); Monster* nearest = 0; // note: in the event of a named non-unique monster that is not indexed under that name, it // will be created with a new name and then renamed, hopefully avoiding crashes when there are five Rexes in bones // but there will be issues if the bonemaker guessed an in-use identifier if (!name.empty() && Monster::byID().find(name) != Monster::byID().end()) { //Debug::notice() << "name of existing monster found" << endl; nearest = Monster::byID()[name]; nearest->called(true); } else if (!fixed_name) { /* find nearest monster */ int min_distance = INT_MAX; // we only care about recently seen monsters here for (map<int, Monster*>::iterator m = Monster::byLastSeen().lower_bound(World::internalTurn() - MAX_MONSTER_MOVE); m != Monster::byLastSeen().end(); ++m) { if (m->second->symbol() != msymbol || m->second->color() != color) continue; // not the same monster if ((m->second->lastSeen() == (int)World::internalTurn()) && (Point(m->second->lastSeenPos()) != point)) continue; // already accounted for if (m->second->called()) continue; // would be obvious if (m->second->lastSeenPos().level() != _level) continue; // not interested /* see if this monster is closer than the last found monster */ int distance = Point::gridDistance(m->second->lastSeenPos(), point); if (distance > MAX_MONSTER_MOVE) continue; // too far away from where we last saw it, probably new monster else if (distance >= min_distance) continue; else if ((m->second->priest() || m->second->shopkeeper()) && distance > 1) continue; // shopkeepers and priests are very close to eachother in minetown /* it is */ min_distance = distance; nearest = m->second; } } if (nearest != 0) { //Debug::notice() << "for " << point << ", using existing monster " << nearest->id() << endl; } else { /* add monster */ string id; if (fixed_name) { id = name; } nearest = new Monster(id); nearest->called(!id.empty()); Debug::notice() << "for " << point << ", using new monster " << nearest->id() << endl; } nearest->symbol(msymbol); nearest->color(color); nearest->attitude(attitude); nearest->shopkeeper(shopkeeper); nearest->priest(priest); nearest->data(data); nearest->observed(Coordinate(_level, point)); } for (map<Point, Monster*>::iterator m = _monsters.begin(); m != _monsters.end(); ++m) _map[m->first.row()][m->first.col()].monster(ILLEGAL_MONSTER); _monsters.clear(); /* set monsters on tiles */ for (map<int, Monster*>::iterator m = Monster::byLastSeen().lower_bound(World::internalTurn() - MAX_MONSTER_MOVE); m != Monster::byLastSeen().end(); ++m) { Coordinate c = m->second->lastSeenPos(); if (c.level() != _level) continue; // not interested m->second->visible(m->second->lastSeen() == (int)World::internalTurn()); if (!m->second->visible() && Point::gridDistance(c, Saiph::position()) <= 1) continue; // obviously not here //Debug::notice() << "Marking " << m->second->id() << " tactically interesting at " << c << endl; _map[c.row()][c.col()].monster(m->second->symbol()); _monsters[c] = m->second; } /* for (int y = MAP_ROW_BEGIN; y <= MAP_ROW_END; ++y) { for (int x = MAP_COL_BEGIN; x <= MAP_COL_END; ++x) { Point p(y,x); if (_monster_points.find(p) != _monster_points.end()) Debug::info() << "_monster_points contains " << p << endl; if (_monsters.find(p) != _monsters.end()) Debug::info() << "_monsters contains " << p << endl; if (_map[y][x].monster() != ILLEGAL_MONSTER) Debug::info() << "_map has non-illegal at " << p << endl; if (_turn_farlooks.find(p) != _turn_farlooks.end()) Debug::info() << "_turn_farlooks contains " << p << endl; } } */ }