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); }