示例#1
0
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;
		}
	}
	*/
}