#include "precompile.h" #include #include "android_new.ai.h" #include "android.h" #include "room.h" #include "metamgr.h" #include "player.h" const int SHUA_RANGE = 580; /* 目标:ai可切换,降级/升级(根据系统当前负载) ai级别 1: 木桩(不射击) 2: 站桩间隔开枪 3: 站桩描边射击 4: 站桩扫射(连续射击) 5: 跑动间隔开枪 6: 跑动描边射击 7: 跑动扫射 8: 跑动射击 */ AndroidNewAI::~AndroidNewAI() { } void AndroidNewAI::Update(int delta_time) { old_ai_data_.state_elapsed_time += delta_time; Human* hum = (Human*)owner; if (hum->poisoning) { hum->poisoning_time += delta_time; } if (hum->poisoning) { hum->UpdatePoisoning(); } if (hum->dead) { return; } #if 1 { if (a8::HasBitFlag(hum->status, HS_NewBieGuideAndroid)) { UpdateNewBieNpc(); return; } if (a8::HasBitFlag(hum->status, HS_LastAndroid)) { UpdateLastNpc(); return; } if ((hum->room->GetRoomType() == RT_NewBrid || hum->room->GetRoomType() == RT_MidBrid) && hum->room->GetGasData().gas_mode != GasInactive && hum->team_uuid.empty() ) { UpdateNewBieRoomLogic(); return; } } #endif if (hum->room->GetGasData().gas_mode == GasInactive) { DefaultAi(); return; } UpdateNewAI(); } void AndroidNewAI::DefaultAi() { Human* hum = (Human*)owner; switch (old_ai_data_.state) { case AS_thinking: { if (old_ai_data_.state_elapsed_time > 1500 + rand() % 3000) { int rnd = rand(); if (rnd % 100 < 30) { ChangeToStateOldAI(AS_moving); } else if (rnd % 100 < 50) { ChangeToStateOldAI(AS_attack); } } } break; case AS_moving: { if (old_ai_data_.state_elapsed_time < 1000 + rand() % 2000) { DoMoveOldAI(); } else { int rnd = rand(); if (rnd % 100 < 30) { ChangeToStateOldAI(AS_thinking); } else if (rnd % 100 < 50) { ChangeToStateOldAI(AS_attack); } } } break; case AS_attack: { if ((old_ai_data_.state_elapsed_time < 3000 && old_ai_data_.last_target) || (old_ai_data_.state_elapsed_time < 1100)) { DoAttackOldAI(); } else { int rnd = rand(); if (rnd % 100 < 30) { ChangeToStateOldAI(AS_moving); } else if (rnd % 100 < 50) { ChangeToStateOldAI(AS_thinking); } } } break; } } void AndroidNewAI::ChangeToStateOldAI(AndroidState_e to_state) { old_ai_data_.state = to_state; old_ai_data_.state_elapsed_time = 0; switch (old_ai_data_.state) { case AS_moving: { Human* hum = (Human*)owner; hum->move_dir = a8::Vec2(1.0f, 0); hum->move_dir.Rotate(a8::RandAngle()); hum->move_dir.Normalize(); hum->attack_dir = hum->move_dir; } break; default: break; } } void AndroidNewAI::DoMoveOldAI() { Human* hum = (Human*)owner; if (hum->room->IsWaitingStart()) { return; } if (owner->UpdatedTimes() % 2 == 0) { Human* hum = (Human*)owner; int speed = std::max(1, (int)hum->GetSpeed()); if (a8::HasBitFlag(hum->status, HS_NewBieGuideAndroid) && hum->room->GetFrameNo() - hum->enable_frameno < SERVER_FRAME_RATE * 8) { hum->move_dir = hum->room->GetFirstNewBie()->GetPos() - hum->GetPos(); hum->move_dir.Normalize(); } for (int i = 0; i < speed; ++i) { a8::Vec2 old_pos = hum->GetPos(); hum->SetPos(hum->GetPos() + hum->move_dir); if (hum->IsCollisionInMapService()) { hum->SetPos(old_pos); if (i == 0) { hum->FindPathInMapService(); } break; } hum->room->grid_service->MoveHuman(hum); } } } void AndroidNewAI::DoAttackOldAI() { Human* hum = (Human*)owner; if (hum->room->IsWaitingStart()) { return; } if (hum->room->GetGasData().gas_mode == GasInactive) { return; } if (owner->UpdatedTimes() % 10 == 0) { Human* enemy = owner->room->FindEnemy((Human*)owner); if (enemy) { Human* sender = (Human*)owner; a8::Vec2 shot_dir = enemy->GetPos() - sender->GetPos(); if (std::abs(shot_dir.x) > FLT_EPSILON || std::abs(shot_dir.y) > FLT_EPSILON) { shot_dir.Normalize(); shot_dir.Rotate((rand() % 10) / 180.0f); sender->attack_dir = shot_dir; sender->Shot(shot_dir); } } old_ai_data_.last_target = enemy; } } void AndroidNewAI::UpdateNewBieNpc() { Human* hum = (Human*)owner; if (hum->room->GetFrameNo() - hum->enable_frameno < 2) { if (hum->GetPos().ManhattanDistance(hum->room->GetFirstNewBie()->GetPos()) > 100) { hum->move_dir = hum->room->GetFirstNewBie()->GetPos() - hum->GetPos(); hum->move_dir.Normalize(); } hum->attack_dir = hum->move_dir; if (hum->curr_weapon->weapon_idx != 0) { hum->curr_weapon->ammo = MetaMgr::Instance()->newbie_first_robot_ammo; } } else if (hum->room->GetFrameNo() - hum->enable_frameno < SERVER_FRAME_RATE * 1.5) { int speed = std::max(1, (int)hum->GetSpeed()); for (int i = 0; i < speed; ++i) { hum->SetPos(hum->GetPos() + hum->move_dir); hum->room->grid_service->MoveHuman(hum); } } else if (hum->room->GetFrameNo() - hum->enable_frameno < SERVER_FRAME_RATE * 3) { Human* enemy = hum->room->GetFirstNewBie(); Human* sender = hum; a8::Vec2 shot_dir = enemy->GetPos() - sender->GetPos(); if (std::abs(shot_dir.x) > FLT_EPSILON || std::abs(shot_dir.y) > FLT_EPSILON) { shot_dir.Normalize(); shot_dir.Rotate((rand() % 10) / 180.0f); sender->attack_dir = shot_dir; sender->Shot(shot_dir); } } else { a8::UnSetBitFlag(hum->status, HS_NewBieGuideAndroid); } } void AndroidNewAI::UpdateLastNpc() { Human* hum = (Human*)owner; if (hum->room->GetFrameNo() - hum->enable_frameno < 2) { if (hum->GetPos().ManhattanDistance(hum->last_human_target->GetPos()) > 100) { hum->move_dir = hum->last_human_target->GetPos() - hum->GetPos(); hum->move_dir.Normalize(); } hum->attack_dir = hum->move_dir; if (hum->curr_weapon->weapon_idx != 0) { hum->curr_weapon->ammo = MetaMgr::Instance()->newbie_first_robot_ammo * 2; } } else if (hum->room->GetFrameNo() - hum->enable_frameno < SERVER_FRAME_RATE * 1.5) { int speed = std::max(1, (int)hum->GetSpeed()); for (int i = 0; i < speed; ++i) { a8::Vec2 old_pos = hum->GetPos(); hum->SetPos(hum->GetPos() + hum->move_dir); if (!hum->room->OverBorder(hum->GetPos(), hum->meta->i->radius())) { hum->room->grid_service->MoveHuman(hum); } else { hum->SetPos(old_pos); break; } } } else if (hum->room->GetFrameNo() - hum->enable_frameno < SERVER_FRAME_RATE * 3) { Human* enemy = hum->last_human_target; Human* sender = hum; a8::Vec2 shot_dir = enemy->GetPos() - sender->GetPos(); if (std::abs(shot_dir.x) > FLT_EPSILON || std::abs(shot_dir.y) > FLT_EPSILON) { shot_dir.Normalize(); shot_dir.Rotate((rand() % 10) / 180.0f); sender->attack_dir = shot_dir; sender->Shot(shot_dir); } } else { a8::UnSetBitFlag(hum->status, HS_LastAndroid); } } void AndroidNewAI::UpdateNewBieRoomLogic() { Human* hum = (Human*)owner; Human* old_last_target = old_ai_data_.last_target; Human* target = old_ai_data_.last_target; if ((old_ai_data_.last_target && old_ai_data_.last_target->real_dead) || !old_ai_data_.last_target) { if (hum->last_human_target && !hum->last_human_target->dead) { target = hum->last_human_target; } else { if (rand() % 100 < 70) { hum->room->TouchPlayerList ( a8::XParams(), [hum, &target] (Player* player, a8::XParams& param) { if (!player->dead && hum->team_id != player->team_id) { if (!target) { target = player; } else { if (hum->GetPos().ManhattanDistance(player->GetPos()) < hum->GetPos().ManhattanDistance(target->GetPos())) { target = player; } } } }); } else { hum->room->TouchHumanList ( a8::XParams(), [hum, &target] (Human* huma, a8::XParams& param) { if (!huma->dead && huma->IsAndroid() && hum->team_id != huma->team_id && !a8::HasBitFlag(huma->status, HS_Disable)) { if (!target) { target = huma; } else { if (hum->GetPos().ManhattanDistance(huma->GetPos()) < hum->GetPos().ManhattanDistance(target->GetPos())) { target = huma; } } } return true; }); } } old_ai_data_.last_target = target; } if (!target) { return; } if (target->IsPlayer()) { if (hum->room->AliveCount() < 15) { if (hum->GetPos().ManhattanDistance(target->GetPos()) > 1000) { a8::Vec2 pos = target->GetPos(); a8::Vec2 dir = target->move_dir; dir = a8::Vec2::UP; if (rand() % 100 < 1) { dir.Rotate(a8::RandAngle() / 2.0f); } else { dir.Rotate(a8::RandAngle()); } pos = pos + dir * SHUA_RANGE; if (hum->room->OverBorder(pos, hum->GetRadius())) { pos.x = target->GetPos().x; if (hum->room->OverBorder(pos, hum->GetRadius())) { pos = target->GetPos(); } } hum->SetPos(pos); hum->room->grid_service->MoveHuman(hum); hum->FindLocation(); hum->RefreshView(); } } } if (hum->GetPos().ManhattanDistance(target->GetPos()) > 180) { if (hum->GetPos().ManhattanDistance(target->GetPos()) > 650 && hum->room->GetFrameNo() - old_ai_data_.last_findenemy_frameno > SERVER_FRAME_RATE * 3) { old_ai_data_.last_findenemy_frameno = hum->room->GetFrameNo(); old_ai_data_.last_target = nullptr; } else { int speed = std::max(1, (int)hum->GetSpeed()); hum->move_dir = target->GetPos() - hum->GetPos(); hum->move_dir.Normalize(); hum->attack_dir = hum->move_dir; speed *= 0.7; for (int i = 0; i < speed; ++i) { hum->SetPos(hum->GetPos() + hum->move_dir); hum->room->grid_service->MoveHuman(hum); } } } else { if (hum->room->GetFrameNo() - old_ai_data_.last_attack_frameno > SERVER_FRAME_RATE + (rand() % 15)) { old_ai_data_.last_attack_frameno = hum->room->GetFrameNo(); Human* sender = (Human*)owner; a8::Vec2 shot_dir = target->GetPos() - sender->GetPos(); if (std::abs(shot_dir.x) > FLT_EPSILON || std::abs(shot_dir.y) > FLT_EPSILON) { shot_dir.Normalize(); shot_dir.Rotate((rand() % 10) / 180.0f); sender->attack_dir = shot_dir; sender->Shot(shot_dir); } } if (old_last_target && old_ai_data_.last_target && old_last_target == old_ai_data_.last_target) { ++old_ai_data_.series_attack_frames; } else { old_ai_data_.series_attack_frames = 0; } if (old_ai_data_.series_attack_frames > SERVER_FRAME_RATE * 10 && old_ai_data_.last_target && old_ai_data_.last_target->IsAndroid()) { old_ai_data_.last_target = nullptr; } } } void AndroidNewAI::UpdateNewAI() { Human* hum = (Human*)owner; ++node_.exec_frame_num; hum->shot_hold = false; switch (node_.main_state) { case ASE_Idle: { UpdateIdle(); } break; case ASE_Thinking: { UpdateThinking(); } break; case ASE_Attack: { UpdateAttack(); } break; case ASE_RandomWalk: { UpdateRandomWalk(); } break; } if (moving_) { DoMoveNewAI(); } } void AndroidNewAI::UpdateIdle() { Human* hum = (Human*)owner; if (hum->room->GetFrameNo() > node_.frameno + node_.param1) { ChangeToStateNewAI(ASE_Thinking); } } void AndroidNewAI::UpdateThinking() { Human* hum = (Human*)owner; if (hum->room->GetGasData().gas_mode == GasInactive || hum->room->IsWaitingStart()) { if (hum->room->IsWaitingStart()) { ChangeToStateNewAI(ASE_Idle); } else { ChangeToStateNewAI(ASE_RandomWalk); } } else { std::array targets = {}; ScanTarget(targets); Human* target = GetTarget(targets, target_range); if (target) { node.target = target; ChangeToStateNewAI(ASE_Attack); } else { if ((rand() % 7) < 4) { ChangeToStateNewAI(ASE_Idle); } else { ChangeToStateNewAI(ASE_RandomWalk); } } } } void AndroidNewAI::UpdateAttack() { } void AndroidNewAI::UpdateRandomWalk() { } void AndroidNewAI::DoMoveNewAI() { Human* hum = (Human*)owner; if (hum->UpdatedTimes() % 2 == 0) { if (std::abs(hum->move_dir.x) > FLT_EPSILON || std::abs(hum->move_dir.y) > FLT_EPSILON) { int speed = std::max(1, (int)hum->GetSpeed()); for (int i = 0; i < speed; ++i) { a8::Vec2 old_pos = hum->GetPos(); hum->SetPos(hum->GetPos() + hum->move_dir); if (hum->IsCollisionInMapService()) { hum->SetPos(old_pos); if (i == 0) { hum->FindPathInMapService(); } break; } hum->room->grid_service->MoveHuman(hum); } } } } void AndroidNewAI::ChangeToStateNewAI(AndroidStateEx_e to_state) { Human* hum = (Human*)owner; switch (to_state) { case ASE_Idle: { node_.param1 = 0; moving_ = false; if (hum->room->GetGasData().gas_mode == GasInactive || hum->room->IsWaitingStart()) { node_.param1 = rand() % (3 * SERVER_FRAME_RATE); } else { node_.param1 = rand() % (2 * SERVER_FRAME_RATE); } } break; case ASE_Thinking: { node_.param1 = 0; moving_ = false; } break; case ASE_Attack: { node_.param1 = 0; moving_ = false; node_.shot_times = 0; } break; case ASE_RandomWalk: { moving_ = true; node_.param1 = SERVER_FRAME_RATE * 2 + rand() % (SERVER_FRAME_RATE * 3); hum->move_dir = a8::Vec2(1.0f, 0); hum->move_dir.Rotate(a8::RandAngle()); hum->move_dir.Normalize(); hum->attack_dir = hum->move_dir; } break; } node_.main_state = to_state; node_.frameno = hum->room->GetFrameNo(); node_.exec_frame_num = 0; }