CombatGameInst* find_closest_hostile(GameState* gs, CombatGameInst* inst,
		const std::vector<CombatGameInst*>& candidates) {
	//Use a 'GameView' object to make use of its helper methods
	GameView view(0, 0, PATHING_RADIUS * 2, PATHING_RADIUS * 2, gs->width(),
			gs->height());

	TeamRelations& teams = gs->teams();
	float min_dist = HUGE_DISTANCE;
	CombatGameInst* closest_inst = NULL;

	for (int i = 0; i < candidates.size(); i++) {
		CombatGameInst* other = candidates[i];
		bool keep_chasing = false;
		if (other->id == inst->target()) {
			view.sharp_center_on(other->x, other->y);
			if (view.within_view(inst->bbox())) {
				keep_chasing = true;
			}

		}

		if (!keep_chasing && !inst_can_see(inst, candidates[i])) {
			continue;
		}
		if (!insts_are_hostile(teams, inst, candidates[i])) {
			continue;
		}
		float dist = inst_distance(inst, candidates[i]);
		if (dist < min_dist) {
			min_dist = dist;
			closest_inst = candidates[i];
		}
	}
	return closest_inst;
}
/* Provides the best (lower bound) estimate possible cheaply */
float estimate_inst_path_distance(CombatGameInst* inst1,
		CombatGameInst* inst2) {
	PlayerInst* p;
	if ((p = dynamic_cast<PlayerInst*>(inst1))) {
		return player_inst_path_distance(p, inst2);
	} else if ((p = dynamic_cast<PlayerInst*>(inst2))) {
		return player_inst_path_distance(p, inst1);
	} else {
		return inst_distance(inst1, inst2);
	}
}
void MonsterController::pre_step(GameState* gs) {
	perf_timer_begin(FUNCNAME);

	CollisionAvoidance& coll_avoid = gs->collision_avoidance();
	PlayerInst* local_player = gs->local_player();
	std::vector<EnemyOfInterest> eois;

	players = gs->players_in_level();

	//Update 'mids' to only hold live objects
	std::vector<obj_id> mids2;
	mids2.reserve(mids.size());
	mids.swap(mids2);

	for (int i = 0; i < mids2.size(); i++) {
		EnemyInst* e = (EnemyInst*)gs->get_instance(mids2[i]);
		if (e == NULL)
			continue;
		EnemyBehaviour& eb = e->behaviour();
		eb.step();

		//Add live instances back to monster id list
		mids.push_back(mids2[i]);

		int closest_player_index = find_player_to_target(gs, e);

		if (eb.current_action == EnemyBehaviour::INACTIVE
				&& e->cooldowns().is_hurting()) {
			eb.current_action = EnemyBehaviour::CHASING_PLAYER;
		}
		if (closest_player_index == -1
				&& eb.current_action == EnemyBehaviour::CHASING_PLAYER) {
			eb.current_action = EnemyBehaviour::INACTIVE;
			e->target() = NONE;
		}

		if (eb.current_action == EnemyBehaviour::CHASING_PLAYER)
			eois.push_back(
					EnemyOfInterest(e, closest_player_index,
							inst_distance(e, players[closest_player_index])));
		else if (eb.current_action == EnemyBehaviour::INACTIVE)
			monster_wandering(gs, e);
		else
			//if (eb.current_action == EnemyBehaviour::FOLLOWING_PATH)
			monster_follow_path(gs, e);
	}

	set_monster_headings(gs, eois);

	//Update player positions for collision avoidance simulator
	for (int i = 0; i < players.size(); i++) {
		PlayerInst* p = players[i];
		coll_avoid.set_position(p->collision_simulation_id(), p->x, p->y);
	}

	for (int i = 0; i < mids.size(); i++) {
		EnemyInst* e = (EnemyInst*)gs->get_instance(mids[i]);
		lua_State* L = gs->luastate();
		lua_gameinst_callback(L, e->etype().step_event.get(L), e);
		update_velocity(gs, e);
		simul_id simid = e->collision_simulation_id();
		coll_avoid.set_position(simid, e->rx, e->ry);
		coll_avoid.set_preferred_velocity(simid, e->vx, e->vy);
	}

	coll_avoid.step();

	for (int i = 0; i < mids.size(); i++) {
		EnemyInst* e = (EnemyInst*)gs->get_instance(mids[i]);
		update_position(gs, e);
	}

	perf_timer_end(FUNCNAME);
}