#include "precompile.h" #include #include "hero_agent.h" #include "hero.h" #include "room.h" #include "movement.h" #include "trigger.h" #include "glmhelper.h" #include "mapinstance.h" #include "human.h" #include "mt/Map.h" HeroAgent::HeroAgent():BaseAgent() { } HeroAgent::~HeroAgent() { } behaviac::EBTStatus HeroAgent::DoRandomWalk() { if (status_ == behaviac::BT_RUNNING) { return DoRunningCb(); } glm::vec3 dir = GetOwner()->GetMoveDir(); GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f); GlmHelper::Normalize(dir); GetOwner()->SetMoveDir(dir); GetOwner()->SetAttackDir(dir); GetOwner()->GetMovement()->CalcTargetPos(200); if (GetOwner()->GetMovement()->GetPathSize() <= 0) { return behaviac::BT_FAILURE; } auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED ( CreatureWeakPtr owner; CreatureWeakPtr last_attacker; long long last_attacked_frameno = 0; std::weak_ptr handler; ); context->owner = GetOwner()->GetWeakPtrRef(); context->handler = GetOwner()->GetTrigger()->AddListener ( kAttacked, [context_wp = context->GetWp()] (const a8::Args& args) { if (!context_wp.expired()) { auto context = context_wp.lock(); Creature* c = args.Get(0); context->last_attacker = c->GetWeakPtrRef(); context->last_attacked_frameno = c->room->GetFrameNo(); } }); context->_destory_cb = ( [context = context.get()] () { if (context->owner.Get()) { context->owner.Get()->GetTrigger()->RemoveEventHandler(context->handler); } }); auto co = std::make_shared(context, "CoRandomWalk"); co->runing_cb = [this, context] () { if (GetOwner()->GetMovement()->GetPathSize() <= 0) { return behaviac::BT_SUCCESS; } else { return behaviac::BT_RUNNING; } }; co->event_cb = [this, context] (bool is_test, bool& has_event) mutable { has_event = context->last_attacker.Get() && !context->last_attacker.Get()->dead ? true : false; if (!is_test && has_event) { FireEvent("OnAttacked", context->last_attacker.Get()->GetUniId(), context->last_attacked_frameno); } }; return StartCoroutine(co); } behaviac::EBTStatus HeroAgent::DoRandomShot() { if (status_ == behaviac::BT_RUNNING) { return DoRunningCb(); } glm::vec3 dir = GetOwner()->GetMoveDir(); GlmHelper::RotateY(dir, (10 + rand() % 360)/ 180.0f); GlmHelper::Normalize(dir); GetOwner()->SetMoveDir(dir); GetOwner()->SetAttackDir(dir); bool shot_ok = false; glm::vec3 shot_dir = dir; GetOwner()->Shot(shot_dir, shot_ok, 0, 0); auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED ( CreatureWeakPtr owner; CreatureWeakPtr last_attacker; long long last_attacked_frameno = 0; long long last_frameno = 0; std::weak_ptr handler; ); context->owner = GetOwner()->GetWeakPtrRef(); context->last_frameno = GetOwner()->room->GetFrameNo(); context->handler = GetOwner()->GetTrigger()->AddListener ( kAttacked, [context_wp = context->GetWp()] (const a8::Args& args) { if (!context_wp.expired()) { auto context = context_wp.lock(); Creature* c = args.Get(0); context->last_attacker = c->GetWeakPtrRef(); context->last_attacked_frameno = c->room->GetFrameNo(); } }); context->_destory_cb = ( [context = context.get()] () { if (context->owner.Get()) { context->owner.Get()->GetTrigger()->RemoveEventHandler(context->handler); } }); auto co = std::make_shared(context, "CoRandomShot"); co->runing_cb = [this, context] () { if (GetOwner()->room->GetFrameNo() - context->last_frameno > SERVER_FRAME_RATE * 3) { return behaviac::BT_SUCCESS; } else { bool shot_ok = false; glm::vec3 shot_dir = GetOwner()->GetAttackDir(); GetOwner()->Shot(shot_dir, shot_ok, 0, 0); return behaviac::BT_RUNNING; } }; co->event_cb = [this, context] (bool is_test, bool& has_event) mutable { has_event = context->last_attacker.Get() && !context->last_attacker.Get()->dead ? true : false; if (!is_test && has_event) { FireEvent("OnAttacked", context->last_attacker.Get()->GetUniId(), context->last_attacked_frameno); } }; return StartCoroutine(co); } behaviac::EBTStatus HeroAgent::DoAttack() { if (status_ == behaviac::BT_RUNNING) { return DoRunningCb(); } Creature* enemy = GetOwner()->room->FindEnemy(GetOwner(), 300); if (!enemy) { return behaviac::BT_FAILURE; } if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(), enemy->GetPos().ToGlmVec3())) { return behaviac::BT_FAILURE; } #if 0 enemy = ((Hero*)GetOwner())->master.Get(); #endif glm::vec3 dir = GetOwner()->GetPos().CalcDir(enemy->GetPos()); GlmHelper::Normalize(dir); GetOwner()->SetMoveDir(dir); GetOwner()->SetAttackDir(dir); bool shot_ok = false; glm::vec3 shot_dir = dir; if (bullet_trace_mode_) { GetOwner()->Shot(shot_dir, shot_ok, 0, enemy->GetUniId()); } else { GetOwner()->Shot(shot_dir, shot_ok, 0, 0); } auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED ( CreatureWeakPtr owner; CreatureWeakPtr target; long long last_frameno = 0; CreatureWeakPtr last_attacker; long long last_attacked_frameno = 0; std::weak_ptr handler; ); context->owner = GetOwner()->GetWeakPtrRef(); context->target = enemy->GetWeakPtrRef(); context->last_frameno = GetOwner()->room->GetFrameNo(); if (GetOwner()->AsHero()->master.Get()) { context->handler = GetOwner()->AsHero()->master.Get()->GetTrigger()->AddListener ( kBulletHitEvent, [context_wp = context->GetWp()] (const a8::Args& args) { if (!context_wp.expired()) { auto context = context_wp.lock(); Creature* c = args.Get(1); context->last_attacker = c->GetWeakPtrRef(); context->last_attacked_frameno = c->room->GetFrameNo(); } }); } context->_destory_cb = ( [context = context.get()] () { if (!context->handler.expired() && context->owner.Get()) { if (context->owner.Get()->IsEntityType(ET_Hero)) { Hero* hero = (Hero*)context->owner.Get(); if (hero->master.Get()) { hero->master.Get()->GetTrigger()->RemoveEventHandler(context->handler); } } } }); auto co = std::make_shared(context, "CoAttack"); co->runing_cb = [this, context] () { if (GetOwner()->room->GetFrameNo() - context->last_frameno > SERVER_FRAME_RATE * 3) { status_ = behaviac::BT_SUCCESS; return behaviac::BT_SUCCESS; } else { if (!context->target.Get()) { return behaviac::BT_SUCCESS; } if (context->target.Get()->dead) { return behaviac::BT_SUCCESS; } if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(), context->target.Get()->GetPos().ToGlmVec3())) { return behaviac::BT_FAILURE; } if (GetOwner()->dead) { return behaviac::BT_FAILURE; } if (GetOwner()->CanShot(true)) { bool shot_ok = false; glm::vec3 shot_dir = GetOwner()->GetPos().CalcDir(context->target.Get()->GetPos());; GlmHelper::Normalize(shot_dir); GetOwner()->SetAttackDir(shot_dir); if (bullet_trace_mode_) { GetOwner()->Shot(shot_dir, shot_ok, 0, context->target.Get()->GetUniId()); } else { GetOwner()->Shot(shot_dir, shot_ok, 0, context->target.Get()->GetUniId()); } } return behaviac::BT_RUNNING; } }; co->event_cb = [this, context] (bool is_test, bool& has_event) mutable { has_event = context->last_attacker.Get() && !context->last_attacker.Get()->dead ? true : false; if (!is_test && has_event) { FireEvent("OnMasterAttackTarget", context->last_attacker.Get()->GetUniId()); } }; return StartCoroutine(co); } behaviac::EBTStatus HeroAgent::DoPursuit() { if (status_ == behaviac::BT_RUNNING) { return DoRunningCb(); } Creature* enemy = GetOwner()->room->FindEnemy(GetOwner(), 500); if (!enemy) { return behaviac::BT_FAILURE; } auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED ( CreatureWeakPtr owner; CreatureWeakPtr target; long long last_frameno = 0; long long last_pursuit_frameno = 0; ); context->owner = GetOwner()->GetWeakPtrRef(); context->target = enemy->GetWeakPtrRef(); context->last_frameno = GetOwner()->room->GetFrameNo(); context->last_pursuit_frameno = GetOwner()->room->GetFrameNo(); auto co = std::make_shared(context, "CoPursuit"); co->runing_cb = [this, context] () { if (GetOwner()->room->GetFrameNo() - context->last_frameno > SERVER_FRAME_RATE * 10 || !context->target.Get() || context->target.Get()->dead) { status_ = behaviac::BT_SUCCESS; return behaviac::BT_SUCCESS; } else { glm::vec3 dir = GetOwner()->GetPos().CalcDir(context->target.Get()->GetPos()); if (GlmHelper::Norm(dir) <= 1.0f) { GetOwner()->GetMovement()->CalcTargetPos(60); context->last_pursuit_frameno = GetOwner()->room->GetFrameNo(); } else { bool is_shot = false; if (GlmHelper::Norm(dir) > 300) { if (GetOwner()->GetMovement()->GetPathSize() < 1) { GlmHelper::Normalize(dir); GetOwner()->SetMoveDir(dir); GetOwner()->SetAttackDir(dir); GetOwner()->GetMovement()->CalcTargetPos(200); context->last_pursuit_frameno = GetOwner()->room->GetFrameNo(); } else { if (GetOwner()->room->GetFrameNo() - context->last_pursuit_frameno > SERVER_FRAME_RATE * 1) { GlmHelper::Normalize(dir); GetOwner()->SetMoveDir(dir); GetOwner()->SetAttackDir(dir); GetOwner()->GetMovement()->CalcTargetPos(200); context->last_pursuit_frameno = GetOwner()->room->GetFrameNo(); } } } else { GlmHelper::Normalize(dir); is_shot = true; } if (is_shot) { bool shot_ok = false; glm::vec3 shot_dir = dir; GetOwner()->SetAttackDir(dir); GetOwner()->Shot(shot_dir, shot_ok, 0, 0); } } return behaviac::BT_RUNNING; } }; co->event_cb = [this, context] (bool is_test, bool& has_event) mutable { }; return StartCoroutine(co); } behaviac::EBTStatus HeroAgent::DoHelpAttack(int target_uniid) { if (status_ == behaviac::BT_RUNNING) { return DoRunningCb(); } Creature* enemy = GetOwner()->room->GetCreatureByUniId(target_uniid); if (!enemy) { return behaviac::BT_FAILURE; } if (enemy->dead) { return behaviac::BT_FAILURE; } if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(), enemy->GetPos().ToGlmVec3())) { return behaviac::BT_FAILURE; } float distance = enemy->GetPos().Distance2D2(GetOwner()->GetPos()); if (distance > GetAttackRange()) { return behaviac::BT_FAILURE; } glm::vec3 dir = GetOwner()->GetPos().CalcDir(enemy->GetPos()); GlmHelper::Normalize(dir); GetOwner()->SetMoveDir(dir); GetOwner()->SetAttackDir(dir); bool shot_ok = false; glm::vec3 shot_dir = dir; if (bullet_trace_mode_) { GetOwner()->Shot(shot_dir, shot_ok, 0, enemy->GetUniId()); } else { GetOwner()->Shot(shot_dir, shot_ok, 0, 0); } auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED ( CreatureWeakPtr target; long long last_frameno = 0; ); context->target = enemy->GetWeakPtrRef(); context->last_frameno = GetOwner()->room->GetFrameNo(); auto co = std::make_shared(context, "CoHelpAttack"); co->runing_cb = [this, context] () { if (GetOwner()->room->GetFrameNo() - context->last_frameno > SERVER_FRAME_RATE * 3) { status_ = behaviac::BT_SUCCESS; return behaviac::BT_SUCCESS; } else { if (!context->target.Get()) { return behaviac::BT_SUCCESS; } if (context->target.Get()->dead) { return behaviac::BT_SUCCESS; } if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(), context->target.Get()->GetPos().ToGlmVec3())) { return behaviac::BT_FAILURE; } float distance = context->target.Get()->GetPos().Distance2D2(GetOwner()->GetPos()); if (distance > GetAttackRange()) { return behaviac::BT_FAILURE; } bool shot_ok = false; glm::vec3 shot_dir = GetOwner()->GetPos().CalcDir(context->target.Get()->GetPos());; GlmHelper::Normalize(shot_dir); GetOwner()->SetAttackDir(shot_dir); if (bullet_trace_mode_) { GetOwner()->Shot(shot_dir, shot_ok, 0, context->target.Get()->GetUniId()); } else { GetOwner()->Shot(shot_dir, shot_ok, 0, 0); } return behaviac::BT_RUNNING; } }; co->event_cb = [this, context] (bool is_test, bool& has_event) mutable { }; return StartCoroutine(co); } behaviac::EBTStatus HeroAgent::DoFlyToMasterAround() { if (!GetOwner()->AsHero()->master.Get()) { return behaviac::BT_FAILURE; } glm::vec3 point; #if 1 glm::vec3 move_dir = GlmHelper::UP; GlmHelper::RotateY(move_dir, a8::RandAngle()); float move_distance = 30 + rand() % 20; glm::vec3 start = GetOwner()->AsHero()->master.Get()->GetPos().ToGlmVec3(); glm::vec3 end = start + move_dir * move_distance; GetOwner()->room->map_instance->Scale(start); GetOwner()->room->map_instance->Scale(end); glm::vec3 hit_point = glm::vec3(0.0f, 0.0f, 0.0f); bool hit_result = false; bool ret = GetOwner()->room->map_instance->Raycast ( start, end, hit_point, hit_result); if (ret) { GetOwner()->room->map_instance->UnScale(hit_point); point = hit_point; } else { point = GetOwner()->AsHero()->master.Get()->GetPos().ToGlmVec3(); } #else glm::vec3 ref_point = GetOwner()->AsHero()->master.Get()->GetPos().ToGlmVec3(); glm::vec3 point = GetOwner()->AsHero()->master.Get()->GetPos().ToGlmVec3(); GetOwner()->room->map_instance->Scale(ref_point); if (GetOwner()->room->map_instance->FindRandomPointAroundCircle ( ref_point, 0.21 * GetOwner()->room->GetMapMeta()->scale(), point )) { GetOwner()->room->map_instance->UnScale(point); #ifdef DEBUG a8::XPrintf("DoFlyToMasteraround1: %f,%f,%f %f,%f,%f distance:%f\n", {point.x, point.y, point.z, GetOwner()->GetPos().GetX(), GetOwner()->GetPos().GetY(), GetOwner()->GetPos().GetZ(), GlmHelper::Norm(GetOwner()->GetPos().ToGlmVec3() - point) }); #endif } else { point = GetOwner()->AsHero()->master.Get()->GetPos().ToGlmVec3(); #ifdef DEBUG a8::XPrintf("DoFlyToMasteraround2: %f,%f,%f %f,%f,%f distance:%f\n", {point.x, point.y, point.z, GetOwner()->GetPos().GetX(), GetOwner()->GetPos().GetY(), GetOwner()->GetPos().GetZ(), GlmHelper::Norm(GetOwner()->GetPos().ToGlmVec3() - point) }); #endif } #endif Global::Instance()->verify_set_pos = 1; GetOwner()->GetMutablePos().FromGlmVec3(point); Global::Instance()->verify_set_pos = 0; GetOwner()->GetMovement()->ClearPath(); GetOwner()->room->grid_service->MoveCreature(GetOwner()); GetOwner()->SetAttackDir(GetOwner()->AsHero()->master.Get()->GetAttackDir()); return behaviac::BT_SUCCESS; } behaviac::EBTStatus HeroAgent::DoFollowMaster() { if (status_ == behaviac::BT_RUNNING) { return DoRunningCb(); } if (GetOwner()->AsHero()->master.Get()->dead) { return behaviac::BT_FAILURE; } auto context = A8_MAKE_SMART_ANON_STRUCT_SHARED ( long long last_frameno = 0; long long last_follow_frameno = 0; ); context->last_frameno = GetOwner()->room->GetFrameNo(); context->last_follow_frameno = GetOwner()->room->GetFrameNo(); auto co = std::make_shared(context, "CoFollowMaster"); co->runing_cb = [this, context] () { if (GetOwner()->room->GetFrameNo() - context->last_frameno > SERVER_FRAME_RATE * 10 || !GetOwner()->AsHero()->master.Get() || GetOwner()->AsHero()->master.Get()->dead) { status_ = behaviac::BT_SUCCESS; return behaviac::BT_SUCCESS; } else { if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(), GetOwner()->AsHero()->master.Get()->GetPos().ToGlmVec3())) { return behaviac::BT_SUCCESS; } glm::vec3 dir = GetOwner()->GetPos().CalcDir(GetOwner()->AsHero()->master.Get()->GetPos()); if (GlmHelper::Norm(dir) < 60) { return behaviac::BT_SUCCESS; } if (GlmHelper::Norm(dir) > 60) { GlmHelper::Normalize(dir); GetOwner()->SetMoveDir(dir); GetOwner()->SetAttackDir(dir); GetOwner()->GetMovement()->CalcTargetPos(60); context->last_follow_frameno = GetOwner()->room->GetFrameNo(); } return behaviac::BT_RUNNING; } }; co->event_cb = [this, context] (bool is_test, bool& has_event) mutable { }; return StartCoroutine(co); } float HeroAgent::GetMasterDistance() { if (!GetOwner()->AsHero()->master.Get()) { return 0.0f; } return GetOwner()->GetPos().Distance2D2(GetOwner()->AsHero()->master.Get()->GetPos()); }