creature_t* creature_t::get_closest_enemy() const { int x = pos.x; int y = pos.y; creature_t* closest_enemy = nullptr; int smallest_distance = INT_MAX; for (size_t i = 0; i < current_dungeon->creatures.size(); i++) { creature_t* possible_enemy = current_dungeon->creatures.at(i); int cx = possible_enemy->pos.x; int cy = possible_enemy->pos.y; int dist = (x - cx) * (x - cx) + (y - cy) * (y - cy); if (( possible_enemy->is_friendly() && !is_ally() ) || (!possible_enemy->is_friendly() && ((identity == IDENT_PLAYER) || is_ally()))) { if (dist < smallest_distance) { closest_enemy = possible_enemy; smallest_distance = dist; } } } return closest_enemy; }
void world::spawn_bullet(const char *type, const vec3 &pos, const vec3 &dir, const plane_ptr &owner) { vec3 r; const bool hit_world = m_phys_world.spawn_bullet(type, pos, dir, r); if (!owner->net || owner->net->source) { for (auto &p: m_planes) { if (p->hp <= 0 || is_ally(owner, p)) continue; if (line_sphere_intersect(pos, r, p->get_pos(), p->hit_radius)) { p->take_damage(60, *this); const bool destroyed = p->hp <= 0; if (destroyed) on_kill(owner, p); if (owner == get_player()) popup_hit(destroyed); } } } if (hit_world) { //ToDo: spark } }
void creature_t::try_move(int move_x, int move_y) { tile_t* tile = get_tile_at(current_dungeon, move_x, move_y); if (tile && (tile_is_walkable_by(*tile, this))) { creature_t* thing = get_creature_at(current_dungeon, move_x, move_y); if (thing) { if (get_active_effects_for(this) & EF_CONFUSE) { creature_attacks(this, thing); } else if ((is_ally() && !thing->is_ally()) || (!is_ally() && thing->is_ally())) { // The two creatures are enemies. creature_attacks(this, thing); } } else if (player.pos.x == move_x && player.pos.y == move_y) { if (!is_friendly() || (get_active_effects_for(this) & EF_CONFUSE)) { // Not ally with player, or confused. creature_attacks(this, &player); } } else { pos.x = move_x; pos.y = move_y; } } else if (tile && tile->id == TILE_DOOR_CLOSED) { if (flag & CF_INTELLIGENT) { open_door(current_dungeon, this, move_x, move_y); //creature->pos.x = move_x; //creature->pos.y = move_y; } } }
void team_deathmatch::on_kill(const object_ptr &k, const object_ptr &v) { auto vp = m_world.get_plane(v); if (!vp) return; auto kp = m_world.get_plane(k); if (kp) { if (!is_ally(kp, vp)) kp->net_game_data.set("score", kp->net_game_data.get<int>("score") + 1); } else vp->net_game_data.set("score", vp->net_game_data.get<int>("score") - 1); }
bool GarrisonAbility::can_invoke(Unit &to_modify, const Command &cmd) { if (!cmd.has_unit()) { return false; } Unit &target = *cmd.unit(); // make sure buildings are completed if (target.has_attribute(attr_type::building)) { auto &build_attr = target.get_attribute<attr_type::building>(); if (build_attr.completed < 1.0f) { return false; } } return to_modify.location && target.has_attribute(attr_type::garrison) && is_ally(to_modify, target); }
void unit_vehicle::update(int dt, world &w) { if (hp <= 0) return; if (m_first_update) { m_first_update = false; if (!m_follow.expired()) { auto f = m_follow.lock(); vec3 diff = get_pos() - f->get_pos(); if (diff.length() < m_params.formation_radius) m_formation_offset = f->get_rot().rotate_inv(diff); else m_formation_offset.set(0, 0, -15.0f); } m_ground = (get_pos().y - w.get_height(get_pos().x, get_pos().z)) < 5.0f; if (m_ground) { //ToDo: gear anim } else { if (m_params.speed_min > 0.01f) m_vel = get_rot().rotate(vec3::forward() * m_params.speed_cruise); m_dpos = vec3(); } return; } float kdt = dt * 0.001f; vec3 target_dir; bool has_target = false; if (m_target.expired()) { if (m_ai > ai_default && m_target_search != search_none) { const bool air = m_ai == ai_air_to_air || m_ai == ai_air_multirole, ground = m_ai == ai_air_to_ground || m_ai == ai_air_multirole; float min_dist = 10000.0f; for (int i = 0; i < w.get_planes_count() + w.get_units_count(); ++i) { object_ptr t; if (i < w.get_planes_count()) { auto p = w.get_plane(i); if (is_ally(p, w)) continue; t = p; } else { if (m_target_search == search_player) continue; auto u = w.get_unit(i - w.get_planes_count()); if (is_ally(u)) continue; t = u; } if (!t->is_targetable(air, ground)) continue; const float dist = (t->get_pos() - get_pos()).length(); if(dist >= min_dist) continue; m_target = t; min_dist = dist; } } } else { if (m_target.lock()->hp <= 0) m_target.reset(); } bool not_path_not_follow = false; if (!m_path.empty()) { has_target = true; target_dir = m_path.front() - get_pos(); if (target_dir.length() < m_vel.length() * kdt * m_params.target_radius) { if (m_path_loop) m_path.push_back(m_path.front()); m_path.pop_front(); if (m_path.empty()) has_target = false; else target_dir = m_path.front() - get_pos(); } } else if (!m_follow.expired()) { has_target = true; auto f = m_follow.lock(); target_dir = f->get_pos() + f->get_rot().rotate(m_formation_offset) - (get_pos() + get_vel() * kdt); //+ f->get_vel() * kdt //player's plane is already updated, ToDo } else not_path_not_follow = true; if (!m_target.expired()) { auto t = m_target.lock(); const auto dir = t->get_pos() + t->get_rot().rotate(vec3(0, 0, -20.0)) - (get_pos() + get_vel() * kdt); if (not_path_not_follow) { target_dir = dir; has_target = true; } for (auto &wp: m_weapons) { if (wp.cooldown > 0) { wp.cooldown -= dt; continue; } if (dir.length() > wp.params.lockon_range) continue; wp.cooldown = wp.params.reload_time; auto m = w.add_missile(wp.params.id.c_str(), wp.mdl); if (!m) continue; m->phys->pos = get_pos(); m->phys->rot = get_rot(); m->phys->vel = get_vel(); m->phys->target_dir = dir; m->target = m_target; } } if (has_target) { const float eps=1.0e-6f; const float target_dist = target_dir.length(); const vec3 v=target_dir / target_dist; const float xz_sqdist=v.x*v.x+v.z*v.z; const auto rot = get_rot(); const auto pyr = rot.get_euler(); const nya_math::angle_rad new_yaw=(xz_sqdist>eps*eps)? (atan2(v.x,v.z)) : pyr.y; nya_math::angle_rad new_pitch=(fabsf(v.y)>eps)? (-atan2(v.y,sqrtf(xz_sqdist))) : 0.0f; nya_math::angle_rad new_roll; if (!m_follow.expired()) new_roll = m_follow.lock()->get_rot().get_euler().z; vec3 pos = get_pos() + m_vel * kdt; const float h = w.get_height(pos.x, pos.z); if ((new_pitch > 0.0f && pos.y <= h + m_params.height_min) || (new_pitch < 0.0f && pos.y >= h + m_params.height_max)) new_pitch = 0.0f; const auto ideal_rot = quat(new_pitch, new_yaw, new_roll); const float angle_diff = rot.rotate(vec3::forward()).angle(target_dir).get_deg(); if (fabsf(angle_diff) > 0.001f) { const float turn_k = nya_math::clamp((180.0f / angle_diff) * m_params.turn_speed * kdt, 0.0, 1.0); m_render->mdl.set_rot(quat::slerp(rot, ideal_rot, turn_k)); } float speed = m_vel.length(); float want_speed = target_dist / kdt; if (!m_follow.expired()) { const float target_speed = m_follow.lock()->get_vel().length(); float decel_time = (speed - target_speed) / m_params.decel; if (target_dist / (speed + m_params.accel * kdt) < decel_time) want_speed = target_speed; } want_speed = nya_math::clamp(want_speed, m_params.speed_min, std::min(m_params.speed_max, m_speed_limit)); speed = tend(speed, want_speed, m_params.accel * kdt, m_params.decel * kdt); m_vel = get_rot().rotate(vec3(0.0, 0.0, speed)); } else if (m_params.speed_min < 0.01f) { float speed = m_vel.length(); if (speed > 0.0f) { speed = tend(speed, 0.0f, m_params.accel * kdt, m_params.decel * kdt); m_vel = get_rot().rotate(vec3(0.0, 0.0, speed)); } } vec3 pos = get_pos() + m_vel * kdt; const float h = w.get_height(pos.x, pos.z); pos.y = nya_math::clamp(pos.y, h + m_params.height_min, h + m_params.height_max); //ToDo set_pos(pos); }
void FightEvent::run() { // store all the fighters except the users std::vector<Fighter*> all_fighters; for (int i = 0; i < static_cast<int>(allies.size()); ++i) all_fighters.push_back(allies.at(i)); for (int i = 0; i < static_cast<int>(enemies.size()); ++i) all_fighters.push_back(enemies.at(i)); // sort from fastest to slowest std::sort(all_fighters.begin(), all_fighters.end(), comp_speed); // find the correct index to insert the user's ship int i = 0; for (; i < static_cast<int>(all_fighters.size()) && all_fighters.at(i)->get_base_speed() > get_modified_speed(); ++i); if (i == static_cast<int>(all_fighters.size())) all_fighters.push_back(player->get_ship()); else all_fighters.insert(all_fighters.begin() + i, player->get_ship()); int round = 1; // fight until user's ship destroyed or no more enemies left while (get_modified_health() > 0 && enemies.size() > 0) { usleep(3000000); utilities::clear_display(); std::cout << "\n==== Fight Round " << round << " ====\n\n"; // let each fighter have a chance to fight for (int j = 0; j < static_cast<int>(all_fighters.size()) && get_modified_health() > 0 && enemies.size() > 0; ++j) { Fighter* cur_fighter = all_fighters.at(j); // fighter is dead if (!is_ally(cur_fighter) && !is_enemy(cur_fighter)) { all_fighters.erase(all_fighters.begin() + j); delete cur_fighter; cur_fighter = NULL; // adjust index based on the removed fighter j--; } // fighter is still alive and can attack else { int area_wide_attk = 0; int reg_attk = 0; // user gets to attack if (cur_fighter == player->get_ship()) { // only one of these can be non-zero area_wide_attk = cur_fighter->is_area_wide() ? get_modified_attack() : 0; reg_attk = cur_fighter->is_area_wide() ? 0 : get_modified_attack(); // do attack affecting all enemies if (area_wide_attk > 0) attack_area(cur_fighter, PLAYER, area_wide_attk, enemies); // do attack targeting a single enemy else if (reg_attk > 0) { // attack a random enemy int who_attacked = rand() % enemies.size(); Fighter *attacked = enemies.at(who_attacked); attack_one(cur_fighter, PLAYER, reg_attk, attacked, enemies, who_attacked); } } // ally is attacking the enemies else if (is_ally(cur_fighter)) { // only one of these can be non-zero area_wide_attk = cur_fighter->attack_enemies(); reg_attk = cur_fighter->attack_enemy(); // do attack affecting all enemies if (area_wide_attk > 0) attack_area(cur_fighter, AL, area_wide_attk, enemies); // do attack targeting a single enemy else if (reg_attk > 0) { // attack a random enemy int who_attacked = rand() % enemies.size(); Fighter *attacked = enemies.at(who_attacked); attack_one(cur_fighter, AL, reg_attk, attacked, enemies, who_attacked); } } // enemy is attacking you and your allies else { // only one of these can be non-zero area_wide_attk = cur_fighter->attack_enemies(); reg_attk = cur_fighter->attack_enemy(); // do attack affecting all allies and user if (area_wide_attk > 0) attack_area(cur_fighter, EN, area_wide_attk, allies); // do attack targeting a single ally or the user else if (reg_attk > 0) { // attack a random ally int who_attacked = 0; if (allies.size() > 0) who_attacked = rand() % allies.size() + 1; // user's ship was attacked if (who_attacked == static_cast<int>(allies.size())) { const int IGNORE = -1; attack_one(cur_fighter, EN, reg_attk, player->get_ship(), allies, IGNORE); } // ally's ship was attacked else { Fighter *attacked = allies.at(who_attacked); attack_one(cur_fighter, EN, reg_attk, attacked, allies, who_attacked); } } } } } // next fight round ++round; } std::cout << std::endl; // clean up all the pointers of ships that weren't defeated for (int m = 0; m < static_cast<int>(all_fighters.size()); ++m) { Fighter *cur = all_fighters.at(m); if (cur != player->get_ship()) { delete cur; cur = NULL; } } if (get_modified_health() > 0) { std::cout << "You managed to survive with " << get_modified_health() << " health!\n\n"; int winnings = rand() % 400 + 1; std::cout << "You came up on " << winnings << " ducats!\n\n"; player->gain_money(winnings); player->won_battle(); } else { std::cout << "Darn! You died. Game over!\n\n"; player->died(); } }