611 lines
18 KiB
C++
611 lines
18 KiB
C++
#include "precompile.h"
|
|
|
|
#include "base_agent.h"
|
|
#include "room.h"
|
|
#include "creature.h"
|
|
#include "human.h"
|
|
#include "movement.h"
|
|
#include "glmhelper.h"
|
|
#include "trigger.h"
|
|
#include "skill.h"
|
|
#include "btcontext.h"
|
|
#include "btevent.h"
|
|
#include "btcoroutine.h"
|
|
#include "mapinstance.h"
|
|
|
|
#include "f8/btmgr.h"
|
|
|
|
#include "mt/Equip.h"
|
|
#include "mt/Skill.h"
|
|
#include "mt/Hero.h"
|
|
#include "mt/Param.h"
|
|
|
|
void DumpBt(BaseAgent* agent)
|
|
{
|
|
static std::string last_bt_name;
|
|
static int last_task_id = 0;
|
|
|
|
std::string data = "CurrentBt: " + f8::BtMgr::Instance()->BtGetCurrent(agent)->GetName() + ": ";
|
|
const behaviac::BehaviorTask* curr_task = f8::BtMgr::Instance()->BtGetCurrent(agent)->GetCurrentTask();
|
|
|
|
if (last_bt_name != f8::BtMgr::Instance()->BtGetCurrent(agent)->GetName() ||
|
|
last_task_id != curr_task->GetId()) {
|
|
last_bt_name = f8::BtMgr::Instance()->BtGetCurrent(agent)->GetName();
|
|
last_task_id = curr_task->GetId();
|
|
while (curr_task) {
|
|
data += a8::Format("->%d",
|
|
{
|
|
curr_task->GetId(),
|
|
});
|
|
curr_task = curr_task->GetCurrentTask();
|
|
}
|
|
a8::XPrintf("%s\n", {data});
|
|
}
|
|
}
|
|
|
|
BaseAgent::BaseAgent():behaviac::Agent()
|
|
{
|
|
|
|
}
|
|
|
|
BaseAgent::~BaseAgent()
|
|
{
|
|
}
|
|
|
|
bool BaseAgent::IsGameOver()
|
|
{
|
|
return GetOwner()->room->IsGameOver();
|
|
}
|
|
|
|
void BaseAgent::Exec()
|
|
{
|
|
behaviac::EBTStatus status = f8::BtMgr::Instance()->BtExec(this);
|
|
if (status == behaviac::BT_RUNNING && coroutine_ && coroutine_->GetContext()->HasEvent()) {
|
|
status_= behaviac::BT_INVALID;
|
|
auto old_coroutine = coroutine_;
|
|
coroutine_ = nullptr;
|
|
GetOwner()->shot_hold = false;
|
|
old_coroutine->GetContext()->FireEvent(this);
|
|
old_coroutine = nullptr;
|
|
}
|
|
}
|
|
|
|
bool BaseAgent::HasTarget(float range)
|
|
{
|
|
Creature* enemy = GetOwner()->room->FindEnemy(GetOwner(), range);
|
|
return enemy != nullptr;
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::DoRunningCb()
|
|
{
|
|
if (status_ != behaviac::BT_RUNNING) {
|
|
abort();
|
|
}
|
|
if (GetOwner()->room->GetFrameNo() < coroutine_->sleep_end_frameno) {
|
|
return behaviac::BT_RUNNING;
|
|
}
|
|
status_ = coroutine_->runing_cb();
|
|
#ifdef DEBUG1
|
|
if ((GetOwner()->room->GetFrameNo() - status_frameno_) % SERVER_FRAME_RATE == 0 ||
|
|
last_status_ != status_) {
|
|
last_status_ = status_;
|
|
a8::XPrintf("Running Status:%s %d\n", {status_name_, status_});
|
|
}
|
|
#endif
|
|
if (status_ != behaviac::BT_RUNNING) {
|
|
coroutine_ = nullptr;
|
|
}
|
|
return status_;
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::StartCoroutine(std::shared_ptr<BtCoroutine> coroutine)
|
|
{
|
|
coroutine_ = coroutine;
|
|
#ifdef DEBUG
|
|
last_status_ = behaviac::BT_INVALID;
|
|
status_frameno_ = GetOwner()->room->GetFrameNo();
|
|
status_name_ = coroutine_->GetName();
|
|
#endif
|
|
status_ = behaviac::BT_RUNNING;
|
|
return status_;
|
|
}
|
|
|
|
bool BaseAgent::HasBuffEffect(int buff_effect)
|
|
{
|
|
return owner_->HasBuffEffect(buff_effect);
|
|
}
|
|
|
|
float BaseAgent::GetAttackRange()
|
|
{
|
|
if (owner_->GetCurrWeapon()) {
|
|
return owner_->GetCurrWeapon()->meta->range();
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
void BaseAgent::SetBulletTraceMode(bool mode)
|
|
{
|
|
bullet_trace_mode_ = mode;
|
|
}
|
|
|
|
bool BaseAgent::CanUseSkill(int skill_id)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int BaseAgent::GetUseableSkill(Creature* target)
|
|
{
|
|
#if 0
|
|
if (!target->IsPlayer()) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
#ifdef DEBUG
|
|
#if 0
|
|
if (GetOwner()->IsHuman()) {
|
|
return -1;
|
|
}
|
|
#endif
|
|
#endif
|
|
Skill* skill = GetOwner()->GetMainSkill();
|
|
if (skill && GetOwner()->CanUseSkill(skill->GetSkillId())) {
|
|
if (skill->GetMinorType()) {
|
|
return -1;
|
|
}
|
|
return skill->GetSkillId();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool BaseAgent::InternalUseSkill(int skill_id, CreatureWeakPtr target, int& wait_time)
|
|
{
|
|
if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(),
|
|
target.Get()->GetPos().ToGlmVec3())) {
|
|
return false;
|
|
}
|
|
Skill* skill = GetOwner()->GetSkill(skill_id);
|
|
if (skill) {
|
|
#ifdef DEBUG
|
|
a8::XPrintf("agent use skill:%d cd:%f\n", {skill_id, skill->GetCd()});
|
|
#endif
|
|
wait_time = 500;
|
|
glm::vec3 skill_dir = target.Get()->GetPos().ToGlmVec3() - GetOwner()->GetPos().ToGlmVec3();
|
|
float skill_distance = GlmHelper::Norm(skill_dir);
|
|
GlmHelper::Normalize(skill_dir);
|
|
|
|
switch (skill->GetCurrSkillMeta()->GetMagicId()) {
|
|
case MAGIC_20101_HL:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_20701_BAO:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_20801_LONG:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_20901_XIONG:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_21001_NIU:
|
|
{
|
|
#if 0
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
#endif
|
|
}
|
|
break;
|
|
case MAGIC_20201_HX:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_20401_MAO:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_20601_DJS:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_20301_XL:
|
|
{
|
|
skill_distance = 30;
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_20501_TZ:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
case MAGIC_60100_1_BOSS:
|
|
case MAGIC_60100_2_BOSS:
|
|
case MAGIC_60100_3_BOSS:
|
|
{
|
|
GetOwner()->DoSkill(skill->GetSkillId(), target.Get()->GetUniId(), skill_dir, skill_distance);
|
|
return true;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void BaseAgent::Sleep(int time)
|
|
{
|
|
if (coroutine_) {
|
|
coroutine_->sleep_end_frameno = GetOwner()->room->GetFrameNo() + time / SERVER_FRAME_RATE;
|
|
coroutine_->sleep_time = time;
|
|
}
|
|
}
|
|
|
|
bool BaseAgent::CurrentTargetMoveCanReach()
|
|
{
|
|
bool ret = false;
|
|
if (!current_target_.Get()) {
|
|
ret = false;
|
|
} else {
|
|
ret = GetOwner()->room->MoveCanReach(GetOwner()->GetPos().ToGlmVec3(),
|
|
current_target_.Get()->GetPos().ToGlmVec3());
|
|
}
|
|
#ifdef DEBUG
|
|
if (GetOwner()->GetHeroMeta()->id() == 60100) {
|
|
a8::XPrintf("CurrentTargetMoveCanReach %f\n", {ret});
|
|
}
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::DoSkill(int skill_id)
|
|
{
|
|
if (!current_target_.Get()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
int wait_time = 0;
|
|
if (InternalUseSkill(skill_id, current_target_, wait_time)) {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
|
|
glm::vec3 BaseAgent::GetPos()
|
|
{
|
|
return GetOwner()->GetPos().ToGlmVec3();
|
|
}
|
|
|
|
bool BaseAgent::MoveCanReach(const glm::vec3& pos)
|
|
{
|
|
return GetOwner()->room->MoveCanReach(GetOwner()->GetPos().ToGlmVec3(),
|
|
pos);
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::SelectUseableSkill(const behaviac::vector<int> skill_ids)
|
|
{
|
|
selected_skill_id = 0;
|
|
if (!current_target_.Get()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(),
|
|
current_target_.Get()->GetPos().ToGlmVec3())) {
|
|
}
|
|
for (int skill_id : skill_ids) {
|
|
Skill* skill = GetOwner()->GetSkill(skill_id);
|
|
if (skill && GetOwner()->CanUseSkill(skill->GetSkillId())) {
|
|
if (!skill->GetMinorType()) {
|
|
if (current_target_.Get()->GetPos().Distance2D2(GetOwner()->GetPos()) >
|
|
skill->meta->skill_distance()) {
|
|
continue;
|
|
}
|
|
selected_skill_id = skill->GetSkillId();
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::CoFindPathToCurrentTarget(float distance)
|
|
{
|
|
if (status_ == behaviac::BT_RUNNING) {
|
|
return DoRunningCb();
|
|
}
|
|
if (!current_target_.Get()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
bool ret = GetOwner()->GetMovement()->FindPath(current_target_.Get()->GetPos().ToGlmVec3(), distance);
|
|
if (!ret) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
);
|
|
|
|
#ifdef DEBUG
|
|
a8::XPrintf("CoFindPathToCurrentTarget %d\n", {current_target_.Get()->GetUniId()});
|
|
#endif
|
|
auto co = std::make_shared<BtCoroutine>(context, "CoFindPathToCurrentTarget");
|
|
co->runing_cb =
|
|
[this, context] ()
|
|
{
|
|
if (GetOwner()->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (GetOwner()->GetMovement()->GetPathSize() <= 0) {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
return behaviac::BT_RUNNING;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::CoMoveToCurrentTarget(float distance)
|
|
{
|
|
if (status_ == behaviac::BT_RUNNING) {
|
|
return DoRunningCb();
|
|
}
|
|
if (!current_target_.Get()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
float target_distance = GetOwner()->GetPos().Distance2D2(current_target_.Get()->GetPos());
|
|
if (target_distance > 1 && target_distance < 2) {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
/*
|
|
if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(),
|
|
current_target_.Get()->GetPos().ToGlmVec3())) {
|
|
return behaviac::BT_SUCCESS;
|
|
}*/
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
CreatureWeakPtr target;
|
|
);
|
|
|
|
context->target = current_target_;
|
|
if (target_distance < 1) {
|
|
GetOwner()->GetMovement()->CalcTargetPos(60);
|
|
} else {
|
|
glm::vec3 dir = GetOwner()->GetPos().CalcDir(context->target.Get()->GetPos());
|
|
GlmHelper::Normalize(dir);
|
|
GetOwner()->SetMoveDir(dir);
|
|
GetOwner()->SetAttackDir(dir);
|
|
GetOwner()->GetMovement()->CalcTargetPos(60);
|
|
}
|
|
#ifdef DEBUG
|
|
a8::XPrintf("CoMoveToCurrentTarget %d\n", {current_target_.Get()->GetUniId()});
|
|
#endif
|
|
auto co = std::make_shared<BtCoroutine>(context, "CoMoveToCurrentTarget");
|
|
co->runing_cb =
|
|
[this, context] ()
|
|
{
|
|
if (GetOwner()->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (GetOwner()->GetMovement()->GetPathSize() <= 0) {
|
|
if (context->target.Get()) {
|
|
if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(),
|
|
current_target_.Get()->GetPos().ToGlmVec3())) {
|
|
} else {
|
|
glm::vec3 dir = GetOwner()->GetPos().CalcDir(context->target.Get()->GetPos());
|
|
GlmHelper::Normalize(dir);
|
|
GetOwner()->SetMoveDir(dir);
|
|
GetOwner()->SetAttackDir(dir);
|
|
}
|
|
}
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
return behaviac::BT_RUNNING;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
bool BaseAgent::CurrentTargetIsValid()
|
|
{
|
|
bool ret = current_target_.Get() && !current_target_.Get()->dead;
|
|
#ifdef DEBUG
|
|
if (GetOwner()->GetHeroMeta()->id() == 60100 && !ret) {
|
|
a8::XPrintf("CurrentTargetIsValid %d\n", {ret});
|
|
}
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::FindEnemy(float range)
|
|
{
|
|
Creature* enemy = GetOwner()->room->FindEnemy(GetOwner(), range);
|
|
find_enemy_target_uniid = enemy ? enemy->GetUniId() : 0;
|
|
#ifdef DEBUG
|
|
if (GetOwner()->GetHeroMeta()->id() == 60100) {
|
|
a8::XPrintf("FindEnemy %f\n", {find_enemy_target_uniid});
|
|
}
|
|
#endif
|
|
return enemy ? behaviac::BT_SUCCESS : behaviac::BT_FAILURE;
|
|
}
|
|
|
|
float BaseAgent::GetCurrentTargetDistance()
|
|
{
|
|
float distance = 0;
|
|
if (current_target_.Get()) {
|
|
distance = current_target_.Get()->GetPos().Distance2D2(GetOwner()->GetPos());
|
|
}
|
|
#ifdef DEBUG1
|
|
if (GetOwner()->GetHeroMeta()->id() == 60100) {
|
|
a8::XPrintf("GetCurrentTargetDistance %f\n", {distance});
|
|
}
|
|
#endif
|
|
return distance;
|
|
}
|
|
|
|
float BaseAgent::GetFindEnemyResultTargetDistance()
|
|
{
|
|
abort();
|
|
return 0;
|
|
}
|
|
|
|
glm::vec3 BaseAgent::GetFindEnemyResultTargetPos()
|
|
{
|
|
abort();
|
|
return glm::vec3(0.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
void BaseAgent::SetCurrentTarget(int target_uniid)
|
|
{
|
|
#ifdef DEBUG
|
|
if (GetOwner()->GetHeroMeta()->id() == 60100) {
|
|
a8::XPrintf("SetCurrentTarget %f\n", {target_uniid});
|
|
}
|
|
#endif
|
|
current_target_.Reset();
|
|
Creature* c = GetOwner()->room->GetCreatureByUniId(target_uniid);
|
|
if (c) {
|
|
current_target_ = c->GetWeakPtrRef();
|
|
}
|
|
}
|
|
|
|
int BaseAgent::GetFindEnemyResultTargetUniId()
|
|
{
|
|
return find_enemy_target_uniid;
|
|
}
|
|
|
|
bool BaseAgent::ShotCanReach(const glm::vec3& target_pos)
|
|
{
|
|
abort();
|
|
return false;
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::CoShot()
|
|
{
|
|
if (status_ == behaviac::BT_RUNNING) {
|
|
return DoRunningCb();
|
|
}
|
|
if (!current_target_.Get()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(),
|
|
current_target_.Get()->GetPos().ToGlmVec3())) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (!GetOwner()->GetCurrWeapon()) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
glm::vec3 dir = GetOwner()->GetPos().CalcDir(current_target_.Get()->GetPos());
|
|
if (GlmHelper::Norm(dir) > GetAttackRange()) {
|
|
#ifdef DEBUG
|
|
a8::XPrintf("CoShot Failed %f\n", {GlmHelper::Norm(dir)});
|
|
#endif
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
bool shot_ok = false;
|
|
GlmHelper::Normalize(dir);
|
|
GetOwner()->SetAttackDir(dir);
|
|
GetOwner()->shot_hold = true;
|
|
GetOwner()->Shot(AdjustShotDir(dir), shot_ok, 0, 0);
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
|
|
bool BaseAgent::IsNearGas(float distance)
|
|
{
|
|
return GetOwner()->IsNearGas(distance);
|
|
}
|
|
|
|
behaviac::EBTStatus BaseAgent::CoRunGas()
|
|
{
|
|
if (status_ == behaviac::BT_RUNNING) {
|
|
return DoRunningCb();
|
|
}
|
|
if (GetSafeAreaRadius() < 200) {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
auto context = MAKE_BTCONTEXT
|
|
(
|
|
int try_count = 0;
|
|
long long frameno = 0;
|
|
bool find_ok = false;
|
|
glm::vec3 target_pos;
|
|
);
|
|
|
|
context->frameno = GetOwner()->room->GetFrameNo();
|
|
auto co = std::make_shared<BtCoroutine>(context, "CoRunGas");
|
|
co->runing_cb =
|
|
[this, context] ()
|
|
{
|
|
if (GetOwner()->dead) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
if (context->find_ok) {
|
|
if (GetOwner()->GetMovement()->GetPathSize() <= 0) {
|
|
return behaviac::BT_SUCCESS;
|
|
} else {
|
|
return behaviac::BT_RUNNING;
|
|
}
|
|
}
|
|
if (GetSafeAreaRadius() < 200) {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
glm::vec3 gas_center = glm::vec3(
|
|
GetOwner()->room->GetGasData().pos_new.x,
|
|
0,
|
|
GetOwner()->room->GetGasData().pos_new.y
|
|
);
|
|
if (GlmHelper::IsEqual2D(GetOwner()->GetPos().ToGlmVec3(),
|
|
gas_center)) {
|
|
return behaviac::BT_SUCCESS;
|
|
}
|
|
++context->try_count;
|
|
if (context->try_count > 3) {
|
|
return behaviac::BT_FAILURE;
|
|
}
|
|
gas_center.y = GetOwner()->GetPos().ToGlmVec3().y;
|
|
glm::vec3 dir = gas_center - GetOwner()->GetPos().ToGlmVec3();
|
|
GlmHelper::Normalize(dir);
|
|
|
|
glm::vec3 center = GetOwner()->GetPos().ToGlmVec3() +
|
|
dir * (30.0f + (float)context->try_count * 50.0f);
|
|
GetOwner()->room->map_instance->Scale(center);
|
|
glm::vec3 point;
|
|
bool ok = GetOwner()->room->map_instance->FindConnectableNearestPoint(center, 50, point);
|
|
if (ok) {
|
|
GetOwner()->room->map_instance->UnScale(point);
|
|
bool ret = GetOwner()->GetMovement()->FindPath(point, 0);
|
|
if (ret) {
|
|
context->find_ok = true;
|
|
context->target_pos = point;
|
|
}
|
|
}
|
|
return behaviac::BT_RUNNING;
|
|
};
|
|
return StartCoroutine(co);
|
|
}
|
|
|
|
float BaseAgent::GetSafeAreaRadius()
|
|
{
|
|
return GetOwner()->room->GetGasData().gas_progress;
|
|
}
|
|
|
|
bool BaseAgent::IsDead()
|
|
{
|
|
return GetOwner()->dead;
|
|
}
|